静态方法是否在 Java 中继承?

我正在阅读《程序员指南》 由 Khalid Mughal 提供的 JavaTM SCJP 认证

在继承一章中,它解释了

成员的继承与其宣布的继承密切相关 如果一个超类成员可以通过它的简单名称来访问 在子类中(不使用任何像 super 这样的额外语法) , 成员被认为是继承的

它还提到静态方法不会被继承,但是下面的代码完全没问题:

class A
{
public static void display()
{
System.out.println("Inside static method of superclass");
}
}


class B extends A
{
public void show()
{
// This works - accessing display() by its simple name -
// meaning it is inherited according to the book.
display();
}
}

我如何能够直接使用 display()在类 B? 甚至更多,B.display()也工作。

书中的解释仅适用于实例方法吗?

177808 次浏览

所有可访问的方法都由子类继承。

摘自 Sun Java 教程:

子类继承其父类的所有公共成员和受保护成员,而不管子类在哪个包中。如果子类与其父类在同一个包中,它还继承父类的包私有成员。您可以按原样使用继承的成员、替换它们、隐藏它们或用新成员补充它们

继承的静态(类)方法和继承的非静态(实例)方法的唯一区别是,当您使用相同的签名编写新的静态方法时,旧的静态方法只是隐藏而不是重写。

关于重写和隐藏之间的区别。

隐藏和重写之间的区别有着重要的含义。被调用的重写方法的版本是子类中的版本。调用的隐藏方法的版本取决于是从超类还是从子类调用它

Display ()之所以能够工作,是因为静态声明使方法/成员属于类,而不是任何特定的类实例(又名对象)。你可以阅读更多关于它的资料。

另一件需要注意的事情是,您不能重写静态方法,您可以让您的子类声明具有相同签名的静态方法,但是它的行为可能与您预期的不同。这可能就是为什么它不被认为是遗传的原因。您可以查看有问题的场景和解释 给你

静态成员是通用成员,可以从任何地方访问它们。

静态方法在 Java 中继承,但它们不参与多态性。如果我们试图重写静态方法,它们只会隐藏超类静态方法,而不会重写它们。

所有公共成员和受保护成员都可以从任何类继承,而默认成员或包成员也可以从与超类在同一个包中的类继承。它不依赖于它是静态成员还是非静态成员。

但是静态成员函数不参与动态绑定也是事实。如果这个静态方法的签名在父类和子类中都是相同的,那么应用阴影概念,而不是多态性。

静态方法在子类中继承,但不是多态的。在编写静态方法的实现时,父类的类方法处于过度隐藏状态,而不是重写状态。想一想,如果没有继承,那么如何能够访问没有 classname.staticMethodname();

您可以在下面的代码中体验到这种差异,这是对代码的轻微修改。

class A {
public static void display() {
System.out.println("Inside static method of superclass");
}
}


class B extends A {
public void show() {
display();
}


public static void display() {
System.out.println("Inside static method of this class");
}
}


public class Test {
public static void main(String[] args) {
B b = new B();
// prints: Inside static method of this class
b.display();


A a = new B();
// prints: Inside static method of superclass
a.display();
}
}

这是由于静态方法是类方法。

Display ()和 B.display ()将调用它们各自类的方法。

如果这本书真是这么说的,那就错了

Java 语言规格 # 8.4.8指出:

8.4.8继承、重写和隐藏

类 C 从它的直接超类继承超类的所有具体方法 m (包括静态方法和实例方法) ,对于这些方法,以下所有条件都成立:

  • M 是 C 的直超类的一个成员。

  • M 是公共的、受保护的,或者在与 C 相同的包中通过包访问声明的。

  • C 中声明的任何方法的签名都不是 m 的签名的子签名(8.4.2)。

[1]在我2000年的第一版中没有这样写。

您可以重写静态方法,但是如果您尝试使用多态性,那么它们将根据类范围工作(与我们通常期望的相反)。

public class A {


public static void display(){
System.out.println("in static method of A");
}
}


public class B extends A {


void show(){
display();
}


public static void display(){
System.out.println("in static method of B");
}


}
public class Test {


public static void main(String[] args){
B obj =new B();
obj.show();


A a_obj=new B();
a_obj.display();




}




}

在第一种情况下,o/p 是“ B 的静态方法”# 成功覆盖 在第2种情况下,o/p 是“在 A 的静态方法”# 静态方法-不会考虑多态性

静态成员不会继承到子类,因为继承只针对非静态成员。 静态成员将由类装入器装入静态池中。继承只适用于对象内部加载的成员

我们可以在子类中声明具有相同签名的静态方法,但是不会考虑重写,因为不会存在任何运行时多态性。因为类的所有静态成员都是在类加载时加载的,所以它在编译时决定(在运行时重写) ,所以答案是“否”。

这个概念并不像看上去那么简单。我们不需要继承就可以访问静态成员,这就是 HasA- 关系。我们也可以通过扩展父类来访问静态成员。这并不意味着它是一个 ISA 关系(继承)。实际上,静态成员属于类,静态成员不是访问修饰符。只要访问修饰符允许访问静态成员,我们就可以在其他类中使用它们。比如,如果它是公共的,那么它可以在同一个包内部访问,也可以在包外部访问。我们不能把它用在任何地方。默认情况下,我们只能在包中使用它。但是为了保护,我们必须扩展超级类。因此将静态方法传递给其他类并不依赖于是静态的。它取决于 Access 修饰符。因此,在我看来,静态成员可以在访问修饰符允许的情况下进行访问。否则,我们可以像 Hasa 关系那样使用它们。而有关系就不是继承。同样,我们不能重写静态方法。如果我们可以使用其他方法,但不能覆盖它,那么它是 HasA- 关系。如果我们不能覆盖它们,那就不是继承,所以作者是100% 正确的。

许多人已经用语言表达了他们的答案,这是一个扩展的代码解释:

public class A {
public static void test() {
System.out.println("A");
}
public static void test2() {
System.out.println("Test");
}
}


public class B extends A {
public static void test() {
System.out.println("B");
}
}


// Called statically
A.test();
B.test();
System.out.println();


// Called statically, testing static inheritance
A.test2();
B.test2();
System.out.println();


// Called via instance object
A a = new A();
B b = new B();
a.test();
b.test();
System.out.println();


// Testing inheritance via instance call
a.test2();
b.test2();
System.out.println();


// Testing whether calling static method via instance object is dependent on compile or runtime type
((A) b).hi();
System.out.println();


// Testing whether null instance works
A nullObj = null;
nullObj.hi();

结果:

A
B


Test
Test


A
B


Test
Test


A


A

因此,结论如下:

  1. 当我们以静态的方式通过。,它将查找在该类中定义的静态,或者与继承链中定义的类最接近的类。这证明了静态方法是继承的。
  2. 当从实例调用静态方法时,它将调用在编译时类型中定义的静态方法。
  3. 静态方法可以从 null实例调用。我的猜测是,编译器将使用变量类型在编译期间查找类,并将其转换为适当的静态方法调用。

Java 中的静态方法是继承的,但不能被重写。如果在子类中声明相同的方法,则隐藏超类方法,而不是重写它。静态方法不是多态的。在编译时,静态方法将被静态链接。

例如:

public class Writer {
public static void write() {
System.out.println("Writing");
}
}


public class Author extends Writer {
public static void write() {
System.out.println("Writing book");
}
}


public class Programmer extends Writer {


public static void write() {
System.out.println("Writing code");
}


public static void main(String[] args) {
Writer w = new Programmer();
w.write();


Writer secondWriter = new Author();
secondWriter.write();


Writer thirdWriter = null;
thirdWriter.write();


Author firstAuthor = new Author();
firstAuthor.write();
}
}

你会得到以下信息:

Writing
Writing
Writing
Writing book

类中的静态方法被继承,而接口中的静态方法不被继承。

类中的静态方法可以使用实例调用,而接口中的静态方法只能通过接口名调用,因为它们不是继承的