文章标题

来源:互联网 发布:以前的淘宝订单不见了 编辑:程序博客网 时间:2024/06/18 17:33

final关键字

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

1. 数据


  • 一个永不变的编译时常量
  • 一个在运行时被初始化的值,而你不希望它被改变

对于编译时常量,编译器可以将该常量值带入任何可能用到它的计算当中,也就是说,可以在编译时执行计算式,减轻附带。必须是基本数据类型,定义的时候必须赋值
对对象引用不是基本类型,当被初始化指向一个对象,就无法指向另一个对象。然而,对象自身却是可以被修改的。同样适用于数组

   private static Random rand=new Random(47);   public static final VAL_TWO=rand.nextInt(20);

这里你新建第二个类,VAL_TWO值也不会变的,因为在类装载的时候,已经初始化了。

空白final

public class BlankFinal{private final int j;public BlankFianl(){j=1;//必须在域的定义处或者每个构造器中用表达式对final进行赋值}}

final参数

int g(final int i){return i+1;}//当基本类型的参数被指明为final,你可以读参数,但无法修改参数,这一特性主要用来向匿名内部类传递数据。

2. 方法

final方法内嵌调用

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

过去建议使用final方法的第二个原因是效率,在java早期版本中,将一个方法指明为final,就是同意编译器将针对该方法的所有调用转为内嵌调用。但是方法太大效率也不会提高,现在java版本中,虚拟机会优化去掉这些效率反而降低的额外的内嵌调用

final 和private 关键字

类中所有的private方法都隐式地指定为final的,由于无法去用private方法,也就无法覆盖它,你可以对private方法添加fianl但那时没有任何额外的意义。

class WithFinals{private final void g(){System.out.println("基类的private类型g()方法");}}class OverridingPrivate extends WithFinals{public final void g(){System.out.println("子类的public类型的g()方法");}}

“覆盖” 只有在某方法是基类的接口的一部分才会出现。即,必须能将一个对象向上转型为它的基本类型并调用相同的方法。如果谋方法是private类型的,它就不是基类的接口的一部分。它仅是一些隐藏于类的程序代码,子类用相同的名称生成一个public、protected或包访问权限的方法的话,仅是生成一个新的方法。

3.类

当将某个类的整体定义为final时,就表明了你不打算继承该类,而且也不允许别人这样做。换句话说,你对该类的设计永不需要做任何改动,或者处于安全考虑,你不希望它有子类。

final class Dinosauer{int i=7;}

final类的域可以选择是或者不是final。然而,由于final类禁止继承,所以final类中所有的方法都隐式的指定为final,因为无法覆盖他们。在final类中可以给方法添加final修饰,同样没有额外的意义。

final的忠告

在设计类时,将方法指明为final的,应该说是明智的,因为你觉得会有人想要覆盖你的方法。有时这是对的。

初始化类的加载

在c++中,如果某个static期望另一个static在被初始化之前就能有效地使用它,那么就会出现问题。但是在Java中就不会出现这个问题,因为它采用了不同的加载方式。

Java中每个类的编译代码都存在于它自己的独立的文件中。该文件只在需要使用程序代码时才会被加载。一般来说”类的代码在初次使用时才加载。”

public class Insect {    private int i = 9;    protected int j;    Insect() {        System.out.println("i= " + i + ", j= " + j);        j = 39;    }    private static int x1 = printInit("static Insect.x1 initialized");//首先执行    static int printInit(String s) {        System.out.println(s);        return 47;    }}
public class Beetle extends Insect {    private int k = printInit("Beetle.k initialized");    public Beetle() {        System.out.println("k = " + k);        System.out.println("j = " + j);    }    private static int x2 = printInit("static Beetle.x2 initialized");    public static void main(String[] args) {        System.out.println("Beetle constructor");        Beetle b = new Beetle();    }}
static Insect.x1 initializedstatic Beetle.x2 initializedBeetle constructori= 9, j= 0Beetle.k initializedk = 47j = 39
  • 在Beetle上运行Java时,所发生的第一件事就是访问Beetle.main(),于是加载器开始启动并再找出Beetle类的编译代码(在名为Beetle.class的文件中)
  • Beetle有一个基类,所以先加载基类Insect()
  • 根基类static 方法先初始化,所以printInit(String s)会先被执行
  • 这样只是初始化,还没有调用,就会先将基类和子类两个类中静态方法调用输出:static Insect.x1 initialized,static Beetle.x2 initialized
原创粉丝点击