JavaSE第二十四讲:static与final使用陷阱 续

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就因为没有对象引用而出错所以程序通不过。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值