关于java:Java中的final关键字

5次阅读

共计 2668 个字符,预计需要花费 7 分钟才能阅读完成。

final 关键字示意的不可变的。上面探讨 final 关键字应用的三种场合:数据、办法以及类。

final 数据
1、final 属性

程序中常常须要用到一些“常数”。常数次要利用于两个方面:

编译期常数,永远不会扭转
在运行期初始化一个值,不心愿它产生扭转。

对于编译期的常数,计算能够在编译期间提前执行,能够将常数值间接用于程序中。Java 中,这种常数必须是根本数据类型。前置关键字 final 申明。定义时必须提供一个值。

class Person {

final String name;  // name 未初始化,编译出错

}

如果对对象句柄应用 final,final 会将句柄变成一个常数。进行申明时,必须将句柄初始化到一个具体的对象,而且不能将句柄指向另一个对象。

复制代码
class Person {

String name = "张三";

}

public class FinalDemo {

public static void main(String[] args) {final Person p = new Person();
    p = new Person();   // Error: 无奈为最终变量 p 调配值}

}
复制代码
然而,对象自身是能够批改的。

复制代码
class Person {

String name = "张三";

}

public class FinalDemo {

public static void main(String[] args) {final Person p = new Person();
    p.name = "萧萧弈寒";
}

}
复制代码
一个可能的后果:

name = fd1,i1 = 0, i2 = 6

name = fd2,i1 = 8, i2 = 6

i1,i2 是在运行期间随机产生的数据。

2、空白 final

Java1.1 容许创立“空白 final”, 它们属于非凡字段。只管被申明为 final,然而却未失去一个初始值。即便如此,空白 final 还是必须在应用之前失去初始化。示例:

复制代码
class Person {}

public class FinalDemo {

final int i;
final Person p;

FinalDemo() {
    i = 1;
    p = new Person();}

FinalDemo(int x) {
    i = x;
    p = new Person();}

public static void main(String[] args) {FinalDemo fd = new FinalDemo();
}

}
复制代码
当初强行要求对 final 进行赋值解决,要么在定义字段时应用一个表达式,要么在每个构建器中。

3、用 final 润饰参数

查了一些材料,很多人都说用 final 润饰办法参数是避免参数在调用时被批改。集体认为这种说法其实有两种了解:一种是变量的理论值不会被批改,另一种是在办法外部不能被批改。无论是基本参数类型还是援用类型,前一种说法都是谬误的。因为 Java 是值传递。

复制代码
public class FinalDemo {

static void f(final int i) {i++;    // 无奈为 final 变量赋值,编译谬误}

public static void main(String[] args) {
    int x = 10;
    f(x);   // ①
}

}
复制代码
①处调用的 f 办法只是将 x 的值赋给了 i,实际上 i 和 x 是两个变量。

再看上面的例子:

复制代码
class Person {

String name = "张三";

}

public class FinalDemo {

public static void main(String[] args) {final Person p = new Person();
    changeName(p);
    System.out.println(p.name);
}

static void changeName(final Person p) {p.name = "萧萧弈寒";}

}
复制代码
【运行后果】:

萧萧弈寒

由此阐明,final 并不能阻止 changeName()办法扭转 p 的内容。接下来,咱们删除润饰参数的 final,而后在 changeName 办法体内扭转 p 指向的实例:

复制代码
class Person {

String name = "张三";

}

public class FinalDemo {

public static void main(String[] args) {final Person p = new Person();
    p.name = "萧萧弈寒";
    changeName(p);
    System.out.println(p.name);
}

static void changeName(Person p) {p = new Person();
}

}
复制代码
【运行后果】:
changeName 中的 name: 张三
萧萧弈寒

咱们能够看出, 尽管办法体内的 p 指向了其余对象,然而对于 main 办法中的 p 并没有影响。起因还是 Java 是值传递的。具体的请参考 Java 值传递还是援用传递?

final 办法

final 办法次要有两个方面的作用:一种是避免任何继承类笼罩办法。若心愿一个办法的行为在继承期间放弃不变,不可被笼罩和改写,就能够采取这种做法。另一种是进步程序执行的效率。将一个办法设成 final 后,编译器就会疏忽为执行办法调用机制而采取的惯例代码插入方法(将自变量压入堆栈;跳至办法代码并执行它;跳回来;革除堆栈自变量;最初对返回值进行解决)。它会用办法主体内理论代码的一个副原本替换办法调用。这样能够防止办法调用时的零碎开销。若办法体太大,可能效率也得不到晋升。

复制代码
class Human {

public final void show() {//...}

}
public class Man extends Human{

public void show() {}   //Cannot override the final method from Human

}
复制代码

类内所有的 private 办法都主动成为 final。因为不能拜访一个 private 办法,所以它相对不会被笼罩。

final 类

如果整个类都是 final,就表明这个类不容许被继承。或者出于平安方面的理由,不心愿进行子类化。除此之外,或者还思考执行效率的问题,确保波及这个类各对象的所有口头都要尽可能地无效。

final class Human {
}

public class Man extends Human{// The type Man cannot subclass the final class Human
}
留神:数据成员既能够是 final,也能够不是。无论类是否被定义成 final,利用于 final 的规定同样实用于数据成员。

将类定义成 final 后,后果只是禁止被继承。因为禁止了继承,所以一个 final 类中的所有办法都默认为 final。

正文完
 0