final修饰符

来源:互联网 发布:ff14人女捏脸数据 编辑:程序博客网 时间:2024/06/05 07:27

final 变量

final修饰变量时,表示该变量一旦获得了初始值之后就不可被改变,final既可修饰成员变量(包括类变量和实例变量),也
可以修饰局部变量、形参。严格的说final修饰的变量不可被改变,一旦获得初始值之后,该final变量的值就不能被重新赋值。
因为final变量获得初始值之后不能被重新赋值,因此final修饰成员变量和修饰局部变量时有一定的不同。


final修饰成员变量

当使用final修饰成员变量的时候,要么在定义成员变量时候指定初始值,要么在初始化块、构造器中为成员变量赋初始值
。如果在定义该成员变量时指定了默认值,则不能在初始化块、构造器中为该属性重新赋值。归纳起来,final修饰的类属性
、实例属性能指定初始值的地方如下:
== 类属性:可在静态初始化块中、声明该属性时指定初始值。
== 实例属性:可在非静态初始化块、声明该属性、构造器中指定初始值
与普通成员变量不同的是,final成员变量(包括实例属性和类属性)必须由程序员显示初始化,系统不会对final成员进行
隐式初始化。所以,如果打算在构造器、初始化块中对final成员变量进行初始化,则不要在初始化之前就访问成员变量的值。
例如下面的成员将会引发错误。

[java] view plaincopy
  1. public class Test{  
  2.     final int age;  
  3.     {  
  4.         //系统不会对final成员变量属性进行默认初始化,所以此处代码将引起错误  
  5.         System.out.println(age);  
  6.         age = 6;  
  7.         System.out.println(age);  
  8.     }  
  9.   
  10.     public static void main(String[] args){  
  11.         new Test();  
  12.     }  
  13. }  

final 修饰局部变量

系统不会对局部变量进行隐式初始化,局部变量必须由程序员显示初始化。因此使用final修饰局部变量时既可以在定义时
默认值,也可以不指定默认值。
如果final修饰的局部变量在定义时没有指定默认值,则可以在后面代码中进行对final变量赋初始值,但只能一次,不能
重复能复制;如果final修饰的局部变量在定义时已经指定默认值,则后面代码中不能再对该变量赋值。下面的程序示范了
final修饰的局部变量、形参的情形:

[java] view plaincopy
  1. public class TestFinalLocalVariable {  
  2.   
  3.     public void test(final int a){  
  4.         //不能对final修饰的形参赋值,下面语句非法  
  5. //      a = 5;  
  6.     }  
  7.       
  8.     public static void main(String[] args) {  
  9.         //定义final局部变量时指定默认值,则src变量无法重新赋值  
  10.         final String str = "hello";  
  11.         //下面语句非法  
  12. //      str = "java";  
  13.           
  14.         //定义final局部变量时没有指定默认值,则d变量可被赋值一次  
  15.         final double d;  
  16.         //第一次赋初始值,成功  
  17.         d = 3.4;  
  18.         //对final变量重复赋值,下面语句非法  
  19. //      d = 4.6;  
  20.     }     
  21. }  

final 修饰基本类型和引用类型变量的区别

当使用final修饰基本类型变量时,不能对基本类型重新赋值,因此基本类型变量不能被改变。但对于引用类型的变量而言,
它保存的仅仅是一个引用,final只保证这个引用所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生
改变。

下面程序示范了final修饰数组和Tom对象的情形

[java] view plaincopy
  1. public class Tom {  
  2.   
  3.     private int age;  
  4.   
  5.     public Tom() {  
  6.   
  7.     }  
  8.   
  9.     public Tom(int age) {  
  10.         this.age = age;  
  11.     }  
  12.   
  13.     public int getAge() {  
  14.         return age;  
  15.     }  
  16.   
  17.     public void setAge(int age) {  
  18.         this.age = age;  
  19.     }  
  20.   
  21. }  
[java] view plaincopy
  1. public class TestFinalReference {  
  2.   
  3.     public static void main(String[] args) {  
  4.         //final修饰数组变量,iArr时一个引用变量  
  5.         final int[]iArr = {5,6,12,9};  
  6.         System.out.println(Arrays.toString(iArr));  
  7.         //对数组元素进行排序,合法  
  8.         Arrays.sort(iArr);  
  9.         System.out.println(Arrays.toString(iArr));  
  10.         //对数组元素赋值,合法  
  11.         iArr[2] = -8;  
  12.         System.out.println(Arrays.toString(iArr));  
  13.         //下面语句对iArr重新赋值,非法  
  14. //      iArr = null;  
  15.           
  16.         //final修饰Tom变量,t是一个引用变量  
  17.         final Tom t = new Tom(4);  
  18.         //修改Tom对象的age属性,合法  
  19.         t.setAge(6);  
  20.         System.out.println(t.getAge());  
  21.         //下面语句对t重新赋值,非法  
  22. //      t = null;  
  23.     }  
  24. }  

从上面程序中可以看出,使用final修饰的引用类型变量不能被重新赋值,但可以改变引用型变量所引用对象的内容



final方法

final修饰方法不可被重写,出于某一些原因,不希望子类重写父类的某个方法, 则可以使用final修饰该方法。

final 类

final修饰的类不可有子类,不可被继承。

不可改变类

不可变类的意思是创建该类的实例后,该实例的属性是不可改变的。Java提供的8个包装类和lava.lang.String类都是不可改变
类,当创建他们的实例后,其实例的属性不可改变。例如下面的代码:

[java] view plaincopy
  1. Double d = new Double(6.5);  
  2. String str = new String("hello");  

上面的程序创建了一个Double对象和一个String对象,并未这两个对象传入了6.5和“hello”字符串作为参数,那么Double类
和String类肯定需要实例属性来保存这两个参数,但程序无法修改这两个实例属性,因此Double类和String类没有提供修改
他们的方法。
如果需要创建自定义的不可改变类,可遵循如下规则:
== 使用private 和final修饰符来修饰该类的属性。
== 提供带参数构造器,用于根据传入参数来初始化类里的属性
== 仅为该类的属性提供getter方法,不要为该类的属性提供setter方法,因为普通方法无法修改final修饰的属性。
== 如有必要,重写Object类中hashCode和equals方法,在equals方法根据关键属性来作为两个对象相等的标准,除此之外,还
应该保证两个用equals方法判断为相等的对象的hashCode也相等。
例如java.lang.String这个类就做的很好,他是根据String对象里的字符序列来作为相等的标准,其hashCode方法也是根据字符
序列计算得到的。下面程序测试了String类的equals和hashCode方法

[java] view plaincopy
  1. public class TestString {  
  2.   
  3.     public static void main(String[] args) {  
  4.         String str1 = new String("hello");  
  5.         String str2 = new String("hello");  
  6.           
  7.         //输出false  
  8.         System.out.println(str1 == str2);  
  9.           
  10.         //输出true  
  11.         System.out.println(str1.equals(str2));  
  12.           
  13.         //输出的hashCode  
  14.         System.out.println(str1.hashCode());  
  15.         System.out.println(str2.hashCode());  
  16.     }  
  17. }  

0 0