码迷,mamicode.com
首页 > 其他好文 > 详细

final修饰符

时间:2015-02-21 23:29:05      阅读:358      评论:0      收藏:0      [点我收藏+]

标签:final

final修饰变量时,表示该变量一旦获得了初始值就不可改变,
由于final变量获得初始值之后不能被重新赋值,因此final修饰成员变量和修饰局部变量时有一定的不同。

5.4.1final成员变量

成员变量是随类初始化或对象初始化而初始化的,
类初始化时,系统会为该类的类变量分配内存,并分配默认值;
创建对象时,系统会为该对象的实例变量分配内存,并分配默认值。
java语法规定:final修饰的成员变量必须由程序员显式地指定初始值
归纳:
final修饰的类变量,实例变量 能指定初始值的地方:
类变量:
- 在静态初始化块中指定初始值

     final static int;
              static{
              i = 10;
              }
  • 声明该类变量时指定初始值
final static int i = 10;

实例变量:
- 非静态初始化块

 final int i;
 {
      i = 10;
}
  • 声明该实例变量
final int i = 10;
  • 构造器中指定初始值
public class FinalVariableTest{
    final int i;
    public FinalVariableTest(){
        i = 10;
        //如果在初始化块已经赋值,就不能在构造器中重新赋值
    }
}

实例变量不能在静态初始化块中指定初始值,因为静态初始化块是静态成员,不可访问实例变量——非静态成员类变量不能在普通初始化块中指定初始值,因为类变量在类初始化阶段已经被初始化了,普通初始化块不能对其重新赋值。

如果打算在构造器、初始化块中对final成员变量进行初始化,则不要在初始化之前就访问成员变量的值。

package code;
public class FinalErrorTest{
    final int age;
    {
        //System.out.println(age);
        age = 6;
        System.out.println(age);
    }
    public static void main(String [] args){
        new FinalErrorTest();
    }
}

I:>javac -d . FinalErrorTest.java
FinalErrorTest.java:5: 错误: 可能尚未初始化变量age
System.out.println(age);
^
1 个错误

5.4.2 final局部变量

package code;
public class FinalLocalVariable{
    public void test(final int a){
        //不能对final修饰的形参赋值,下面语句非法
        //a = 5;
    }
    public static void main(String[] args){
        //定义final局部变量时指定默认值,则str变量无法重新赋值
        final String str = "hello";
        //str = "java";
        final double d;
        d = 44.5;
        //d = 443.3;
    }
}

I:>javac -d . FinalLocalVariable.java
FinalLocalVariable.java:10: 错误: 无法为最终变量str分配值
str = “java”;
^
1 个错误
I:>javac -d . FinalLocalVariable.java
FinalLocalVariable.java:5: 错误: 不能分配最终参数a
a = 5;
^
FinalLocalVariable.java:13: 错误: 可能已分配变量d
d = 443.3;
^
2 个错误

因为形参在调用该方法,由系统根据传入的参数来完成初始化,因此使用final修饰的形参不能被赋值。

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

package code;
import java.util.Arrays;
class Person{
    private int age;
    public Person(){}
    public Person(int age){
        this.age = age;
    }
    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return age;
    }
}
public class FinalReferenceTest{
    public static void main(String[]args){
        final int[] iArr = {5,6,12,8};
        System.out.println(Arrays.toString(iArr));
        Arrays.sort(iArr);
        System.out.println(Arrays.toString(iArr));
        iArr[2] = -8;
        System.out.println(Arrays.toString(iArr));
        //iArr = null;
        final Person p = new Person(45);
        p.setAge(21);
        System.out.println(p.getAge());
        //p = null;
    }
}

[5, 6, 12, 8]
[5, 6, 8, 12]
[5, 6, -8, 12]
21

使用final修饰的引用类型变量不能被重新赋值,但可以改变引用类型变量所引用对象的内容。

5.4.4 可执行“宏替换”的final变量

对一个final变量,不管它是类变量,实例变量,还是局部变量,只要该变量满足三个条件,这个final变量就不再是一个变量,而是相当于一个直接量。

  • 使用final修饰符修饰
  • 在定义该final变量时指定了初始值
  • 该初始值可以在编译时就被确定下来
package code;
public class FinalReplaceTest{
    public static void main(String[]args){
        final int a = 5+3;
        final double b = 1.2/3;
        final String str = "疯狂" + "Java";
        final String book = "疯狂Java讲义:" + 99.0;
        final String book2 = "疯狂Java讲义" + String.valueOf(99.0);
        System.out.println(book == "疯狂Java讲义:99.0");
        System.out.println(book2 == "疯狂Java讲义:99.0");
    }
}

true
false

由于定义book2变量时显式将数值99.0转换为字符串,但由于该变量的值需要调用String类的方法,因此编译器无法在编译时确定book2的值,book2不会被当成“宏变量”处理。

package code;
public class StringJoinTest{
    public static void main(String[] args){
        String str1 = "疯狂Java";
        String str2 = "疯狂" + "Java";
        String str3 = str1 + str2;
        System.out.println(str1 == str2);
        System.out.println(str1 == str3);

    }
}

true
false

由于编译器可以在编译阶段就确定str2的值为“疯狂Java”,所以系统会让s2直接指向常量池中缓存的“疯狂Java”字符串,因此str1 = str2.
对于final实例变量而言,只有在定义该变量时指定初始值才会有“宏变量”的效果

5.4.5 final方法

final修饰的方法不可被重写,如果出于某些原因,不希望子类重写父类的某个方法,则可以使用final方法。
对于一个private方法,因为它仅在当前类中可见,其子类无法访问该方法,所以子类无法重写该方法—–如果子类中定义一个与父类private方法有相同方法名,相同形参列表,相同返回值类型的方法,也不是方法重写,只是重新定义了一个新方法。

package code;
public class PrivateFinalMethodTest{
    private final void test(){}
}
class Sub extends PrivateFinalMethodTest{
    public void test(){}
}
class FinalOverload{
    //final修饰的方法只是不能被重写,完全可以被重载
    public final void test(){}
    public final void test(String agr){}
}

5.4.6 final类

final修饰的类不可以有子类,例如java.lang.Math类就是一个final类,它不可以有子类

final修饰符

标签:final

原文地址:http://blog.csdn.net/u014270902/article/details/43899701

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!