欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程语言 > java >内容正文

java

【Java】6.4 final 修饰符

发布时间:2025/3/20 java 39 豆豆
生活随笔 收集整理的这篇文章主要介绍了 【Java】6.4 final 修饰符 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

目录

final 成员变量

final局部变量

 final修饰基本类型变量和引用类型变量的区别

可执行“宏替换”的final变量 

final方法

final类

不可变类

缓存实例的不可变类


【final】关键字可以用来修饰【类】、【变量】(包括成员变量和局部变量)、【方法】

final 成员变量

Java成员(Field)默认是可以由系统执行初始化,程序员可以不指定初始化。而final修饰过的成员变量【必须由程序员执行初始化】,final修饰变量 —— 该变量值只能赋值一次,不可改变。(原因见注释1)

【注意】若final修饰实例变量,可以再如下三个地方为final实例变量的初始值 —— 最多指定一次,不能多也不能少

  • 定义时指定初始值
  • 初始化块
  • 构造器
  • 【添加】普通方法不能为final修饰的成员变量赋值
  • 【添加】final不会对成员变量进行隐式初始化
  • 【注意】普通方法不能对final值修饰的实例变量赋值。若final修饰类变量,可以在如下2个地方为final类变量指定初始值

  • 定义时指定初始值
  • 类初始化
  • 实例变量不能在静态初始化块中指定初始值(原因见注释2),同样的类变量也不能在普通初始化块中指定初始值

    public class FinalVariableTest {// 定义成员变量时的初始值,合法final int a = 6;// 下面变量将在初始化块或构造器中分配初始值final String str;final int c;final static double d;// 以上既没有指定默认值,有没有在初始化块或构造器中指定初始化值// 下面定义的ch实例变量是不合法的// final char ch;// 初始化块,可对没有指定默认值的实例变量指定初始化值{// 在初始化块中为实例变量指定初始值str = "hello";}static {// 静态初始化块为静态变量指定初始值d = 55.56;}// 构造器中,可对既有没有默认初始值,又没有在初始化块中指定初始值的实例变量指定初始值public FinalVariableTest() {c = 5;}public void changeFinal() {// 普通方法不能为final修饰的变量赋值// 不能在普通方法中为final成员变量指定初始值// d=1.2;// ch='a';}public static void main(String[] args) {FinalVariableTest ft = new FinalVariableTest();System.out.println(ft.a); //输出6System.out.println(ft.c); //输出5System.out.println(ft.str); //输出helloSystem.out.println(FinalVariableTest.d); //输出55.56} }

    final局部变量

    系统不会对局部变量初始化,所以需要有程序员显式初始化。在final修饰的局部变量中

  • 可以在定义时就赋值
  • 也可以在后面代码中对final修饰的局部变量赋初始值
  • 且赋值之后不可改变
  •  final修饰基本类型变量和引用类型变量的区别

    当使用final修饰基本类型变量的时候,基本类型变量只能被赋值一次。但是当final修饰引用类型变量的时候,他保存的仅仅只是一个引用,final只能保证这个引用变量的地址不会被改变,即一直引用同一个对象。使用final修饰的引用类型变量不能被重新赋值,但是可以改变引用类新变量所引用对象的内容

    import java.util.Arrays;class Persons{private int age;public Persons(){}public Persons(int age) {this.age=age;}public int getAge() {return age;}public void setAge(int age) {this.age = age;} } public class FinalReferenceTest {public static void main(String[] args) {//final修饰数组变量,iArr是一个引用变量final int[] iArr = {5,6,8,2};System.out.println(Arrays.toString(iArr));//对数组元素进行排序,合法Arrays.sort(iArr);System.out.println(Arrays.toString(iArr));//对于元素赋值,合法iArr[2]=-8;System.out.println(Arrays.toString(iArr));//下面语句对iArr重新赋值,非法//iArr = null;//final修饰Person变量,p是一个引用变量final Persons p = new Persons(45);//改变Person对象的age值,合法p.setAge(23);System.out.println(p.getAge());//下面语句对p重新赋值,非法//p = null;} }

    运行结果

    可执行“宏替换”的final变量 

    final是在编译的时候就确定下来了。只要有变量,编译的时候就确定不下来。对于一个final变量来说,无论它是什么类型的变量,只要满足以下三个条件,这个final就不再是一个变量,而是相当于一个直接量:

  • 使用final修饰符修饰
  • 在定义该final变量时指定了初始值
  • 该初始值可以在编译时就被确定下来
  • final方法

    final修饰的方法不可被重写,常用于不希望父类中的方法被子类重写重写。

    Java提供Object类中就有一个final方法:getClass()

    此外,在Java方法中,final和private一起使用时没有意义(注释3

    public class FinalMethonTest{private void test() {} } class Sub extends FinalVariableTest{//会出现提示性错误@Overrideprivate void test() {//} }

    final类

    final修饰的类不允许有子类。用于保护父类的内部数据和禁止重写父类的方法。。

    不可变类

    不可变类是指创建该类的实例之后,该实例不可被改变。比如8个包装类。 如果需要创建自定义的不可变类,需要遵守如下准则:

  • 使用private和final修饰符来修饰类的成员变量
  • 提供携带参数构造器,用于根据传入参数来初始化类里的成员变量
  • 仅为该类的成员变量提供getter()方法,不要为成员变量提供setter方法,因为普通方法不能修改final修饰的成员变量的值
  • 若有必要,重写Object类的hashCode()和equals()两个方法。equals方法根据关键成员变量来作为两个对象是否相等的标准,除此之外,还应该保证用两个equals方法判断为相等的hashCode方法也相等
  • class Name {private String firstName;private String lastName;public Name() {}public Name(String firstName, String lastName) {this.firstName = firstName;this.lastName = lastName;}public String getFirstName() {return firstName;}public void setFirstName(String firstName) {this.firstName = firstName;}public String getLastName() {return lastName;}public void setLastName(String lastName) {this.lastName = lastName;}}public class Person3 {private final Name name;public Person3(Name name) {// 设置name实例变量为临时创建的Name对象,该对象为firstname和lastname// 与传入的name参数的firstname和lastname相同this.name = new Name(name.getFirstName(),name.getLastName());//若换下面的语句,则可以对firstname做修改//this.name = name;}public Name getName() {return new Name(name.getFirstName(),name.getLastName());//return name;}public static void main(String[] args) {Name n = new Name("悟空", "孙");Person3 p = new Person3(n);// Person对象的name的firstname为:悟空System.out.println(p.getName().getFirstName());// 以下为了改变Person对象的firstname值//无法改变值了,输出还是悟空n.setFirstName("八戒");System.out.println(p.getName().getFirstName());} }

    缓存实例的不可变类

    若经常使用不可变类,可以将不可变类缓存下来。

    class CacheImmutale{private static int MAX_SIZE=10;//用数组缓存已有实例private static CacheImmutale[] cache = new CacheImmutale[MAX_SIZE];//记录缓存实例在缓存中的位置,cache[pos-1]是最新的缓存实例private static int pos = 0;private final String name;private CacheImmutale(String name) {this.name=name;}public String getName() {return name;}public static CacheImmutale valueOf(String name) {//遍历已缓存对象for (int i = 0; i < MAX_SIZE; i++) {//若存在两个相同的实例,则直接返回该缓存实例if(cache[i]!=null&&cache[i].getName().equals(name)) {return cache[i];}}//若缓存池已满if(pos==MAX_SIZE) {//把缓存的第一个对象覆盖,即把刚刚生成的对象放在缓存池最开始的位置cache[0]=new CacheImmutale(name);//把pos设为1pos=1;}else{cache[pos++]=new CacheImmutale(name);}return cache[pos-1];}public boolean equals(Object obj) {if(this==obj) {return true;}if(obj!=null&&obj.getClass()==CacheImmutale.class) {CacheImmutale ci= (CacheImmutale)obj;return name.equals(ci.getName());}return false;}public int hashCode() {return name.hashCode();}} public class CacheImmutaleTest {public static void main(String[] args) {CacheImmutale c1 = CacheImmutale.valueOf("hello");CacheImmutale c2 = CacheImmutale.valueOf("hello");System.out.println(c1==c2); //输出true} }

     

    注释1若让系统初始化,变量则会被自动赋予0/0.0/\u0000/false/null等值。final修饰的这也变量值不允许被改变,name这些就失去价值了

    【注释2】因为静态初始化块是静态成员,不可以访问实例变量 —— 非静态成员。

    【注释3】因为private方法不能被子类中的实例访问到,所以子类中即使有相同的名字、相同的形参列表、相同的返回值,那也只不过是定义了一个新的方法,不是重写。同时final也是不让子类重写方法,所以两者放在一起没有意义

    总结

    以上是生活随笔为你收集整理的【Java】6.4 final 修饰符的全部内容,希望文章能够帮你解决所遇到的问题。

    如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。