我熟悉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();
因为obj
是Base
类型的变量,而display
是static
方法。事实上,如果你看一下编译的字节码,你会发现它实际上是那个调用,实例变量在任何地方都没有提到:
公开课测试 { 公共测试(); 法典: 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
。
如果声明了类型Derived
的obj1
,则会看到相反的行为。跟:
Derived obj1 = new Derived();
然后
obj1.display();
输出:
来自派生的静态或类方法
,因为它实际上是:
Derived.display();
这完全与实例变量的类型有关。实例本身的类型根本不重要(实际上,obj1
可能是null
)。
不要通过实例变量调用static
方法。请改用类名。
我知道
static
方法可以在子类中重新声明,但它的定义被隐藏并且与父类相同。。
当派生类定义与基类中的静态方法具有相同签名的
static
方法时,派生类中的方法将隐藏基类中的方法。
这两种说法是相互矛盾的。关系如下:当通过派生类引用时,派生的static
方法将重写基static
方法。因此,对于您的代码,Base.display
引用Base.display
,Derived.display
引用Derived.display
。事实上,Derived
上有display
不会影响Base
上的,它仍然可以通过Base
(或Base
类型变量)访问。(如果你在Derived
中没有display
,Derived.display
会引用Base.display
,但既然你这样做了,它就没有了。
但是我很好奇为什么以及何时需要在派生类中重新声明基类的静态方法......
您唯一需要的时间是如果您希望Derived.display
(或obj1.display
当obj1
声明为Derived
时)执行与Base.display
不同的事情(或obj1.display
当obj1
声明为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 没有被抛出。打印"你好世界"表明主要 表达式确实在运行时被完全计算,尽管事实上 仅使用其类型(而不是其值)来确定要确定的字段 访问(因为字段名称是静态的)。