我正在阅读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()
也有效。
本书的解释是否仅适用于实例方法?
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
我们可以在子类中声明具有相同签名的静态方法,但是它不被认为是覆盖,因为不存在任何运行时多态性。因为类的所有静态成员都是在类加载时加载的,所以它在编译时决定时间(在运行时覆盖)因此答案是'否'。
许多人用语言表达了他们的答案。这是代码中的扩展说明:
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
实例调用静态方法。我的猜测是编译器将使用变量类型在编译期间查找类,并将其转换为适当的静态方法调用。静态成员是普遍成员。他们可以从任何地方访问。
静态成员不会继承到子类,因为继承仅适用于非静态成员。静态成员将通过类加载器加载到静态池中。继承仅适用于在对象内部加载的成员
如果这就是这本书的真实内容,那就错了。[1]
Java Language Specification #8.4.8说:
8.4.8 Inheritance, Overriding, and Hiding
类C从其直接超类继承超类的所有具体方法m(静态和实例),以下所有条件都为真:
- m是C的直接超类的成员。
- m是与C相同的包中的公共,受保护或声明的包访问。
- 在C中声明的方法没有签名是m的签名的子签名(第8.4.2节)。
[1]它并没有在我的副本中,第1版,2000年。
您可以体验以下代码中的差异,这稍微修改了您的代码。
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()将调用各自类的方法。
这个概念并不像看起来那么容易。我们可以访问没有继承的静态成员,即HasA-relation。我们也可以通过扩展父类来访问静态成员。这并不意味着它是一个ISA关系(继承)。实际上,静态成员属于该类,而static不是访问修饰符。只要访问修饰符允许访问静态成员,我们就可以在其他类中使用它们。就像它是公共的一样,它可以在同一个包中访问,也可以在包外。对于私人我们不能在任何地方使用它。默认情况下,我们只能在包中使用它。但是对于受保护,我们必须扩展超类。因此将静态方法引入其他类并不依赖于静态。它取决于Access修饰符。因此,在我看来,如果访问修饰符允许,静态成员可以访问。否则,我们可以像Hasa-relation一样使用它们。并且有一种关系不是继承。我们再次无法覆盖静态方法。如果我们可以使用其他方法但不能覆盖它,则它是HasA关系。如果我们不能覆盖它们就不会继承。所以作者是100%正确的。
静态方法在Java中继承,但它们不参与多态。如果我们尝试覆盖静态方法,它们只会隐藏超类静态方法而不是覆盖它们。
静态方法在子类中继承,但它不是多态的。在编写静态方法的实现时,父类的方法被隐藏,而不是被覆盖。想想,如果没有继承那么你怎么能在没有classname.staticMethodname();
的情况下访问?
所有公共成员和受保护成员都可以从任何类继承,而默认或包成员也可以从与超类相同的包中的类继承。它不取决于它是静态成员还是非静态成员。
但静态成员函数也不参与动态绑定也是如此。如果该静态方法的签名在父类和子类中都相同,则应用Shadowing的概念,而不是多态。
您可以覆盖静态方法,但如果您尝试使用多态,则它们根据类范围工作(与我们通常期望的相反)。
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”#静态方法 - 不会考虑多态性