无论属性是基本类型、引用类型,都使变量里存放的“值”不可变。
常和static关键字协作,作为常量:
所以修饰的变量必须初始化:
public static final String LOAN = "loan";
LOAN = new String("loan") //invalid compilation error
final变量只读!
该方法可被继承,但不许被任何子类重写。
调用final方法时,直接将方法主体插入到调用处,而非进行方法调用,这样能提高程序效率(内联机制)。
如认为一个方法功能够完整,子类中不需要改变,可声明为final。final方法比非final方法快,因为在编译时候已静态绑定,无需在运行时再动态绑定。
class PersonalLoan{
public final String getName(){
return "personal loan";
}
}
class CheapPersonalLoan extends PersonalLoan{
@Override
public final String getName(){
return "cheap personal loan"; //compilation error: overridden method is final
}
}
使用final来修饰的类叫作final类。
final类通常功能是完整的,不能被继承。Java中有许多类是final,如String、Interger及其他包装类。类不可被继承,但这并非表示final类的实例变量也不可变,除非给实例变量也增加final修饰。
final class PersonalLoan{
}
class CheapPersonalLoan extends PersonalLoan{ //compilation error: cannot inherit from final class
}
一个类不可同时被abstract和final修饰。
创建不可变类要使用final关键字。不可变类是指它的对象一旦被创建了就不能被更改了。String是不可变类的代表。不可变类有很多好处,譬如它们的对象是只读的,可以在多线程环境下安全的共享,不用额外的同步开销等等。
final变量就是常量,常量名通常大写:
private final int COUNT = 10;
对于集合对象声明为final指的是引用不能被更改,但是你可以向其中增加,删除或者改变内容。譬如:
private final List Loans = new ArrayList();
list.add(“home loan”); //valid
list.add("personal loan"); //valid
loans = new Vector(); //not valid
此项检查会报告那些可安全地声明为 final
的字段。所有 final
字段都有一个值,并且这个值在初始化后不会改变,可使代码更易理解和推断。
为了避免过于耗时的分析,此检查仅在以下情况下报告字段: 字段具有 private
修饰符,或字段定义在局部类或匿名类中。 一个字段可以被设为 final
,如满足以下条件:
static
初始化块中被精确地初始化一次且字段在其他任何地方都未被修改。
示例:
public class Person {
private String name;
Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
修复后:
public class Person {
private final String name;
Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
使用 "Annotations" (注解) 按钮来修改注解列表。这些注解会被认为隐含了对字段的写入操作(这会阻止字段被标记为 final
)。
byte b1 = 1;
byte b2 = 3;
// 当程序执行到这一行的时候会出错
// 因b1、b2可自动转换成int型变量,运算时JVM对它进行转换,结果导致把一个int赋值给byte
byte b3 = b1 + b2; // Error: Type mismatch: cannot convert from int to byte
final byte b1=1;
final byte b2=3;
// 不会出错,看了上面的解释就知道原因
byte b3=b1+b2;
byte b3 = b1 + b2;
报错Java 的算术运算类型提升 (Integer Promotion):对小于 int
的整型(即 byte
, short
, char
)进行算术运算(如 +
, -
, *
, /
),它们的操作数会先被自动提升(promote)为 int
类型,然后执行运算。
因此,b1 + b2
表达式实际按 (int)b1 + (int)b2
来执行的。两个 int
类型相加,其结果必然是 int
类型。
表达式 b1 + b2
的结果是 int
类型(值为 4),而变量 b3
被声明为 byte
类型。将一个 int
类型的值赋给 byte
类型的变量属于窄化原始类型转换 (Narrowing Primitive Conversion)。
Java 编译器不允许这种可能导致精度丢失的隐式窄化转换。因为 int
的范围(-2^31 到 2^31-1)远大于 byte
的范围(-128 到 127),直接赋值可能会丢失信息。所以编译器会报错,提示类型不匹配。
如果确实需要将结果赋给 byte
,必须进行强制类型转换:
byte b3 = (byte)(b1 + b2); // 显式强制转换,编译通过
当 byte
变量被 final
修饰且在声明时用常量(字面量)初始化时,b1
和 b2
成为编译时常量 (Compile-time constants)。
常量折叠 (Constant Folding): Java 编译器会对涉及编译时常量的表达式进行常量折叠优化。即编译器在编译阶段就直接计算出 b1 + b2
的结果。它看到 1 + 3
,直接计算得到常量 4
。
编译时检查常量值: 此时,赋值语句 byte b3 = b1 + b2;
在编译期间实际上被看作是 byte b3 = 4;
。Java 编译器特殊规则:如果一个 int
类型的常量值(字面量或编译时常量表达式的结果)在 byte
类型的表示范围内(-128 到 127),那么编译器允许将这个 int
常量隐式地赋值给 byte
变量。
赋值通过: 因为 4
在 byte
的范围 -128, 127 之内,所以编译器认为这个赋值是安全的,不会导致信息丢失,因此编译通过。
本文已收录在Github,关注我,紧跟本系列专栏文章,咱们下篇再续!
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有