关于继承:是否在Java中继承了静态方法?

Are static methods inherited in Java?

我在读一本程序员指南爪哇?哈立德莫卧儿的SCJP认证。

在继承一章中,它解释了

Inheritance of members is closely tied to their declared
accessibility. If a superclass member is accessible by its simple name
in the subclass (without the use of any extra syntax like super), that
member is considered inherited

它还提到静态方法不是继承的。但是下面的代码是完美的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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();
    }
}

我如何能直接在B类中使用display()?更重要的是,B.display()也起作用。

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


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

来自Sun JAVA教程:

A subclass inherits all of the public and protected members of its parent, no matter what package the subclass is in. If the subclass is in the same package as its parent, it also inherits the package-private members of the parent. You can use the inherited members as is, replace them, hide them, or supplement them with new members

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

从页面上看,覆盖和隐藏的区别。

The distinction between hiding and overriding has important implications. The version of the overridden method that gets invoked is the one in the subclass. The version of the hidden method that gets invoked depends on whether it is invoked from the superclass or the subclass


如果这就是书中所说的,那就错了。

Java语言规范84.8状态:

8.4.8 Inheritance, Overriding, and Hiding

A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass for which all of the following are true:

  • m is a member of the direct superclass of C.

  • m is public, protected, or declared with package access in the same package as C.

  • No method declared in C has a signature that is a subsignature (§8.4.2) of the signature of m.

[1]在我的2000年第1版中没有这么说。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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()将调用各自类的方法。


b.display()之所以有效,是因为静态声明使方法/成员属于类,而不是任何特定的类实例(aka对象)。你可以在这里了解更多。

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


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


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

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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();
    }
}

您将得到以下信息:

1
2
3
4
Writing
Writing
Writing
Writing book


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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是"静态方法中的"静态方法-不考虑多态性


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


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

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


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


许多人已经用语言表达了他们的答案。这是代码中的扩展说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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();

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
A
B

Test
Test

A
B

Test
Test

A

A

因此,得出以下结论:

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

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


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


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