为什么以及何时需要在派生类中重新声明静态方法,如果其定义不能被派生类覆盖/更改



我熟悉static关键字,以及它是如何使用的。我知道static方法可以在子类中重新声明,但它的定义被隐藏并且与父类相同。我提到了一些我已经读过的文章链接:

https://www.geeksforgeeks.org/can-we-overload-or-override-static-methods-in-java/

为什么Java不允许覆盖静态方法?

静态和最终的区别?

当派生类定义与基类中的静态方法具有相同签名的静态方法时,派生类中的方法将隐藏基类中的方法。但是基类的方法仍然被称为基类的方法display()例如基类的方法。

但我很好奇为什么以及何时需要重新宣布static派生类中的base class方法(如果其定义不能) 在派生类中重写/更改,而是显示基类的定义?

/* Java program to show that if static method is redefined by 
a derived class, then it is not overriding. */
// Superclass 
class Base { 
// Static method in base class which will be hidden in subclass 
public static void display() { 
System.out.println("Static or class method from Base"); 
} 
// Non-static method which will be overridden in derived class 
public void print() { 
System.out.println("Non-static or Instance method from Base"); 
} 
} 
// Subclass 
class Derived extends Base { 
// This method hides display() in Base 
public static void display() { 
System.out.println("Static or class method from Derived"); 
} 
// This method overrides print() in Base 
public void print() { 
System.out.println("Non-static or Instance method from Derived"); 
} 
} 
// Driver class 
public class Test { 
public static void main(String args[ ]) { 
Base obj1 = new Derived(); 
// As per overriding rules this should call to class Derive's static 
// overridden method. Since static method can not be overridden, it 
// calls Base's display() 
obj1.display(); 
// Here overriding works and Derive's print() is called 
obj1.print();    
} 
} 

这里的主要要点是: 不要使用实例变量来调用static函数。Java 允许它,但它令人困惑,因为它看起来像一个实例方法调用,而事实并非如此。

此行创建一个Derived实例,并将其分配给Base类型变量:

Base obj1 = new Derived(); 

稍后,当您键入:

obj1.display();

真正发生的是:

Base.display();

因为objBase类型的变量,而displaystatic方法。事实上,如果你看一下编译的字节码,你会发现它实际上是那个调用,实例变量在任何地方都没有提到:

公开课测试 { 公共测试(); 法典:  0: aload_0  1: invokespecial #1//Method java/lang/Object.":()V  4:返回 public static void main(java.lang.String[]); 法典:  0:新的 #2//类派生  3:重复  4: invokespecial #3//Method Derived.":()V  7: astore_1  8: aload_1  9:流行音乐 10: invokestatic #4//Method Base.display:()V 13: aload_1 14: invokevirtual #5//Method Base.print:()V 17:返回 }

注意obj1.display()调用之间的区别

10: invokestatic #4//Method Base.display:()V

obj1.print()调用:

13: aload_1 14: invokevirtual #5//Method Base.print:()V

static调用不会在堆栈上推送obj1,而是使用invokestatic.实例调用确实在堆栈 (aload_1) 上推送obj1并调用invokevirtual

如果声明了类型Derivedobj1,则会看到相反的行为。跟:

Derived obj1 = new Derived(); 

然后

obj1.display();

输出:

来自派生的静态或类方法

,因为它实际上是:

Derived.display();

这完全与实例变量的类型有关。实例本身的类型根本不重要(实际上,obj1可能是null)。

不要通过实例变量调用static方法。请改用类名。

我知道static方法可以在子类中重新声明,但它的定义被隐藏并且与父类相同。

当派生类定义与基类中的静态方法具有相同签名的static方法时,派生类中的方法将隐藏基类中的方法。

这两种说法是相互矛盾的。关系如下:当通过派生类引用时,派生的static方法将重写基static方法。因此,对于您的代码,Base.display引用Base.displayDerived.display引用Derived.display。事实上,Derived上有display不会影响Base上的,它仍然可以通过Base(或Base类型变量)访问。(如果你在Derived中没有displayDerived.display会引用Base.display,但既然你这样做了,它就没有了。

但是我很好奇为什么以及何时需要在派生类中重新声明基类的静态方法......

您唯一需要的时间是如果您希望Derived.display(或obj1.displayobj1声明为Derived时)执行与Base.display不同的事情(或obj1.displayobj1声明为Base时)。我能想到的一个例子是创建实例的方法,也许是通过 Builder 模式:

Base b = Base.builder()
.setName("the name")
.setAnswer(42)
.setBiz("baz")
.build();

与。

Derived d = Derived.builder()
.setName("the name")
.setAnswer(42)
.setBiz("baz")
.setDerivedThingy("whatever")
.build();

调用静态成员或方法时不需要实例。

由于静态成员属于类而不是实例。

例 15.11.1-2.接收器变量与静态字段访问无关

以下程序将澄清您的疑问。它演示了空引用也可用于访问类(静态)变量,而不会导致任何 Null 指针异常:

class Test {
static String name = "Jaspreet";
static Test method1(){
System.out.print("Hello world");
return null;
}
public static void main(String[] args) {
System.out.println(method1().name);
}
}

并分析它为什么会发生

即使 method1() 的结果为 null,一个 NullPointerException 没有被抛出。打印"你好世界"表明主要 表达式确实在运行时被完全计算,尽管事实上 仅使用其类型(而不是其值)来确定要确定的字段 访问(因为字段名称是静态的)。

相关内容

最新更新