前言
今天在复习final关键字的时候突发奇想,在考虑static和final关键字既然可以修饰静态常量,那能否修饰一个方法呢?带着这个问题,我发掘到了一个疑问点:Java中父类的静态方法能否被子类重写?
一、final关键字和static关键字介绍
先来简单回顾下这两个关键字的具体含义
(1)final:可以修饰类、属性、方法和局部变量。
应用:①当不希望类被继承时,可用final修饰。
②当不希望父类的某个方法被子类重写(override)时,可用final修饰。
③当不希望类的某个属性的值被修改,可用final修饰。
④当不希望某个局部变量被修改,可用final修饰(也称为局部变量)。
(2)static:用来修饰静态变量和静态方法的关键字。
①静态变量:该类所有对象共享的变量,在类加载时就已经初始化了,即使未创建对象,也能通过类名.静态变量名来访问。类变量的生命随着类的加载开始,随类的消亡而销毁。
②静态方法:静态方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区,静态方法中只能使用静态成员(静态变量和静态方法),不能使用和对象有关的关键字(如this和super)
二、问题产生及解决
1.错误结论
在复习完这两个关键字后,由于可以用static final修饰一个常量,也叫静态常量,因此我尝试了一下能否用这两个关键字修饰方法
代码如下(示例):
class a{
public static void q(){
}
}
class b extends a{
public static final void q(){
System.out.println("aaa");
}
}
但这里Idea却警告:‘static’ method declared ‘final’,由于在前面学习静态方法时我尝试在子类中重写了父类的静态方法,结果竟然还输出了正确的重写方法,我也得到了一个错误的结论:静态方法可以重写。
public class Test {
public static void main(String[] args) {
bb b1 = new bb();
b1.q();
}
}
class aa{
public static void q(){
System.out.println("这是父类a的静态方法");
}
}
class bb extends aa{
public static void q(){
System.out.println("这是子类b的静态方法");
}
}
这里输出了这是子类b的静态方法,因此我得到了错误结论
2.正确结论及验证
实际上父类的静态方法能被子类继承,但不能被子类重写
为什么呢?因为如果静态方法q()
被重写的话,那么使用多态向上转型,调用得到的输出也应该是这是子类b的静态方法。
public class Test {
public static void main(String[] args) {
aa b1 = new bb();
b1.q();
}
}
class aa{
public static void q(){
System.out.println("这是父类a的静态方法");
}
}
class bb extends aa{
public static void q(){
System.out.println("这是子类b的静态方法");
}
}
但这里输出的是这是父类a的静态方法,这也证明了在子类bb中的静态方法q()
根本没有重写父类中的静态方法。因此证明了父类的静态方法不能被子类重写。
这里再看下重写的概念:重写指的是根据运行时对象的类型来决定调用哪个方法,而不是根据编译时的类型。因此概念是不对的。
通过这个例子我也得出了另一个结论:对于一个类创建的对象,其静态方法的调用看的是该对象的编译类型,即"=“左边的类型(多态的知识)。而对于普通方法的调用,看的则是该对象的运行类型,即”="右边的类型。
总结
对于父类的静态方法不能被子类重写这个结论,可以理解为在类加载时就已经加载了,因此不能重写(个人理解,可能比较浅薄,希望大佬多多指正)。而子类中的q()
方法根本不是重写父类的q()
方法,即使子类中的静态方法与父类中的静态方法完全一样,也是两个完全不同的方法。