Java学习之旅第二季-14:super关键字与final关键字
14.1 super关键字
super 指向父类的实例,但不可单独使用,它可用于普通方法与构造方法中,这两种场景下的意义不一样。
1、用于普通实例方法中,使用super.member的语法显式访问父类的成员,如有一个父类:
public class Parent {protected int num = 10;public void print() {System.out.println(num);}
}
其中声明了一个受保护的 num 属性和一个 public 修饰的方法 print。
为 Parent 类声明一个子类:
public class Child extends Parent {int num = 20;@Overridepublic void print() {System.out.println(num); // 输出的是当前类的 num}public void test() {int num = 30;System.out.println(num); // 输出的是局部变量 num,为30System.out.println(this.num); // 输出的是当前类的属性num,为20System.out.println(super.num); // 输出的是父类的属性num,为10print(); // 访问的是本类的方法 print,输出为 20 super.print(); // 访问的是父类的方法 print,输出为 10}
}
上面的子类中,同样声明了属性num,且重写了方法print,其中输出的就是子类的nun值,另外在test方法中也声明了局部变量num,同时我使用了几种不同的方式获取不同场景下的num,每一句代码我简短的注释了,最后运行结果见注释。
另外一种写法就是重写的方法中使用super访问父类的方法:
@Override
public void print() {System.out.println(num);super.print();
}
这种写法就是要小心,不能少写super,不然就是方法自己调用自己,这是算法中的递归算法,没有终止条件的话,就是一个无法结束的死递归。
2、用于构造方法中,使用super(参数)的形式显式访问父类构造方法
public class Parent {private int num;public Parent(int num) {this.num = num;}public int getNum(){return this.num;}
}
子类的声明:
public class Child extends Parent {public Child(int num){super(num); // 显式调用父类中int参数的构造方法}
}
测试代码:
Child child = new Child(1); // 将 1 传到了父类的属性 num 上
System.out.println(child.getNum()); // 调用的是父类的 getNum 方法,输出的是父类属性 num,为 1
另外几个语法注意点:
- 子类构造方法如果没有显式使用super调用父类构造方法,则会隐式使用super() 调用父类的无参构造方法;当然如果父类没有无参构造方法,则子类会出现语法错误。
- 如果一个类没有可被子类访问的构造方法,则该类不可被继承。比如构造方法是 private 修饰的:
public class Parent {private Parent(int num) {}
}
- 在之前的版本中,super语句必须是构造方法中的第一句代码,但在Java 25中这条限制取消了。
14.2 final关键字
final 直接翻译为最终的,在Java中它可以用于三种场景,下面分别通过代码说明其用法与意义。
1、修饰类,表示该不可继承,如下面的类前使用 了final修饰符:
public final class FinalDemo{}
class关键字前的修饰符,顺序无所谓,将public放在final后面也是可行的。如果强行声明一个类继承 final 修饰的类,则会出现类似下面的错误信息:
Cannot inherit from final class 'com.laotan.article14.FinalDemo'
2、修饰方法,表示该方法不可被子类重写,比如在非final的父类中声明如下的方法:
public class FinalDemo{public final void method(){}
}
虽然类是可以被继承的,但是其中的method方法是不可被重写的。如果强行重写,会有类似以下的错误信息:
'method()' cannot override 'method()' in 'com.laotan.article14.FinalDemo'; overridden method is final
3、修饰变量,表示变量不可重新赋值,也可称为常量。这里的变量包括属性,方法参数及局部变量。比如下面的写法:
public void method() {final int num = 1;System.out.println(num);num++; // 编译错误
}
对于上述代码中的局部变量 num ,一旦声明为 final,则之后是不能改变初始值的。所以第4行直接有编译错误。
如果 fianl 修饰的是引用数据类型也是类似的,比如:
final int[] nums = {1, 2, 3, 4, 5};
nums = new int[]{6, 7, 8, 9, 10}; // 编译错误
第1行中声明的数组是 final 修饰,那么第 2 行再次为nums 赋值就是不合法的。
但是,如果我们不是重新为其赋值,而是使用索引获取其中的元素并更新它呢?
final int[] nums = {1, 2, 3, 4, 5};
for (int i = 0; i < nums.length; i++) {nums[i] *= 2;
}
上述代码片段中针对 final 修饰的数组进行遍历,并将其中所有的元素翻倍,结果并无任何错误,这就说明 final 修饰的变量仅仅限制对其重新赋值,而不是改变其中的元素或使用对象方法修饰其内部属性值。
14.3 小结
本小节介绍了Java中super和final关键字的使用方法。super关键字用于访问父类成员,包括普通方法中的super.member语法和构造方法中的super()调用。final关键字可用于类、方法和变量:修饰类表示不可继承,修饰方法表示不可重写,修饰变量表示不可重新赋值(但可修改对象内容)。文章通过代码示例详细说明了这些关键字的语法规则和使用场景,并说明Java 25中取消lsuper语句必须放在构造方法首行的限制。