Java关键字final

根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类、非抽象类成员方法和变量。你可能出于两种理解而需要阻止改变:设计或效率。

  1. final类不能被继承,没有子类,final类中的方法默认是final的。
  2. final方法不能被子类的方法覆盖,但可以被继承。
  3. final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
  4. final不能用于修饰构造方法。

注意:父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。

1. final类

final类不能被继承,因此final类的成员方法没有机会被覆盖,默认都是final的。在设计类时候,如果这个类不需要有子类,类的实现细节不允许改变,并且确信这个类不会载被扩展,那么就设计为final类。换言之,出于这样或那样的原因,我们的类肯定不需要进行任何改变;或者出于安全方面的理由,我们不希望进行子类化(子类处理)。
除此以外,我们或许还考虑到执行效率的问题,并想确保涉及这个类各对象的所有行动都要尽可能地有效。如下所示:

 

public class SmallBrain {

}

public final class  Dinosaur {
    int i = 7;
    int j = 1;
    SmallBrain x = new SmallBrain();

    void f() {
    }

    @Override
    public String toString() {
        return "Dinosaur [i=" + i + ", j=" + j + ", x=" + x + "]";
    }
    
}

public class Jurassic {
    public static void main(String[] args) {
        Dinosaur n = new Dinosaur();
        n.f();
        n.i = 40;
        n.j++;
        System.out.println(n);
      }
}

 

输出结果

Dinosaur [i=40, j=2, x=com.david.javaTest.SmallBrain@17b68215]
View Code

 

注意:数据成员既可以是final,也可以不是,取决于我们具体选择。应用于final的规则同样适用于数据成员,无论类是否被定义成final。将类定义成final后,结果只是禁止进行继承——没有更多的限制。然而,由于它禁止了继承,所以一个final类中的所有方法都默认为final。因为此时再也无法覆盖它们。所以与我们将一个方法明确声明为final一样,编译器此时有相同的效率选择。

2.final方法

如果一个类不允许其子类覆盖某个方法,则可以把这个方法声明为final方法。使用final方法的原因有二:
第一、把方法锁定,防止任何继承类修改它的意义和实现。
第二、高效。编译器在遇到调用final方法时候会转入内嵌机制,大大提高执行效率。
 例如:

public class FinalMethod {
    public void nonFinalMethod() {
        System.out.println("nonFinalMethod");
    }

    public final void finalMethod() {
        System.out.println("finalMethod");
    }

}
public class TestFinalMethod extends FinalMethod{
    public void nonFinalMethod() {
        System.out.println("test nonFinalMethod");
    }

    public static void main(String[] args) {
        TestFinalMethod t1 = new TestFinalMethod();
        t1.nonFinalMethod();
        t1.finalMethod();
    }

}

结果:

test nonFinalMethod
finalMethod
View Code

3.final变量(常量)

用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量、实例变量和局部变量,分别表示三种类型的常量。       

从下面的例子中可以看出,一旦给final变量初值后,值就不能再改变了。       

另外,final变量定义的时候,可以先声明,而不给初值,这中变量也称为final空白,无论什么情况,编译器都确保空白final在使用之前必须被初 始化。但是,final空白在final关键字final的使用上提供了更大的灵活性,为此,一个类中的final数据成员就可以实现依对象而有所不同, 却有保持其恒定不变的特征.

特别说明:如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的,即它是个常量;如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的,这里需要提醒大家注意的是,不可改变的只是这个变量所保存的引用,并不是这个引用所指向的对象。在第二种情况下,final的含义与第一种情况相同。实际上对于前两种情况,有一种更贴切的表述final的含义的描述,那就是,如果一个变量或方法参数被final修饰,就表示它只能被赋值一次, 但是JAVA虚拟机为变量设定的默认值不记作一次赋值。

package com.david.javaTest;

public class FinalTest {
    private final String S = "final实例变量S";
    private final int A = 100;
    public final int B = 90;

    public static final int C = 80;
    private static final int D = 70;

    public final int E; // final空白,必须在初始化对象的时候赋初值

    public FinalTest(int x) {
        E = x;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        new FinalTest(2).f1(2);
        FinalTest t = new FinalTest(2);

        // 使用final关键字修饰一个变量是指引用变量不能变,引用变量所指向的对象中的内容还是可以被修改。
        final StringBuffer stringBuffer = new StringBuffer("hello stringBuffer");
        System.out.println(stringBuffer);
        stringBuffer.append(" append ");
        System.out.println(stringBuffer);

        // t.A=101; //出错,final变量的值一旦给定就无法改变
        // t.B=91; //出错,final变量的值一旦给定就无法改变
        // t.C=81; //出错,final变量的值一旦给定就无法改变
        // t.D=71; //出错,final变量的值一旦给定就无法改变

        System.out.println(t.A);
        System.out.println(t.B);
        System.out.println(t.C); // 不推荐用对象方式访问静态字段
        System.out.println(t.D); // 不推荐用对象方式访问静态字段
        System.out.println(FinalTest.C);
        System.out.println(FinalTest.D);
        // System.out.println(FinalTest.E); //出错,因为E为final空白,依据不同对象值有所不同.
        System.out.println(t.E);

        FinalTest t1 = new FinalTest(3);
        System.out.println(t1.E); // final空白变量E依据对象的不同而不同
    }

    private void test() {
        System.out.println(new FinalTest(1).A);
        System.out.println(FinalTest.C);
        System.out.println(FinalTest.D);
    }

    public void test2() {
        final int a; // final空白,在需要的时候才赋值
        final int b = 4; // 局部常量--final用于局部变量的情形
        final int c; // final空白,一直没有给赋值.
        a = 3;
        // a=4; 出错,已经给赋过值了.
        // b=2; 出错,已经给赋过值了.
    }

    public void f1(final int i) {
        // i++; //i是final类型的,值不允许改变的.
        System.out.println(i);
    }
}

4、final参数

当函数参数为final类型时,你可以读取使用该参数,但是无法改变该参数的值。
public static void main(String[] args) {
                new Test4().f1(2);
        }

        public void f1(final int i) {
                //i++;    //i是final类型的,值不允许改变的.
                System.out.print(i);
        }
}

5.被final修饰的变量必须被初始化。初始化的方式有以下几种: 

  1. 在定义的时候初始化。
  2. final变量可以在初始化块中初始化,不可以在静态初始化块中初始化。
  3. 静态final变量可以在静态初始化块中初始化,不可以在初始化块中初始化。
  4. final变量还可以在类的构造器中初始化,但是静态final变量不可以。
public class FinalTest {
    final String teString ;
    public static final  String hello;//如果不在静态代码块中初始化则The blank final field hello may not have been initialized
    static{
        final String staticFinalVar ="staticFinalVar";
        hello="hello has been initialized in static block";
        //hello="hh";
        //teString = "this is initial block";//Cannot make a static reference to the non-static field teString
        System.out.println(staticFinalVar);
        System.out.println(hello);
    }
    {
        teString = "this is initial block";
        System.out.println(teString);
    }

        public static void main(String[] args) {
        new FinalTest(2);    
        }
}

6.面试题

使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。例如,对于如下语句:
final StringBuffer a=new StringBuffer("immutable");执行如下语句将报告编译期错误:
a=new StringBuffer("");但是,执行如下语句则可以通过编译:
a.append(" broken!"); 

 

 


 

 

posted @ 2016-07-05 11:53  404_Exception  阅读(168)  评论(0编辑  收藏  举报