Hành vi của phương thức tĩnh cuối cùng


123

Tôi đã thử với các công cụ sửa đổi với phương thức tĩnh và bắt gặp một hành vi kỳ lạ.

Như chúng ta đã biết, các phương thức tĩnh không thể bị ghi đè, vì chúng được liên kết với lớp chứ không phải trường hợp.

Vì vậy, nếu tôi có đoạn mã dưới đây, nó sẽ biên dịch tốt

//Snippet 1 - Compiles fine
public class A {
    static void ts() {
    }
}

class B extends A {
    static void ts() {
    }
}

Nhưng nếu tôi đưa công cụ sửa đổi cuối cùng vào phương thức tĩnh trong lớp A, thì quá trình biên dịch không thành công ts () trong B không thể ghi đè ts () trong A; phương thức ghi đè là cuối cùng tĩnh .

Tại sao điều này lại xảy ra khi phương thức tĩnh không thể được ghi đè?


2
nó có vẻ kỳ lạ, +1 cho câu hỏi, nhưng cho đến bây giờ không có câu trả lời nào thỏa đáng.
Rakesh Juyal

1
Nó không bị ghi đè. Nó vẫn ở đó tại A.ts ().
Alex Feinman

Câu trả lời:


166

Các phương thức static không thể bị ghi đè nhưng chúng có thể bị ẩn đi. Các ts()phương pháp B không được trọng (không thuộc đối tượng đa hình) các ts()của A nhưng nó sẽ ẩn nó. Nếu bạn gọi ts()trong B (NOT A.ts()hoặc B.ts()... just ts()), một trong B sẽ được gọi chứ không phải A. Vì điều này không phải là đa hình, nên lệnh gọi ts()trong A sẽ không bao giờ được chuyển hướng đến lệnh gọi trong B.

Từ khóa finalsẽ vô hiệu hóa phương thức bị ẩn. Vì vậy, chúng không thể bị ẩn và cố gắng làm như vậy sẽ dẫn đến lỗi trình biên dịch.

Hi vọng điêu nay co ich.


30
Để có thể kết thúc câu trả lời của bạn, tôi tin rằng đó là đúng, vấn đề ở đây về cơ bản là một thông báo lỗi trình biên dịch không hợp lệ: nó phải nói rằng B không thể ẩn ts () trong A. Khai báo một phương thức tĩnh cuối cùng là tuyên bố nó không thể ẩn.
Sean Owen

2
@Sean Owen: Tôi cũng nghĩ vậy. Thuật ngữ 'hide' thậm chí còn được sử dụng trong Đặc tả Java, vậy tại sao không sử dụng nó trong thông báo trình biên dịch.
NawaMan

2
Tại sao đây thậm chí là một tính năng? Nó sẽ hữu ích trong bối cảnh nào?
user253751

public class Test {final static public void main (String ... srik) {System.out.println ("Trong phương thức main"); ts (); } public static void ts () {Con c = new Con (); c.ts (); System.out.println ("Kiểm tra ts"); }} public class Con mở rộng Test {public static void ts () {System.out.println ("Con ts"); }} Xin chào Bạn có thể giải thích cho tôi điều gì sẽ xảy ra trong trường hợp này không
srikanth r

@SeanOwen Tôi cũng không nghĩ điều này đúng, trình biên dịch nên nói rằng vì A#tsđang được kế thừa và một phương thức như vậy đã tồn tại trong đó B, chỉ cần có hai phương thức có cùng chữ ký và một công cụ sửa đổi khác ( final) sẽ không hoạt động như quá tải .. . tôi ước gì tôi có thể nghĩ đến một thông điệp đơn giản cho điều này, mặc dù
Eugene

13

các phương thức tĩnh không thể được ghi đè

Điều này là không đúng sự thật. Mã ví dụ thực sự có nghĩa là phương thức ts trong B ẩn phương thức ts trong A. Vì vậy, nó không chính xác ghi đè. Trên Javaranch có một lời giải thích hay.


4
Nó đúng chỉ là không chính xác. các phương thức tĩnh không thể bị ghi đè nhưng có thể bị ẩn nếu bạn đang gọi chúng trên một tham chiếu cá thể thay vì tên lớp.
John Mercier

1
Thật không may, liên kết của bạn không hoạt động nữa. Có thể sửa lỗi này không?
Mathias Bader

Các liên kết JavaRanch không hoạt động, nhưng Googling từ khóa bật lên liên kết này trên mã trang trại
Sundeep

Tôi đã chỉnh sửa bài viết bằng cách thay thế liên kết chết bằng liên kết được đăng bởi Sundeep.
MC Emperor

10

Các phương thức tĩnh thuộc về lớp, không thuộc về cá thể.

A.ts()B.ts()sẽ luôn là những phương pháp riêng biệt.

Vấn đề thực sự là Java cho phép bạn gọi các phương thức tĩnh trên một đối tượng cá thể. Các phương thức tĩnh có cùng chữ ký từ lớp cha được ẩn khi được gọi từ một thể hiện của lớp con. Tuy nhiên, bạn không thể ghi đè / ẩn các phương thức cuối cùng .

Bạn sẽ nghĩ rằng thông báo lỗi sẽ sử dụng từ ẩn thay vì ghi đè ...


6

Bạn có thể nghĩ đến việc tạo một phương thức tĩnh cuối cùng, hãy xem xét những điều sau:

Có các lớp sau:

class A {
    static void ts() {
        System.out.print("A");
    }
}
class B extends A {
    static void ts() {
        System.out.print("B");
    }
}

Bây giờ cách 'chính xác' để gọi các phương thức này sẽ là

A.ts();
B.ts();

điều này sẽ dẫn đến ABnhưng bạn cũng có thể gọi các phương thức trên các trường hợp:

A a = new A();
a.ts();
B b = new B();
b.ts();

mà cũng sẽ dẫn đến AB.

Bây giờ hãy xem xét những điều sau:

A a = new B();
a.ts();

mà sẽ in A. Điều đó có thể làm bạn ngạc nhiên vì bạn đang thực sự có một đối tượng của lớp B. Nhưng vì bạn đang gọi nó từ một loại tham chiếu A, nó sẽ gọi A.ts(). Bạn có thể in Bbằng mã sau:

A a = new B();
((B)a).ts();

Trong cả hai trường hợp, đối tượng bạn có thực sự là từ lớp B. Nhưng tùy thuộc vào con trỏ trỏ đến đối tượng, bạn sẽ gọi phương thức from Ahoặc from B.

Bây giờ giả sử bạn là người phát triển lớp Avà bạn muốn cho phép phân lớp con. Nhưng bạn thực sự muốn phương thức ts(), bất cứ khi nào được gọi, ngay cả từ một lớp con, nó sẽ thực hiện những gì bạn muốn nó làm và không bị ẩn bởi một phiên bản lớp con. Sau đó, bạn có thể tạo nó finalvà ngăn nó bị ẩn trong lớp con. Và bạn có thể chắc chắn rằng đoạn mã sau sẽ gọi phương thức từ lớp của bạn A:

B b = new B();
b.ts();

Ok, thừa nhận rằng nó được xây dựng bằng cách nào đó, nhưng nó có thể có ý nghĩa đối với một số trường hợp.

Bạn không nên gọi các phương thức tĩnh trên các cá thể mà trực tiếp trên các lớp - thì bạn sẽ không gặp vấn đề đó. Ngoài ra, IntelliJ IDEA chẳng hạn sẽ hiển thị cho bạn một cảnh báo, nếu bạn gọi một phương thức tĩnh trên một phiên bản và cũng như nếu bạn thực hiện một phương thức tĩnh cuối cùng.


0

Phương thức ts () trong B không ghi đè phương thức ts () trong A, nó chỉ đơn giản là một phương thức khác. Lớp B không nhìn thấy phương thức ts () trong A vì nó là static, do đó nó có thể khai báo phương thức riêng của nó được gọi là ts ().

Tuy nhiên, nếu phương thức là cuối cùng, thì trình biên dịch sẽ nhận ra rằng có một phương thức ts () trong A không được ghi đè trong B.


Tôi không nghĩ điều này giải thích tại sao 'cuối cùng' đột nhiên có nghĩa là những phương pháp này không thể cùng tồn tại. Như bạn nói, không có 'cuối cùng', không có vấn đề. Bạn nói rằng nó không ghi đè, nhưng sau đó nói rằng vấn đề là B không thể ghi đè phương thức của A.
Sean Owen

Chắc chắn rồi, tôi nói rằng B không nhìn thấy phương thức ts () trong A (nó là 'ẩn'), nhưng công cụ sửa đổi cuối cùng không 'ẩn' các phương thức khỏi các lớp mở rộng khác. Nhưng eh, ok.
amischiefr

0

Tôi nghĩ rằng lỗi biên dịch khá sai lệch ở đây. Nó không nên nói "overridden method is static final.", Nhưng thay vào đó nó nên nói "overridden method is final.". Công cụ sửa đổi tĩnh không liên quan ở đây.


1
Vì vậy, bạn xem xét phương thức tĩnh trong B ghi đè phương thức trong A?
Koray Tugay

@KorayTugay Tôi chỉ tự hỏi nếu trình biên dịch ngoại hình đầu tiên tại có khả năng phương pháp overridable (bỏ qua của tĩnh trong chốc lát), thấy cuối cùng tại thất bại. Tuy nhiên, chỉ là một phỏng đoán hoang dã
Eugene

Balus Tôi nghĩ đây là câu trả lời chất lượng thấp duy nhất mà bạn có trong StackOverflow. Xem xét tất cả các câu trả lời đặc biệt của bạn, câu trả lời này không thuộc về họ. @BalusC
Koray Tugay

@KorayTugay: lúc đó mình chưa đủ uy tín để bình luận :) Nếu bạn ping lại, mình sẽ xóa câu trả lời, không vấn đề gì.
BalusC

0

Một phương thức tĩnh không thể bị ghi đè trong Java, không giống như các phương thức không tĩnh. Nhưng chúng được kế thừa giống như các thành viên dữ liệu tĩnh và không tĩnh. Đó là lý do tại sao không thể tạo một phương thức không tĩnh có cùng tên trong lớp cha

class Writer { 
    public static void doo(){
        System.out.println("sth");
    } 
}
class Author extends Writer{ 
    public void doo(){
        System.out.println("ok"); // error overridden method is static
    }
}

Các finalĐảm bảo từ khóa đó phương pháp cơ thể cụ thể được chạy mỗi khi một cuộc gọi đến phương pháp này. Bây giờ nếu một phương thức tĩnh được tạo trong lớp con có cùng tên và một lệnh gọi đến phương thức được thực hiện, thì phương thức trong lớp con sẽ được thực thi, điều này sẽ không xảy ra nếu cuối cùng được đặt trước tên phương thức tĩnh trong lớp cha. . Do đó, từ khóa final hạn chế việc tạo phương thức có cùng tên trong lớp con.

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.