164

我正在阅读Khalid Mughal的 Java™ 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()也有效。

这本书的解释是否只适用于实例方法?

4

15 回答 15

204

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

来自 Sun Java教程

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

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

页面上了解覆盖和隐藏之间的区别。

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

于 2012-04-24T05:11:14.493 回答
25

您可以在以下代码中体验到不同之处,这是对您的代码的轻微修改。

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();
    }
}

这是因为静态方法是类方法。

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

于 2014-11-21T05:47:21.743 回答
14

如果这本书真的这么说,那就错了。 [1]

Java 语言规范 #8.4.8指出:

8.4.8 继承、覆盖和隐藏

一个类 C 从它的直接超类继承了超类的所有具体方法 m(静态和实例),其中所有以下都为真:

  • m 是 C 的直接超类的成员。

  • m 是公共的、受保护的或在与 C 相同的包中声明为具有包访问权限。

  • C 中声明的任何方法都没有作为 m 签名的子签名(第 8.4.2 节)的签名。

[1] 在我的副本中没有这样说,第 1 版,2000。

于 2015-04-19T03:43:36.217 回答
14

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
于 2018-07-27T04:33:25.447 回答
5

B.display() 之所以有效,是因为静态声明使方法/成员属于类,而不是任何特定的类实例(又名对象)。你可以在这里阅读更多关于它的信息。

另一件需要注意的是,你不能重写静态方法,你可以让你的子类声明一个具有相同签名的静态方法,但它的行为可能与你期望的不同。这可能是它不被认为是继承的原因。您可以在此处查看有问题的场景和解释。

于 2012-04-24T05:12:59.737 回答
3

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

于 2014-06-24T10:39:33.727 回答
3

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

于 2017-09-27T20:55:18.440 回答
0

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

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

于 2014-07-26T05:03:27.340 回答
0

静态方法在子类中继承,但它不是多态性。当您编写静态方法的实现时,父类方法被过度隐藏,而不是被覆盖。想一想,如果它不是继承的,那么你如何能够在没有 的情况下访问classname.staticMethodname();

于 2014-09-07T11:01:18.153 回答
0

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

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 的静态方法中”# 成功覆盖在第二种情况下,o/p 是在“在 A 的静态方法中”# 静态方法 - 不会考虑多态性

于 2015-05-06T06:32:46.937 回答
0

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

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

于 2022-03-02T13:21:48.077 回答
-1

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

于 2016-04-04T02:24:24.210 回答
-1

许多人已经用文字说出了他们的答案。这是代码中的扩展解释:

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. 当我们通过 . 以静态方式调用 static 时,它会查找该类中定义的静态,或者在继承链中最接近该静态的类。这证明静态方法是继承的。
  2. 从实例调用静态方法时,它会调用编译时类型中定义的静态方法。
  3. 可以从null实例调用静态方法。我的猜测是编译器将在编译期间使用变量类型来查找类,并将其转换为适当的静态方法调用。
于 2018-02-09T03:29:20.803 回答
-2

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

于 2013-09-08T15:46:27.190 回答
-3

静态成员不会被继承到子类,因为继承仅适用于非静态成员。静态成员将由类加载器加载到静态池中。继承仅适用于加载在对象内的那些成员

于 2016-01-16T06:52:16.407 回答