黑马程序员技术交流社区

标题: 学习笔记:关于final一些小细节的认识 [打印本页]

作者: 381890216    时间: 2015-9-22 03:06
标题: 学习笔记:关于final一些小细节的认识
final修饰符:
1.被他修饰过的类不能被继承
2.被他修饰过的方法不能被复写
3.被他修饰过的变量作为常量使用(String的null同样适用)

以下简例:
  1. final int x = 1;
  2. x = 2; //必然报错,final后的值为常量

  3. final String s = "abc";
  4. s = "def"; //同理,报错
复制代码



我想整理的是,final作用在数组上及其操作后是怎样的结果呢?


  1. //程序一
  2. public class Final {

  3. public static void main(String[] args){
  4.             final String[] x = {"4","5","6"};
  5.             System.out.println(x[0]);
  6.             System.out.println(x[1]);
  7.             System.out.println(x[2]);
  8.             
  9.             x[0] = null;    //试图改变数组元素→从输出来看是成功的
  10.             System.out.println(x[0]);
  11.             System.out.println(x[1]);
  12.             System.out.println(x[2]);
  13.             System.out.println("length="+x.length);    }}
复制代码
//当数组的元素被设定为null之后长度不变
输出结果一:
4
5
6
null
5
6
length=3
------------------------------------------------------------------------

产生了问题:为什么被final后的数组还是能更改?这样的final修饰还是否有意义?
与朋友讨论后,首先尝试如下代码:

  1.                
  2. //程序二
  3. public class Final {
  4.            public static void main(String[] args){
  5.                        final int[] x = {4,5,6};
  6.                        System.out.println(x[0]);
  7.                        System.out.println(x[1]);
  8.                        System.out.println(x[2]);
  9. //                       x = new int[] {1,2,3}; //企图赋一个新数组给x,编译失败,报错The final local variable x cannot be assigned. It must be blank and not using a compound assignment
  10.                        x[0] = 1;
  11.                        x[1] = 2;
  12.                        x[2] = 3;
  13.                        System.out.println(x[0]);
  14.                        System.out.println(x[1]);
  15.                        System.out.println(x[2]);
  16.                        System.out.println("length="+x.length); }}  
复制代码

--------------------------------------------------------------------------------------------

输出结果二:
4
5
6
1
2
3
length=3

可知final其实对数组是生效的。可以看到一但我们企图对已经final掉的数组int[] x重新建立一个对象后,立即报错。而程序一的可以修改的实质是“修改数组的内容”而本程序试图new对象的实质是”试图给int[] x的指针重新指向一个新的内存空间“,于是报错。

于是我们给程序一和程序二的更改前后x分别输出x.toString,发现两程序各自更改前后的x地址无变化。

得出结论:final作用于数组上,固定的是该数组存放的内存地址,而数组的空间内具体存放什么数据,final并不管理。这里想起了毕老师视频里多次强调对象对类的引用并不是把该类储存到对象里,而是把该类的地址储存到对象里。。。

又尝试写写final数组作为参数导入至方法里的效果:


  1. //程序三
  2. public class Final {
  3. public static void test(int[] i){
  4. i =new int[] {1,2,3}; //这里final的数组out导入后竟然new成功了
  5. }
  6. public static void main(String[] args){
  7. final int[] out = new int[]{4,5,6};
  8. test(out);
  9. System.out.println(out[0]);
  10. System.out.println(out[1]);
  11. System.out.println(out[2]);
  12. }}
复制代码

-----------------------------------------------
输出结果三:
4
5
6

首先程序里final掉的数组int[] out作为参数被导入方法test之后,i = new int[]竟然编译通过了,与程序二形成了矛盾(?)
其次发现输出还是out初始化的数值4,5,6。。。。意味着i就算new成功了成为一个新数组,却并没有影响int[] out。。。。。?

我们修改了程序,目的在于观察运行中各个阶段的各个值。


  1. //程序四
  2. public class Final {
  3. public static void test(int[] i){
  4. System.out.println("被test方法new前的i地址"+i);
  5. i =new int[] {1,2,3};
  6. System.out.println("被test方法new后的i地址"+i);
  7. System.out.println(i[0]);
  8. System.out.println(i[1]);
  9. System.out.println(i[2]);
  10. }
  11. public static void main(String[] args){
  12. final int[] out = new int[]{4,5,6};
  13. System.out.println("被final的out地址"+out);
  14. test(out);
  15. System.out.println(out[0]);
  16. System.out.println(out[1]);
  17. System.out.println(out[2]);
  18. }}
复制代码

--------------------------------------------------
输出结果四:
被final的out地址[I@659e0bfd
被test方法new前的i地址[I@659e0bfd
被test方法new后的i地址[I@2a139a55
1
2
3
4
5
6

发现原来test方法里new出来的数组有另一个地址,就是说test方法里的参数int[] i不受被导入的out的修饰符final控制。out final与无final并无区别。

再尝试修改程序:

  1. public class Final {
  2. public static void test(final int[] i){
  3. System.out.println("被test方法new前的i地址"+i);
  4. i =new int[] {1,2,3}; //编译失败,报错The final local variable i cannot be assigned. It must be blank and not using a compound assignment
  5. ...........
复制代码


编译失败,报错final的变量不能被更改。

至此明白,final要想在方法里起作用必须设定在参数身上,而不是被存入的具体实例上。
作者: meihua    时间: 2015-9-22 13:04
先留着,应该会有用。。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2