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

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

评论

stackoverflow.com/questions/4716040/…有有趣的信息。

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

相关:stackoverflow.com/questions/25169175/…

#1 楼

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

从Sun Java教程:


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


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

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


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


评论


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

–算法专家
2012年4月24日在5:20

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

– yincrash
2012年4月24日5:24



重新定义是否也具有覆盖等一些规则?

–投降Thakran
13年3月28日在2:34

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

–马丁·安德森(Martin Andersson)
14年4月14日在9:09

您的最后一段被完全破坏了!!! “被调用的重写方法的版本是子类中的版本”这是不正确的:假设:被调用的重写方法的版本仅在运行时由JVM确定,而JVM与哪个对象已打电话:)

– mounaim
14年4月16日在8:49

#2 楼

您可以在下面的代码中体验到差异,对您的代码稍作修改。

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

评论


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

–卢卡斯·费霍(Lucas C. Feijo)
16年8月24日在16:06

多数民众赞成在此程序的解释,实例化B的对象,并期望继承工作与静态成员是不可能的。尝试在eclipse /任何ide中采用相同的代码,或者使用javac进行编译并执行

–加拉夫
16-8-25在11:43



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

– dingalapadum
17年4月25日在0:00

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

–张紫阳
18-2-24在3:16

#3 楼

如果那是本书的真正意思,那就错了。[1]

Java语言规范#8.4.8指出:


8.4.8继承,重写,以及Hide

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


m是C的直接超类的成员。
m是公共的,受保护的或通过与C相同的程序包中的程序包访问来声明。
C中声明的任何方法都没有以下签名: m的签名的子签名(第8.4.2节)。



[1]在我的副本(2000年第1版)中没有说过。

#4 楼

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

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

#5 楼

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


#6 楼

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

评论


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

– sharhp
17年8月12日下午4:50

#7 楼

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

评论


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

–user207421
18年11月8日在9:50

#8 楼

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

#9 楼

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

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

#10 楼

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

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

#11 楼

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

评论


我不知道为什么人们总是拒绝投票,而没有给出拒绝投票的理由。

– surajs1n
16年4月4日在2:52

这个答案是关于压倒一切的。问题是关于继承。

–user207421
16年4月6日在10:28

#12 楼

许多人用言语表达了自己的答案。这是代码的扩展解释:

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


因此,这是结论:


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


评论


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

–user207421
18-3-29的1:18

#13 楼

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

评论


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

– kleopatra
2013年9月8日在16:12



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

– Triynko
2014年2月24日18:21



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

–user207421
16-4-6在10:29



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

– MasterJoe
16-11-17在7:19

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

– Rakesh Yadav
17年7月27日在0:20

#14 楼

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

评论


完全不正确。参见JLS#8.4.8。

–user207421
18-3-29在1:20



错误的,如果您现在很清楚,请更新您的答案:)

–令人讨厌
10月4日7:06