Các phương thức tĩnh được kế thừa trong Java?


141

Tôi đã đọc Hướng dẫn của Lập trình viên về Chứng nhận SCJP Java ™ của Khalid Mughal.

Trong chương Kế thừa, nó giải thích rằng

Kế thừa của các thành viên gắn chặt với khả năng tiếp cận được tuyên bố của họ. Nếu một thành viên siêu lớp có thể truy cập bằng tên đơn giản của nó trong lớp con (không sử dụng bất kỳ cú pháp bổ sung nào như siêu), thì thành viên đó được coi là kế thừa

Nó cũng đề cập rằng các phương thức tĩnh không được kế thừa. Nhưng mã dưới đây là hoàn hảo tốt:

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();
    }
}

Làm thế nào tôi có thể trực tiếp sử dụng display()trong lớp B? Thậm chí, B.display()còn hoạt động.

Có phải lời giải thích của cuốn sách chỉ áp dụng cho các phương pháp ví dụ?



Đó không phải là những gì nó nói trong bản sao của tôi, phiên bản 1. Vui lòng cung cấp một báo giá thực tế.
Hầu tước Lorne

Câu trả lời:


177

Tất cả các phương thức có thể truy cập được kế thừa bởi các lớp con.

Từ Hướng dẫn Java của Sun :

Một lớp con kế thừa tất cả các thành viên công khai và được bảo vệ của cha mẹ của nó, bất kể lớp con đó nằm trong gói nào. Nếu lớp con đó nằm trong cùng một gói với cha mẹ của nó, thì nó cũng thừa hưởng các thành viên riêng của gói. Bạn có thể sử dụng các thành viên được kế thừa, thay thế chúng, ẩn chúng hoặc bổ sung chúng với các thành viên mới

Sự khác biệt duy nhất với các phương thức tĩnh (lớp) được kế thừa và các phương thức không tĩnh (thể hiện) được kế thừa là khi bạn viết một phương thức tĩnh mới có cùng chữ ký, phương thức tĩnh cũ chỉ bị ẩn, không bị ghi đè.

Từ trang về sự khác biệt giữa ghi đè và ẩn.

Sự khác biệt giữa ẩn và ghi đè có ý nghĩa quan trọng. Phiên bản của phương thức được ghi đè được gọi là phương thức trong lớp con. Phiên bản của phương thức ẩn được gọi phụ thuộc vào việc nó được gọi từ siêu lớp hay lớp con


được kế thừa liên quan đến việc chúng ta có thể ghi đè thành viên đó trong lớp con không?
Thuật toán

Vâng, đó là một phần của thừa kế, nhưng không phải tất cả. Tôi muốn nói rằng các phần chính khác của thừa kế là tái sử dụng mã và đa hình.
yincrash

Liệu xác định lại cũng có một số quy tắc như ghi đè có?
Surender Thakran

2
@ Thuật toán không chính xác. Tất cả những thứ mà lớp con của bạn nhìn thấy trong cấu trúc phân cấp, là thứ mà lớp của bạn được thừa hưởng. Nhưng các phương thức tĩnh được kế thừa, không thể bị ghi đè, chỉ bị ẩn ("khai báo lại" với cùng một chữ ký). Do đó, bạn cũng có thể khai báo các phương thức tĩnh của mình là cuối cùng, điều đó không thành vấn đề. Phương thức tĩnh nào sẽ được gọi được biết đến tại thời điểm biên dịch. Với các phương thức cá thể không phải là cuối cùng, độ phân giải phải được hoãn lại trong thời gian chạy vì chúng có thể bị ghi đè.
Martin Andersson

1
Đoạn cuối của bạn hoàn toàn bị phá hoại !!! "Phiên bản của phương thức overriden được gọi là một trong lớp con" điều này không đúng: Giả sử: Phiên bản của phương thức overriden được gọi chỉ được xác định trong thời gian chạy bởi JVM liên quan đến đối tượng đã tạo ra gọi :)
mounaim

14

Nếu đó là những gì cuốn sách thực sự nói, thì nó đã sai. [1]

Các ngôn ngữ Java Specification # 8.4.8 trạng thái:

8.4.8 Kế thừa, ghi đè và ẩn

Một lớp C kế thừa từ siêu lớp trực tiếp của nó tất cả các phương thức cụ thể m (cả tĩnh và thể hiện) của siêu lớp mà tất cả các điều sau đây là đúng:

  • m là thành viên của siêu lớp trực tiếp của C.

  • m là công khai, được bảo vệ hoặc khai báo với quyền truy cập gói trong cùng gói với C.

  • Không có phương thức nào được khai báo trong C có chữ ký là phần phụ (§8.4.2) của chữ ký của m.

[1] Nó không nói rằng trong bản sao của tôi, ấn bản 1, 2000.


13

Bạn có thể trải nghiệm sự khác biệt trong mã sau đây, đó là một chút sửa đổi so với mã của bạn.

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();
    }
}

Điều này là do các phương thức tĩnh là các phương thức lớp.

A.display () và B.display () sẽ gọi phương thức của các lớp tương ứng của chúng.


1
Gọi một phương thức tĩnh trên một cá thể như bạn đang cố gắng không hoạt động trong java.
Lucas C. Feijo

Đó là những gì chương trình này giải thích, việc khởi tạo đối tượng của B và mong muốn kế thừa hoạt động sẽ không thể thực hiện được với các thành viên tĩnh. Hãy thử lấy cùng một mã trong nhật thực của bạn / bất kỳ ide hoặc biên dịch bằng javac và thực thi nó
Gaurav

2
@ LucasC.Feijo thực sự tôi làm việc. Ít nhất là trong IDE của tôi (nhật thực). Tôi chỉ nhận được một cảnh báo. Nó có thể không phải là phong cách tốt mặc dù ... nhưng đó là một câu chuyện khác.
dingalapadum

2
@ LucasC.Feijo gọi một phương thức tĩnh không được khuyến nghị. Nhưng nó hoạt động tương tự như gọi một phương thức tĩnh trên một tên lớp.
Ziyang Zhang

5

B.display () hoạt động vì khai báo tĩnh làm cho phương thức / thành viên thuộc về lớp chứ không phải bất kỳ thể hiện lớp cụ thể nào (hay còn gọi là Object). Bạn có thể đọc thêm về nó ở đây .

Một điều cần lưu ý là bạn không thể ghi đè một phương thức tĩnh, bạn có thể yêu cầu lớp phụ của bạn khai báo một phương thức tĩnh có cùng chữ ký, nhưng hành vi của nó có thể khác với những gì bạn mong đợi. Đây có lẽ là lý do tại sao nó không được coi là di truyền. Bạn có thể kiểm tra kịch bản có vấn đề và giải thích ở đây .


3

Các phương thức tĩnh trong Java được kế thừa, nhưng không thể bị ghi đè. Nếu bạn khai báo cùng một phương thức trong một lớp con, bạn ẩn phương thức siêu lớp thay vì ghi đè lên nó. Phương pháp tĩnh không đa hình. Tại thời điểm biên dịch, phương thức tĩnh sẽ được liên kết tĩnh.

Thí dụ:

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();
    }
}

Bạn sẽ nhận được những điều sau đây:

Writing
Writing
Writing
Writing book

2

Các phương thức tĩnh được kế thừa trong Java nhưng chúng không tham gia vào đa hình. Nếu chúng ta cố gắng ghi đè các phương thức tĩnh, chúng sẽ chỉ ẩn các phương thức tĩnh siêu lớp thay vì ghi đè chúng.


Tôi không thấy một lý do để hạ thấp câu trả lời này. Nó rõ ràng và rõ ràng, ít nhất là phần đầu tiên. Phần thứ hai không nên được thực hiện quá kỹ thuật, nếu không thì không sao. Để làm rõ, trong các phương thức ghi đè, kiểu trả về có thể thay đổi (thành kiểu phụ) trong khi đây không phải là trường hợp với các phương thức tĩnh. Về mặt kỹ thuật, 'cố gắng ghi đè' không áp dụng cho các phương thức tĩnh, vì vậy tất cả những gì chúng ta có thể nói là chúng ta không thể.
sharhp

2

Khái niệm này không dễ dàng như vẻ ngoài của nó. Chúng ta có thể truy cập các thành viên tĩnh mà không cần kế thừa, đó là mối quan hệ HasA. Chúng ta có thể truy cập các thành viên tĩnh bằng cách mở rộng lớp cha. Điều đó không ngụ ý rằng đó là mối quan hệ của ISA (Kế thừa). Thực tế các thành viên tĩnh thuộc về lớp và static không phải là công cụ sửa đổi truy cập. Miễn là các công cụ sửa đổi truy cập cho phép truy cập các thành viên tĩnh, chúng ta có thể sử dụng chúng trong các lớp khác. Giống như nếu nó là công khai thì nó sẽ có thể truy cập được trong cùng một gói và cả bên ngoài gói. Đối với riêng tư, chúng tôi không thể sử dụng nó bất cứ nơi nào. Để mặc định, chúng tôi chỉ có thể sử dụng nó trong gói. Nhưng để bảo vệ chúng ta phải mở rộng siêu hạng. Vì vậy, có được phương thức tĩnh cho lớp khác không phụ thuộc vào tĩnh. Nó phụ thuộc vào công cụ sửa đổi Access. Vì vậy, theo tôi, Thành viên tĩnh có thể truy cập nếu sửa đổi truy cập cho phép. Mặt khác, chúng ta có thể sử dụng chúng giống như chúng ta sử dụng theo quan hệ Hasa. Và có một mối quan hệ không phải là thừa kế. Một lần nữa chúng ta không thể ghi đè phương thức tĩnh. Nếu chúng ta có thể sử dụng phương thức khác nhưng không thể ghi đè lên nó, thì đó là quan hệ HasA. Nếu chúng ta không thể ghi đè lên thì đó sẽ không phải là thừa kế. Vì vậy, người viết đã đúng 100%.


Mở rộng lớp cha mối quan hệ 'is-a'. Nếu quyền truy cập là riêng tư, bạn có thể sử dụng nó từ trong lớp. 'được bảo vệ' bao gồm các lớp và lớp dẫn xuất trong gói hiện tại. Quá nhiều lỗi ở đây.
Hầu tước Lorne

0

Phương thức tĩnh được kế thừa trong lớp con nhưng nó không phải là đa hình. Khi bạn viết việc thực hiện phương thức tĩnh, phương thức lớp của cha mẹ bị ẩn đi, không bị ghi đè. Hãy suy nghĩ, nếu nó không được kế thừa thì làm sao bạn có thể truy cập mà không cần classname.staticMethodname();?


0

Tất cả các thành viên công khai và được bảo vệ có thể được kế thừa từ bất kỳ lớp nào trong khi các thành viên mặc định hoặc gói cũng có thể được kế thừa từ lớp trong cùng một gói với lớp đó. Nó không phụ thuộc vào việc nó là thành viên tĩnh hay không tĩnh.

Nhưng cũng đúng là chức năng thành viên tĩnh không tham gia liên kết động. Nếu chữ ký của phương thức tĩnh đó giống nhau ở cả lớp cha và lớp con thì khái niệm Shadowing được áp dụng, không phải là đa hình.


0

Bạn có thể ghi đè các phương thức tĩnh, nhưng nếu bạn cố gắng sử dụng đa hình, thì chúng hoạt động theo phạm vi lớp (Trái ngược với những gì chúng ta thường mong đợi).

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 trường hợp đầu tiên, o / p là "phương thức tĩnh của B" # ghi đè thành công Trong trường hợp thứ 2, o / p là "trong phương thức tĩnh của A" # Phương thức tĩnh - sẽ không xem xét tính đa hình


-1

Chúng ta có thể khai báo các phương thức tĩnh có cùng chữ ký trong lớp con, nhưng nó không được xem là ghi đè vì sẽ không có bất kỳ đa hình thời gian chạy nào. Bởi vì tất cả các thành viên tĩnh của một lớp được tải tại thời điểm tải lớp nên nó quyết định biên dịch thời gian (ghi đè vào thời gian chạy) Do đó, câu trả lời là 'Không'.


2
Tôi không biết tại sao mọi người luôn bỏ phiếu và không đưa ra lý do bỏ phiếu.
surajs1n

Câu trả lời này là về ghi đè. Câu hỏi là về thừa kế.
Hầu tước Lorne

-1

Nhiều người đã lên tiếng trả lời bằng lời. Đây là một lời giải thích mở rộng trong các mã:

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();

Các kết quả:

A
B

Test
Test

A
B

Test
Test

A

A

Do đó, đây là kết luận:

  1. Khi chúng ta gọi tĩnh theo cách tĩnh thông qua., Nó sẽ tìm tĩnh được định nghĩa trong lớp đó hoặc lớp gần nhất trong chuỗi kế thừa. Điều này chứng tỏ rằng các phương thức tĩnh được kế thừa.
  2. Khi phương thức tĩnh được gọi từ một thể hiện, nó gọi phương thức tĩnh được định nghĩa trong kiểu thời gian biên dịch.
  3. Phương thức tĩnh có thể được gọi từ một nullthể hiện. Tôi đoán là trình biên dịch sẽ sử dụng kiểu biến để tìm lớp trong quá trình biên dịch và dịch nó sang lệnh gọi phương thức tĩnh thích hợp.

1
Mã đơn thuần không phải là một lời giải thích, nó là một minh chứng. Một câu trả lời cho câu hỏi này nên trích dẫn các tài liệu tham khảo quy phạm, không chỉ thể hiện hành vi của một số thực hiện không có căn cứ.
Hầu tước Lorne

-2

Thành viên tĩnh là thành viên phổ quát. Họ có thể được truy cập từ bất cứ đâu.


4
có thể được truy cập từ bất cứ nơi nào được thực hiện theo nghĩa đen, đó là sai: static! = scope. bạn có thể muốn làm rõ :-)
kleopatra

Trên thực tế, câu trả lời này là tốt khi thực hiện theo nghĩa đen. Tôi không thể nghĩ về một nơi duy nhất trong mã nơi mã có thể đi mà người ta không thể truy cập vào một thành viên tĩnh của lớp. Bạn có thể truy cập chúng trong các bộ khởi tạo tĩnh, hàm tạo tĩnh, hàm tạo cá thể, phương thức, thuộc tính, trong các lớp khác nhau, trong bất kỳ phạm vi nào. Miễn là lớp và phương thức tĩnh là công khai, chúng có thể được truy cập từ bất cứ đâu, giả sử không có phụ thuộc vòng tròn vào các bộ khởi tạo tĩnh. Về bản chất, các thành viên tĩnh không được kế thừa, chúng chỉ là các phương thức cấp lớp (tức là phổ quát) có thể truy cập từ bất cứ đâu.
Triynko

@Triynko Câu trả lời là sai trong trường hợp các phương thức là riêng tư hoặc được bảo vệ gói truy cập từ bên ngoài gói.
Hầu tước Lorne

@kleopatra - lạc đề. đu quay java? những người thực sự sử dụng những ngày này?
MasterJoe2

@Pavan thử gọi tĩnh riêng từ bên ngoài lớp. Nó sẽ không hoạt động.
Rakesh Yadav

-2

Các thành viên tĩnh sẽ không được kế thừa vào lớp con vì kế thừa chỉ dành cho các thành viên không tĩnh .. Và các thành viên tĩnh sẽ được tải bên trong nhóm tĩnh bởi trình nạp lớp. Kế thừa chỉ dành cho những thành viên được tải bên trong đối tượng


Hoàn toàn không chính xác. Xem JLS # 8.4.8 .
Hầu tước Lorne
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.