Java是否继承了静态方法?


141

我正在阅读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()也可以。

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



那不是我在第一版中所说的。请提供实际报价。
罗恩侯爵

Answers:


177

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

从Sun Java 教程

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

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

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

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


那么继承关系到我们是否可以覆盖子类中的该成员?
Algorithmist

好吧,那是继承的一部分,但不是全部。我会说继承的其他主要部分是代码重用和多态性。
yincrash 2012年

重新定义是否也具有覆盖等规则?
Surender Thakran

2
@Algorithmist不完全是。子类在层次结构中进一步看到的所有东西都是您的类继承的东西。但是继承的静态方法不能被覆盖,只能被隐藏(具有相同签名的“重新声明”)。因此,您也可以将静态方法声明为final,这没有关系。在编译时已知将调用哪个静态方法。对于非最终实例方法,必须将解决方案推迟到运行时,因为它们可能会被覆盖。
Martin Andersson 2014年

1
您的最后一段被完全破坏了!“被调用的重写方法的版本是子类中的版本。”这是不正确的:可以说:被调用的重写方法的版本仅在运行时由JVM决定,该JVM与哪个对象使电话:)
mounaim 2014年

14

如果这就是书中所说的话,那就错了。[1]

Java语言规范8.4.8#状态:

8.4.8继承,覆盖和隐藏

类C从其直接超类继承超类的所有具体方法m(静态和实例),并且满足以下所有条件:

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

  • m是公共的,受保护的或通过与C相同的程序包中的程序包访问声明。

  • 用C声明的方法都没有签名是m签名的子签名(第8.4.2节)。

[1]在我的第1版,2000年中没有说过。


13

您可以在下面的代码中体会到不同之处,对您的代码稍作修改。

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()将调用它们各自类的方法。


1
在您要尝试的实例上调用静态方法将无法在Java中工作。
Lucas C. Feijo

这就是程序解释的内容,静态成员无法实例化B的对象并期望继承起作用。尝试采取相同的代码在Eclipse /任何IDE或使用javac编译并执行它
拉夫

2
@ LucasC.Feijo实际上我确实可以。至少在我的IDE中(日食)。我刚刚得到警告。虽然它可能不是很好的风格……但这是另外一回事了。
dingalapadum 2015年

2
不建议在实例上使用@ LucasC.Feijo调用静态方法。但是,其作用与在类名上调用静态方法相同。
张紫阳

5

B.display()之所以有效,是因为静态声明使方法/成员属于该类,而不属于任何特定的类实例(即Object)。您可以在此处了解更多信息。

需要注意的另一件事是,您不能覆盖静态方法,可以让您的子类声明具有相同签名的静态方法,但是其行为可能与您期望的不同。这可能是为什么不将其视为继承的原因。您可以在此处查看有问题的情况和说明。


2

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


我认为没有理由拒绝这个答案。至少在第一部分,它酥脆清晰。第二部分不应该从技术上讲太多,否则就可以了。需要说明的是,在重写方法中,返回类型可以更改(更改为子类型),而静态方法则不是这种情况。从技术上讲,“尝试覆盖”不适用于静态方法,因此我们只能说不能。
sharhp

2

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


扩展父类 “是”关系。如果访问是私有的,则可以在该类中使用它。“受保护”包括派生类和当前包中的类。这里有太多错误。
罗恩侯爵

2

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

0

静态方法在子类中继承,但不是多态性。当编写静态方法的实现时,父级的类方法被隐藏,而不是被覆盖。想想,如果它不是继承的,那么您将如何能够不使用classname.staticMethodname();


0

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

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


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的静态方法中”#静态方法-将不考虑多态性


-1

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


2
我不知道为什么人们总是拒绝投票,却不给出拒绝投票的理由。
surajs1n

这个答案是关于覆盖。问题是关于继承。
罗恩侯爵,

-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实例中调用静态方法。我的猜测是,编译器将在编译期间使用变量类型查找类,并将其转换为适当的静态方法调用。

1
仅仅代码不是解释,而是演示。这个问题的答案应该引用规范性参考文献,而不仅仅是展示某些未声明实现的行为。
罗恩侯爵

-2

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


4
可以从字面上看的任何地方访问,这是错误的:static!= scope。您可能需要澄清
一下

实际上,从字面上看,这个答案很好。我想不出代码中的哪个地方可以访问代码的静态成员。您可以在任何范围的不同类中的静态初始化程序,静态构造函数,实例构造函数,方法,属性中访问它们。只要类和静态方法是公共的,就可以从任何地方访问它们,前提是这些静态和初始值设定项之间没有循环依赖关系。本质上,静态成员不是继承的,它们只是可以从任何地方访问的类级别(即通用)方法。
Triynko 2014年

@Triynko对于私有方法或从程序包外部访问受程序包保护的方法,答案是错误的。
罗恩侯爵,

@kleopatra-离题。Java秋千?这些天人们实际上使用了吗?
MasterJoe2 '16

@Pavan尝试从类外部调用private static。它不会工作。
Rakesh Yadav'7

-2

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


完全不正确。参见JLS#8.4.8
罗恩侯爵'18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.