Java中的静态方法是继承的吗?

Posted

技术标签:

【中文标题】Java中的静态方法是继承的吗?【英文标题】:Are static methods inherited in Java? 【发布时间】:2012-05-04 17:42:28 【问题描述】:

我正在阅读程序员指南 由 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();
    

我怎样才能在课堂B 中直接使用display()?更重要的是,B.display() 也可以。

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

【问题讨论】:

***.com/questions/4716040/… 有有趣的信息。 这不是我的副本中所说的,第一版。请提供实际报价。 相关:***.com/questions/25169175/… 【参考方案1】:

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

来自 Sun Java Tutorials:

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

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

来自page 关于覆盖和隐藏的区别。

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

【讨论】:

如此继承关系到我们是否可以覆盖子类中的那个成员? 嗯,这是继承的一部分,但不是全部。我想说继承的其他主要部分是代码重用和多态性。 重新定义是否也有一些规则,比如覆盖有? @Algorithmist 不完全是。你的子类在层次结构中看到的所有东西都是你的类继承的东西。但是继承的静态方法不能被覆盖,只能隐藏(“重新声明”具有相同的签名)。因此,你也可以将你的静态方法声明为 final,没关系。将调用哪个静态方法在编译时是已知的。对于非最终实例方法,解决方案必须推迟到运行时,因为它们可能会被覆盖。 你的最后一段完全被破坏了!!! “被调用的覆盖方法的版本是子类中的版本”这是不正确的:假设:被调用的覆盖方法的版本仅在运行时由与哪个对象相关的JVM确定打电话:)【参考方案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 中不起作用。 这就是这个程序所解释的,实例化 B 的对象并期望继承工作对于静态成员是不可能的。尝试在你的 eclipse/任何 ide 中使用相同的代码或使用 javac 编译并执行它 @LucasC.Feijo 实际上我确实有效。至少在我的 IDE(日食)中。我只是得到一个警告。虽然这可能不是很好的风格......但这是一个不同的故事。 @LucasC.Feijo 不建议在实例上调用静态方法。但它的工作原理与在类名上调用静态方法相同。【参考方案3】:

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

Java Language Specification #8.4.8 声明:

8.4.8 继承、覆盖和隐藏

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

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

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

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

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

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

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

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

【讨论】:

【参考方案6】:

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

【讨论】:

我看不出拒绝这个答案的理由。至少第一部分清晰明了。第二部分不应该太技术化,否则没关系。澄清一下,在覆盖方法中,返回类型可以更改(到子类型),而静态方法并非如此。从技术上讲,“尝试覆盖”不适用于静态方法,所以我们只能说我们不能。【参考方案7】:

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

【讨论】:

扩展父类is是一种“is-a”关系。如果访问是私有的,您可以在班级内使用它。 'protected' 包括派生类和当前包中的类。这里错误太多。【参考方案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();


    



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

【讨论】:

【参考方案11】:

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

【讨论】:

我不知道为什么人们总是投反对票而不给出反对票的原因。 这个答案是关于覆盖的。问题是关于继承的。【参考方案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

因此,这是结论:

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

【讨论】:

纯代码不是解释,而是演示。这个问题的答案应该引用规范性参考,而不仅仅是展示一些未说明的实现的行为。【参考方案13】:

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

【讨论】:

可以从任何地方访问字面意思,这是错误的:静态!=范围。你可能想澄清:-) 实际上,从字面上看,这个答案很好。我想不出代码中有一个地方不能访问类的静态成员。您可以在静态初始化程序、静态构造函数、实例构造函数、方法、属性中,在不同的类中,在任何范围内访问它们。只要类和静态方法是公共的,就可以从任何地方访问它们,假设静态初始化器没有循环依赖。本质上,静态成员不是继承的,它们只是可以从任何地方访问的类级别(即通用)方法。 @Triynko 对于私有方法或从包外部访问的受包保护的方法,答案是错误的。 @kleopatra - 题外话。爪哇摇摆?这些天人们真的使用它吗? @Pavan 尝试从类外调用私有静态。它不会起作用。【参考方案14】:

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

【讨论】:

完全不正确。见JLS #8.4.8。 不正确,如果您现在清楚,请更新您的答案:)

以上是关于Java中的静态方法是继承的吗?的主要内容,如果未能解决你的问题,请参考以下文章

在Java中,类中的枚举类型是静态的吗?

Python中静态方法和类方法的区别

Java中的静态类

Java继承方法隐藏(覆盖)

java中静态属性和和静态方法的继承问题 以及多态的实质

java中静态变量与静态方法的继承(转)