java final 关键字

根据上下文环境,Java的关键字final的含义存在着细微的区别,但通常它指的是"这是无法改变的."不想做改变可能出于两种原因:设计或效率.由于这两个原因相差很远,所以final有可能误用

以下谈到了final的三种情况:数据.方法和类

一.final数据

恒定不变的数据比如

1.一个永不改变的编译时常量  //java中这类常量必须是基本数据类型

2.一个在运行时时被初始化的值,而你不希望它被改变.

3.当对对象使用final时,不变的只是指向对象的引用无法被改变,而对象自身可以被修改

 

package object;
import java.util.*;
import static net.mindview.util.Print.*;
class Value{
    int i ;//Package access
    public Value(int i){ this.i = i;}
}
public class FinalData{
    private static Random rand = new Random(47);
    private String id;
    public FinalData(String id){ this.id = id;}
    //Can be fianl int valueOne = 9
    private final int valueOne = 9;
    private static final int VALUE_TWO = 99;// 根据惯例既是static又是final的域将用大写表示
    public static final int VAL_THREE = 39; //public 说明可以被用于包外,定义为static,才强调只有一份,定义为final,则说明它是一个常量
    private final int i4 = rand.nextInt(20);
    static final int INT_5 = rand.nextInt(20);
    private Value v1 = new Value(11);
    private final Value v2 = new Value(33);
    private static final Value VAL_3 = new Value(33);
    //Arrays:
    private final int []a = {1,2,3,4,5,6};
    public String toString()
    {
        return id + ": " + "i4 = "  + i4 + ", INT_5= " + INT_5;
    }
public static void main(String[] args)
{
    FinalData fd1 = new FinalData("fd1");
    //! fd1.valueOne++;; // Error: can't change value
    fd1.v2.i++; //object isn't constant
    fd1.v1 = new Value(9); //ok -- no final
    for(int i = 0; i < fd1.a.length; i++)
        fd1.a[i]++;//Object isn't constant
    //! fd1.v2 = new Value(0); //Error: can't
    //! fd1.VAL_3 = new Value(1    ;//Change reference
    //! fd1.a = new int[3];
    print(fd1);
    print("Creading new FinalData");
    FinalData fd2 = new FinalData("fd2");
    print(fd1);
    print(fd2);
}
}
/* output:
 * fd1: i4 = 15, INT_5= 18
 *Creading new FinalData
 *fd1: i4 = 15, INT_5= 18
 *fd2: i4 = 13, INT_5= 18
 *///:~

二:空白final

java 允许生产"空白final",所谓空白final是指被声明为final但又未给初值的域(field),无论什么情况,编译器都会确保空白final字使用前必须被初始化,但是,空白final在关键字final的使用上提供了很大的灵活性,为此,一个类中的final域就可以做到根据对象而有所不同,却又保持其恒定不变的特性

package object;

class Poppet{
    private int i;
    Poppet(int ii){i = ii;}
}
public class BlankFinal{
    private final int i = 0; //Initialized final
    private final int j ; //blank final
    private final Poppet p; //Blank final reference
    //blank finals must be initialized in the constructor
    public BlankFinal(){
        j = 1; //initialized
        p = new Poppet(1);
    }
    public BlankFinal(int x)
    {
        j = x; //initialized final
        p = new Poppet(x); //initialized final reference
    }
    public static void main(String[] args)
    {
        new BlankFinal();
        new BlankFinal(47);
    }
}//必须在域的定义出或每个构造器中用表达式对final赋值,这正是final域在使用前总是被初始化的原因所在

 final 参数

java 允许参数列表中以声明的方式将参数指明为final,这意味着你无法再方法中改变参数所引用的对象

//: ch7_19/final.java
// blank final
package object;

class Gizmo{
    public void spin(){}
}
public class FinalArguments{
    void with(final Gizmo g)
    {
        //! g  = new Gizmo(); //Illegal  --g is final
    }
    void without(Gizmo g)
    {
        g = new Gizmo(); //ok -- g not final
        g.spin();
    }
    // void f(final int i) { i++;} //can't change 
    // you can only read from a final primitive
    int g(final int i){return i+1;}
    public static void main(String[] args)
    {
        FinalArguments bf = new FinalArguments();
        bf.without(null);
        bf.with(null);
    }
}

三 final 方法

使用final 方法的原因有两个,第一个原因是把方法锁定,以防止任何继承类修改它的含义,这是出于设计的考虑:想要确保再继承中使方法行为保持不变,并且不会被覆盖

过去使用final方法的第二个原因是效率,现在不用了,只有再明确禁止导出类的方法覆盖基类方法时,才将基类方法设置为final

private和final:由于无法取得private方法,所以也就无法覆盖它,可以对private加final,但无意义

//: reusing/FinalOverridingIllusion.java
// it only loos like you cna override
// a private or private final method
package ch7_20;

class WithFinals{
    //Identical to "private" alone
    private final void f(){
        System.out.println("WithFinals.f()");
    }
    private void g() {
        System.out.println("WithFinals.g()");
    }
}

class OverridePrivate extends WithFinals{
    private final void f()
    {
      System.out.println("Overridingprivate.f()");
    }
    private void g()
    {
        System.out.println("Overridingprivate.g()");
    }
}

class OverridePrivate2 extends OverridePrivate{
    public final void f()
    {
      System.out.println("Overridingprivate2.f()"); //"覆盖" 只有在某方法时接口的一部分才会出现
    }
    public void g()
    {
        System.out.println("Overridingprivate2.g()");
    }
}
public class FinalOverridingIllusion{
    public static void main(String[] args)
    {
        OverridePrivate2 op2 = new OverridePrivate2();
        op2.f();
        op2.g();
        // you can upcast
        OverridePrivate op = op2;
        // but you can't call the methods
        //! op.f();
        //! op.g();
        WithFinals wf = op2;
        //! wf.f();
        //! wf.g();
    }
}

final 类

当将某个类的整体定义为final时,就表明了 你不打算继承该类,而且也不允许别人这样做,

package object;

class SmallBrain{
    
}
final class Dinosaur{
    int i = 7; //Dinosaur 所有方法都隐式的指定为是final的
    int j = 1;
    
    SmallBrain x = new SmallBrain();
    void f(){}
}
// class further extends dinosaur {}
// error: annt extend final class Dinosaur
public class Jurassic{
    public static void main(String[] args)
    {
        Dinosaur n = new Dinosaur();
        n.f();
        n.i =40;
        n.j++;
    }
}

在设计类时将方法指明时final,应该说时明智的.

posted @ 2018-12-29 00:03  江期玉  阅读(186)  评论(0编辑  收藏  举报