Java类体中包含成员变量的声明和方法的定义,而成员变量又可分为实例变量和类变量,方法又可分为实例方法和类方法。
.
> 实例变量和类变量的声明
在声明成员变量时,用关键字 static 修饰的变量称作类变量(也可称为static变量、静态变量),否则称作实例变量。static 需放在变量的类型前面。
例如grades类中,Chinese为实例变量,math为类变量:
class Grades{
double Chinese; //实例变量
static double math; //类变量
}
.
> 实例变量和类变量的区别
1.不同对象的实例变量互不相同
一个类通过使用new运算符可以创建多个不同的对象,这些对象将被分配不同的成员变量。分配给不同对象的实例变量占有不同的内存空间,改变其中一个对象的实例变量不会影响其他的对象的实例变量。
2.所有对象共享类变量
如果类中有类变量,当使用new运算符创建多个不同的对象时,分配给这些对象的这个类变量占有相同的一处内存,改变其中的一个对象的这个类变量会影响其他对象的这个类变量,即对象共享类变量。
3.通过类名直接访问类变量
当java程序执行时,类的字节码文件会被加载到内存,如果该类没有创建对象,类中的实例变量不会被分配内存。但是,类中的类变量,在该类被加载到内存时,就分配了相应的内存空间。如果该类创建对象,那么不同对象的实例变量互不相同,即分配不同的内存空间,二类变量不再重新分配内存,所有的对象共享类变量,即所有的类变量是相同的一处内存空间,类变量的内存空间直到程序退出运行,才释放所占有的内存。
类变量是与类相关联的变量,即类变量是和该类创建的所有对象相关联的变量,改变其中一个对象的这个类变量就同时改变了该类其他对象的这个类变量。因此,类变量既可以通过对象访问,也可以直接通过类名访问。
而实例变量只与对象相关联,不同对象的实例变量互不干扰,对象的实例变量只能通过该对象访问,不能通过类名访问。
代码表示:
class Grades{
double Chinese; //实例变量
static double math; //类变量
void inChinese(double c){ //设置语文成绩
Chinese=c;
}
void inmath(double m) { //设置数学成绩
math=m;
}
double outChinese() { //获取语文成绩
return Chinese;
}
double outmath() { //获取数学成绩
return math;
}
}
public class grades {
public static void main(String[] args) {
Grades.math=90; //通过类名操作类变量
Grades student1=new Grades();
Grades student2=new Grades();
student1.inChinese(80);
student2.inChinese(100);
System.out.println("学生1的语文成绩:"+student1.outChinese());
System.out.println("学生1的数学成绩:"+student1.outmath());
System.out.println("学生2的语文成绩:"+student2.outChinese());
System.out.println("学生2的数学成绩:"+student2.outmath());
student1.inmath(70); //通过某一个对象更改类变量的值
System.out.println("修改后学生1的数学成绩:"+student1.outmath());
System.out.println("修改后学生2的数学成绩:"+student1.outmath());
}
}
运行结果:
.
> 实例方法和类方法的定义
类中的方法分为实例方法和类方法,在方法声明时,方法类型前面不加关键字 static 修饰的是实例方法,加了关键字 static 修饰的是类方法。
例如:
class Grades{
double Chinese;
static double math;
void ingrades(double c,double m){ //实例方法
Chinese=c;
math=m;
}
void inChinese(double c) { //实例方法
Chinese=c;
}
static void inmath(double m) { //类方法
math=m;
}
double outChinese() { //实例方法
return Chinese;
}
static double outmath() { //类方法
return math;
}
}
.
> 实例方法与类方法的区别
1.对象调用实例方法
当类的字节码文件被加载到内存时,类的实例方法不会被分配入口地址,只有该类创建对象后,类中的实例方法才分配入口地址,从而实例方法可以被类创建的任何对象调用执行。需要注意的是,当创建第一个对象时,类中的实例方法就分配了入口地址,当再创建对象时,不再分配入口地址,即方法的入口地址被所有对象共享,当所有对象都不存在时,方法的入口地址才被取消。
实例方法中不仅可以操作实例变量,也可以操作类变量。当对象调用实例方法时,该方法中出现的实例变量就是分配给该对象的实例变量,该方法中出现的类变量就是分配给该对象的类变量,只不过这个变量与其他对象共享。
2.类名调用类方法
对于类中的类方法,在该类被加载到内存时,就分配了相应的入口地址,所以类方法不仅可以被类创建的任何对象调用,也可以直接被类名调用。类方法的入口地址直到程序退出才被取消。需要注意的是,实例方法只能被类的对象调用执行,而不能通过类名调用。
与实例方法不同,类方法不能操作实例变量,因为在类创建对象之前,实例成员变量还没有分配内存。
3.设计类方法的原则
对于static类,不必创建对象就可以用类名直接调用它(创建对象会导致类中的实例变量被分配内存空间)。如果一个方法不需要操作类中的任何实例变量就可以满足程序的需要,考虑将这样的方法设计为一个static方法。
代码表示:
package project;
class Grades{
double Chinese;
static double math;
void ingrades(double c,double m){ //实例方法 操作实例变量和类变量
Chinese=c;
math=m;
}
void inChinese(double c) { //实例方法
Chinese=c;
}
static void inmath(double m) { //类方法 只能操作类变量
math=m;
}
double outChinese() { //实例方法
return Chinese;
}
static double outmath() { //类方法
return math;
}
}
public class grades {
public static void main(String[] args) {
Grades.inmath(90); //使用类名调用类方法
Grades student1=new Grades();
Grades student2=new Grades();
student1.inChinese(80); //对象调用实例方法
student2.inChinese(100);
System.out.println("学生1的语文成绩:"+student1.outChinese());
System.out.println("学生1的数学成绩:"+student1.outmath());
System.out.println("学生2的语文成绩:"+student2.outChinese());
System.out.println("学生2的数学成绩:"+student2.outmath());
student1.ingrades(85, 95); //对象调用类方法
System.out.println("修改后学生1的语文成绩:"+student1.outChinese());
System.out.println("修改后学生1的数学成绩:"+student1.outmath());
System.out.println("修改后学生2的数学成绩:"+student1.outmath());
}
}
运行结果