public class FinalTest4
{
final int a;
}
编译结果:
D:\src>javac FinalTest4.java
FinalTest4.java:1: 错误: 可能尚未初始化变量a
public class FinalTest4
^
1 个错误
【说明】:如果变量没有用final修饰,则是可以的,因为可以在后面进行赋值,但是用final修饰的变量必须要赋值,如果不赋值,则接下来就没有机会对其进行操作了,因为final修饰的属性是不能被更改的。
public class FinalTest4{
final int a = 0;
}
编译结果正确。
再看下一个例子
public class FinalTest4{
final int a;
public FinalTest4(){
a = 0;
}
}
编译结果正常
【说明】:因为构造方法是一定要执行的,而a是可以再构造方法中给其赋初值。
继续修改以上程序
public class FinalTest4{
final int a = 0;
public FinalTest4(){
a = 0;
}
}
编译结果:
D:\src>javac FinalTest4.java
FinalTest4.java:4: 错误: 无法为最终变量a分配值
a = 0;
^
1 个错误
【说明】:final类型的a已经赋值完了,此时在构造方法中继续对其赋值,哪怕是一样的都是0也是对其属性进行更改,所以也是不行的。
继续修改以上程序:
public class FinalTest4{
final int a;
public FinalTest4(){
a = 0;
}
public FinalTest4(int a){
}
}
编译结果:
D:\src>javac FinalTest4.java
FinalTest4.java:8: 错误: 可能尚未初始化变量a
}
^
1 个错误
【说明】:此时虽然构造函数一定会执行会给final定义的a赋值,但是这个类中有两个构造方法,当我构造对象的时候,到底使用第一个构造方法还是使用第二个是不确定的,如果使用第一个则正常,如果使用第二个时则错误,所以程序出现错误。所以必须对所以的构造方法对其进行赋值。
这样写就正确了:
public class FinalTest4{
final int a;
public FinalTest4(){
a = 0;
}
public FinalTest4(int a){
this.a = a;
}
}
编译成功
1.【final使用陷阱】对于final类型成员变量,一般来说有两种赋初值方式:
a)在声明final类型的成员变量时就赋上初值
b)在声明final类型的成员变量时不赋初值,但在类的所有构造方法中都为其赋上初值。
2.static代码块:静态代码块。静态代码块的作用也是完成一些初始化工作。首先执行静态代码块,然后执行构造方法。静态代码块在类被加载的时候执行,而构造方法是在生成对象的时候执行;要想调用某个类来生成对象,首先需要将类加载到Java虚拟机上(JVM),然后由JVM加载这个类来生成对象。
public class StaticTest4{
public static void main(String[] args){
P p = new P();
}
}
class P{
static{
System.out.println("static block");
}
public P(){
System.out.println("P constructor");
}
}
执行结果:
D:\src>java StaticTest4
static block
P constructor
【说明】:当我们定义一个类的时候,编译时会在硬盘上生成一个.class文件,当执行的时候会将.class文件加载到java虚拟机上(JVM),由Java虚拟机去处理它然后再生成对象,而static块就是在.class被加载的时候执行的。而构造方法是在生成对象的时候才执行的。所以产生了时机的先后区别。
修改上一个程序第二行代码段:
public static void main(String[] args){
P p = new P();
P p2 = new P();
}
执行结果:
D:\src>java StaticTest4
static block
P constructor
P constructor
【说明】:static块是在类加载的时候执行的,所以只执行一次,而new一次就会调用一次构造方法。
3.类的静态代码块只会执行一次,是在类被加载的时候执行的,因为每个类只会被加载一次,所以静态代码块也只会被执行一次;而构造方法则不然,每次生成一个对象的时候都会调用类的构造方法,所以new一次就会调用构造方法一次。
4.如果继承体系中既有构造方法,又有静态代码块,那么首先执行最顶层的类的静态代码块,一直执行到最底层类的静态代码块,然后再去执行最顶层类的构造方法,一直执行到最底层类的构造方法。注意:静态代码块只会执行一次。
public class StaticTest4{
public static void main(String[] args){
new S();
}
}
class P{
static{
System.out.println("P static block");
}
public P(){
System.out.println("P constructor");
}
}
class Q extends P{
static{
System.out.println("Q static block");
}
public Q(){
System.out.println("Q constructor");
}
}
class S extends Q{
static{
System.out.println("S static block");
}
public S(){
System.out.println("S constructor");
}
}
执行结果:
D:\src>java StaticTest4
P static block
Q static block
S static block
P constructor
Q constructor
S constructor
修改上程序的第二行代码段:
public static void main(String[] args){
new S();
new S();
}
执行结果:
D:\src>java StaticTest4
P static block
Q static block
S static block
P constructor
Q constructor
S constructor
P constructor
Q constructor
S constructor
5.不能在静态方法中访问非静态成员变量;可以在静态方法中访问静态的成员变量。可以在非静态方法中访问静态的成员变量。
public class StaticTest5{
public static void main(String[] args){
W.change();
}
}
class W{
int a = 10;
public static void change(){
a ++;
}
}
执行结果:
D:\src>javac StaticTest5.java
StaticTest5.java:10: 错误: 无法从静态上下文中引用非静态 变量 a
a ++;
^
1 个错误
【说明】:不能在静态方法中访问非静态成员变量,因为是静态方法所以可以通过类去调用这个方法,这个方法对a进行++操作,但是不确定是对哪一个具体对象的a进行操作了。所以程序报错。
修改上一个程序第七行代码段:
class W{
static int a = 10;
public static void change(){
a ++;
}
}
编译成功
【说明】:静态方法可以访问静态成员变量。因为a声明为静态的属性,所以通过类的名字去改所有的对象都是共用这个a的,a的成员变量只有一个。
继续修改上一个例子:
public class StaticTest5{
public static void main(String[] args){
W w = new W();
w.change();
}
}
class W{
static int a = 10;
public void change(){
a ++;
}
}
编译成功。
【说明】:可以在非静态方法中访问静态的成员变量。
6. 总结:静态的只能访问静态的;非静态的可以访问一切。
7. 不能在静态方法中使用this关键字。可以把this关键字看做是非静态的成员变量
public class StaticTest5{
public static void main(String[] args){
W w = new W();
w.change();
}
}
class W{
static int a = 10;
public static void change(){
this.a ++;
}
}
执行结果:
D:\src>javac StaticTest5.java
StaticTest5.java:11: 错误: 无法从静态上下文中引用非静态 变量 this
this.a ++;
^
1 个错误
【说明】:this表示对当前对象的引用,换句话说一定要有一个对象,而静态方法可以由类来调用,而此时this就因为没有对象引用而出错,所以程序通不过。