1.变量类型
成员变量:类体内定义的变量
局部变量:方法体内定义的变量
成员变量又可分为
实例变量(非静态变量):没有使用static修饰的成员变量
类变量(静态变量):使用static修饰的成员变量
2.实例变量和类变量
非法向前引用:
(1)public class ErrorDef{
int num1=num2+2
int num2=20
}
(2)public class ErrorDef{
static int num1=num2+2
static int num2=20
}
合法向前引用:
public class ErrorDef{
int num1=num2+2
static int num2=20
}
这是因为num2是一个类变量,而num1是一个实例变量,类变量初始化在实例变量初始化之前。
实例变量属于对象,而类变量属于类的特性。在同一个JVM中,每个类只有一个Class对象,而每个类可以创建多个java对象。因此,类变量只需分配一块内存空间(堆内存),而实例变量则每创建一个实例就需分配一块内存空间(堆内存)。
通俗的说,你每new一个对象,那么这个对象就拥有自己的实例变量,如:有一个Person类,其中有age,name属性(实例变量),还有一个count变量(类变量),则你每new一个Person对象,那么这个对象就有自己的name和age,而count是所有对象所共享的变量。如果你在每次new一个Person对象时,都让count++,则就实现了计数创建对象个数的功能。
(1)定义时指定初始值
(2)非静态初始化块中指定初始值
(3)构造器中指定初始值
其实java程序编译时仍然是将前两种赋值语句合并到构造器中,并且位于构造器的所有语句之前。
4.类变量的初始化
(1)定义时指定初始值
(2)静态初始化块中指定初始值
这两种方式的执行顺序与它们在类中的排列顺序相同
public class Price {
final static Price INSTANCE = new Price(2.8);//1处
static double initPrice = 20;//2处
double currentPrice;
public Price(double discount) {
currentPrice = initPrice - discount;
}
}
public class PriceTest {
public static void main(String[] args) {
System.out.println(Price.INSTANCE.currentPrice);//3处
Price price = new Price(2.8);//4处
System.out.println(price.currentPrice);
}
}
这时会输出-2.8,17.2 原因:第一次用到Price类时,程序开始对Price类进行初始化,分为两个阶段
(1)系统为Price的两个类变量分配内存空间
(2)按初始化代码的排列顺序对类变量进行初始化
3处:程序第一阶段,系统先为INSTANCE 和initPrice分配内存空间,此时他们默认值为null和0.0,接着第二阶段,程序依次对他们进行赋值。先对INSTANCE 赋值要调用构造方法Price(2.8),创建Price实例,由于initPrice此时为0.0,则会得到currentPrice=-2.8。接着对initPrice赋值为20,但是已经晚了。
4处:这里必然会输出17.2
若将1处和2处调换,会发现输出为17.2,17.2,按照上面的思路,道理就非常简单了。