Something interesting with the keyword final

  我还是老习惯,最上来讲下我遇到的问题吧

  问题是关于3个简单的程序,他们之间的变化甚微,但是结果有些出忽意料

让我们来看看这3个程序吧

第一个程序

public   class  Test01  {
    
public static void main(String[] args) {        
        System.out.println(
"Test01 main invoke: num = " + Test02.num);
        
    }

}


class  Test02  {
    
static {
        System.out.println(
"Test02 static block: num = " + Test02.num);
    }

     
static int num = 5;
}

第2个程序

 

public   class  Test01  {
    
public static void main(String[] args) {        
        System.
out.println("Test01 main invoke: num = " + Test02.num);
        
    }

}


class  Test02  {
    
static {
        System.
out.println("Test02 static block: num = " + Test02.num);
    }

     final 
static int num = 5;//第一个程序中这个变量不是final的,还记得吗?
}

 

第3个程序,其实并不是问题的根源,而是我本人遇到这样的问题时,自己给出的一个思考方法而已.我等会再说这个程序的意义在哪里

 


public   class  Test01  {
    
public static void main(String[] args) {        
        System.
out.println("Test01 main invoke: num = " + Test02.num);
        System.
out.println(new Test02().num); //从第2个程序中读出来的
    }

}


class  Test02  {
    
static {
        System.
out.println("Test02 static block: num = " + Test02.num);
    }

     final 
static int num = 5;
}

 

然后我们分别来告诉下大家他们的输出结果好嘛

 

// 第一个程序的
Test02  static  block: num  =   0
Test01 main invoke: num 
=   5


// 第2个程序的
Test01 main invoke: num  =   5

// 第3个程序的
Test01 main invoke: num  =   5
Test02 
static  block: num  =   5
5

 

  第一个程序其实很简单,为什么呢,因为static{}中间用到了下面的static的变量,此时他仅仅被赋了默认值0,所以就是0和5的输出

我们所迷惑的是为什么第2个程序只有1个程序,他明明也用到了第2个类.我们也知道,一旦一个类被用到,我们就需要首先加载他的static内容.But Why?What we have done to program is just adding a final keyword.

但是不要着急,我不是还写了第3个程序了嘛

那么我生成一下第2个类的对象,而此时,我们的静态块中的输出终于千呼万唤始出来.等等等等,为什么你刚才调用了这个属性,我来找找是这个Test02.num..对,就是这个了,不是也用到了第2个类了吗?为什么这个时候没有执行加载静态块呢,你不是忽悠我呢吧!!!

好吧,我没有忽悠你,如果是谁忽悠了你,那就是编译器了.与我无关,我也在跟你一起研究这个问题呢

既然我没有忽悠你,你就该静下来好好想想,恩,

System.out.println( new  Test02().num);
这个才是真正用到了第2个类,那就是说,上面的调用
System.out.println( " Test01 main invoke: num =  "   +  Test02.num);

根本就没有用到第2个类嘛....你说呢

也许是对的,但是程序怎么知道我把Test02.num设置为5了,而不是1,2,3或者其他任何的int型呢?

还记得嘛,第2个程序把这个变量已经声明成final的了,但是这有什么区别吗?Does it make someting different?    你不要鄙视我哦,至今为止我也不知道这个问题的准确答案呢.于是我去找《thinking in java》中间有关final的章节,好吧,是英文的,我先打出来,一会我会简单翻译下的

 

blank finals    // 不对
final method  // 也不对
final   class      // 我靠,我要的段落呢,跑哪去了。。。有多远给我滚多远,再不出来我就火了啊
final  data      // 真是的,总算找到了
// 让我们看看他是怎么说的吧   好不容易找到了
A constant is useful   for  two reasons:
    
1 .       It can be a compile - time constant that won ' t ever change
     2 .       It can be a value initialized at run time that you don ' t want changed
In the   case  of a compile - time constant, the compiler is allowed to  " fold "  the constant value into any calculation in which it ' s used;that is ,the calucalation can be performed at compile time ,eliminating some run-time overhead. In java, these sorts of constants must be primitives and are expressed with final keyword. A value must be given at the time of defination of such a constant.
// 哈哈,够了,我们终于找到我们要的东西了
// 正如我前面许诺的,我要翻译一下的对吧。。。原谅我蹩脚的英语水平
在2种情况下一个恒量(永远不变的)会是有用的:
   
1 。    可能是编译时就确定了值的恒量
   
2 。    可能是需要到运行时才能确定值的恒量
在第一种情况下,编译器会拿着这个恒量,把所有牵涉这个恒量的计算都计算出来
这里我要打个岔,稍微解释下什么意思呢?
比如说
static   final   int   a = 10 ;
int  b = a + 10 ;
这一步会在编译的时候就做好,也就是在class中间是int b
= 20 ;你必须要知道的是,像10这样的数字也算是恒量哦 ~~~~ 这个是我没解释清楚。。请你原谅我。不过他们本来就满足啊。。。一个数字10又不是一个变量。。。你能希望他变成啥呢

再下面的就是一些关于这样的恒量需要满足什么条件了:必须是原型变量,在声明时必须被赋值

哈哈,有猜想,有证明。。。不正如高中老师所说的嘛。。。西西,大胆的假设,细心的证明

好了,我们得到结论了呢,也就是说在编译阶段我们的这段代码

 System.out.println( " Test01 main invoke: num =  "   +  Test02.num);

已经被替换掉了,替换成了

 System. out .println( " Test01 main invoke: num =  "   +   5 );

所以,根本就没有用到第2个类的内容,所以我们不需要加载第2个类,也就不用执行静态块的代码了,同样也就没有预期的输出了

证明完毕了。。。

西西,有成就感

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值