2012-04-26 31 views
11

Tôi có thiết lập sau đây cho tôi một thông báo nói rằng "Constructor gọi phương thức có thể ghi đè". Tôi biết điều này đang xảy ra, nhưng câu hỏi của tôi là cách khắc phục nó để mã vẫn hoạt động và thông báo biến mất.Cách khắc phục "Phương thức gọi hàm lập phương thức có thể đọc được"

public interface Foo{ 
    void doFoo(); 
} 
public class FooImpl implements Foo{ 
@Override{ 
public void doFoo(){ 
    //.. Do important code 
} 
} 
public class Bar{ 
    private FooImpl fi; 
    public Bar(){ 
    fi = new FooImpl(); 
    fi.doFoo(); // The message complains about this line 
    } 
} 

Cảm ơn!

+0

Mã bạn đã hiển thị đang gọi phương thức ghi đè * sau * được gọi là hàm tạo, không phải * từ * hàm tạo, phải không? Hay tôi đang thiếu một cái gì đó? – NPE

+0

Hiển thị mã thực sự ức chế cảnh báo có thể là một ý tưởng tuyệt vời .. – Voo

+0

aix- Nó đang nâng cao thông điệp vì Bar đang gọi fi.doFoo() bên trong hàm tạo của Bar. Voo - Mã quá dài để sao chép/dán. Đây là một ví dụ được cắt tỉa về những gì đang diễn ra – user973479

Trả lời

6

Bạn có thể tuyên bố doFoo như cuối cùng nếu bạn không cần phải ghi đè phương thức sau:

public final void doFoo() { }

0

IDE của bạn được nói với bạn rằng, bởi vì nó có khả năng gây mất an toàn. Bạn có thể cung cấp bất kỳ implimentation hoặc doFoo và làm cho tất cả các đối tượng Bar để các công cụ khác nhau khi khởi động. Điều này có vẻ như một sự lựa chọn tồi của thiết kế trong hầu hết các trường hợp.

Dường như bạn đang sử dụng mẫu chiến lược, trong một hàm tạo. Không nên sử dụng chiến lược hay bất kỳ hành vi nào có thể vượt qua khác trong hàm tạo. Sử dụng nó một số nơi khác.

+0

Làm thế nào nó có khả năng không an toàn để gọi một phương thức không cuối cùng của một lớp hoàn toàn khác trong constructor? – Voo

+0

Câu trả lời của bạn cho bạn downvoting vì bạn không hiểu các hàm ý theo sau là hành vi overridable trong một constructor? Bài viết này giải thích về nguy cơ tiềm tàng của việc sử dụng phương thức gọi hàm overridale trong một hàm tạo: http://www.javapractices.com/topic/TopicAction.do?Id=215 – Terraego

+1

Nếu bạn thực sự đã đọc bài đăng của mình, bạn đã nhận thấy rằng câu hỏi là về việc gọi một phương thức ảo trên một đối tượng đã được xây dựng hoàn toàn. Các nhược điểm nổi tiếng khi gọi các phương thức ảo trên đối tượng được xây dựng cũng được biết đến, nhưng không áp dụng ở đây. – Voo

0

Nguồn của lỗi bạn thấy là PMD (tìm kiếm ở đó cho "overr") và khi xây dựng lại ví dụ của bạn, cảnh báo này không được kích hoạt bởi phiên bản PMD (4.2.6) này. Sonar chỉ tích hợp PMD, Checkstyle và các công cụ khác, và cung cấp một cái nhìn tổng quan. Vì vậy, kiểm tra phiên bản của Sonar (và PMD) bạn đang sử dụng.

Bạn có thể xem điều đó trong Sonar: Sonar > Quality Profiles > Search for "overr" phải làm nổi bật quy tắc bạn đang sử dụng.

Trong Sonar, bạn có thể kiểm tra phiên bản PMD bạn đang sử dụng. Truy cập Sonar > Configuration > Update Center và xem phiên bản PMD bạn đang sử dụng.

14

Như @Voo nói,

câu hỏi của bạn là về gọi một phương thức ảo trên một đối tượng đã hoàn toàn xây dựng. Các downfalls nổi tiếng gọi phương pháp ảo trên đối tượng xây dựng được nổi tiếng, nhưng không áp dụng ở đây

Từ Effective Java 2nd Edition, khoản 17: Thiết kế và tài liệu cho các thừa kế, nếu không cấm nó :

Có một vài hạn chế khác mà lớp học phải tuân thủ để cho phép thừa kế . Các nhà xây dựng không được gọi các phương pháp có thể ghi đè, trực tiếp hoặc gián tiếp. Nếu bạn vi phạm quy tắc này, lỗi chương trình sẽ kết quả là . Trình tạo lớp bậc trên chạy trước lớp con của lớp con , vì vậy phương thức ghi đè trong lớp con sẽ được gọi trước khi hàm tạo lớp con chạy. Nếu phương pháp ghi đè phụ thuộc vào bất kỳ khởi tạo nào được thực hiện bởi hàm tạo lớp con, phương thức sẽ không hoạt động như mong đợi.

Gọi phương thức có thể ghi đè trong khi xây dựng đối tượng có thể dẫn đến việc sử dụng dữ liệu chưa được khởi tạo, dẫn đến ngoại lệ thời gian chạy hoặc kết quả không lường trước được.

Constructors phải gọi chỉ phương pháp mà là cuối cùng hay tin

Bạn có thể sử dụng phương pháp nhà máy tĩnh để giải quyết vấn đề mà bạn phải tạo các đối tượng của bạn từ Bar class.

Effective Java, khoản 1: Xem xét các phương pháp nhà máy tĩnh thay vì nhà xây dựng

Cách bình thường đối với một lớp học để cho phép một khách hàng để có được một thể hiện của chính nó là để cung cấp một constructor công cộng. Có một kỹ thuật khác là nên là một phần của bộ công cụ của mỗi lập trình viên. Một lớp có thể cung cấp phương thức nhà máy tĩnh công khai, chỉ đơn giản là phương thức tĩnh trả về một thể hiện của lớp.

Vì vậy, bạn đi đến có giao diện:

public interface Foo { 
    void doFoo(); 
} 

và thực hiện:

public class FooImpl implements Foo { 
    @Override 
    public void doFoo() { 
    //.. Do important code 
    } 
} 

Để tạo lớp học của bạn với phương pháp nhà máy của bạn, bạn có thể làm việc bằng cách này:

  • Sử dụng giao diện để xác định biến lớp học của bạn private Foo fi thay vì private FooImpl fi, sử dụng giao diện trên các loại bê tông là chìa khóa để đóng gói tốt và cho khớp nối lỏng mã của bạn.

  • Đặt hàm tạo mặc định của bạn ở chế độ riêng tư để ngăn việc khởi tạo lớp học của bạn bên ngoài.

    Bar tin() {// Ngăn chặn instantiation }

  • Hủy bỏ tất cả các cuộc gọi đến ghi đè lên các phương pháp được hiện diện trong constructor của bạn.

  • Tạo phương thức tĩnh của bạn

Cuối cùng bạn sẽ có được một lớp Bar với một phương pháp nhà máy như:

public class Bar { 
    private Foo fi; 

    private Bar() {// Prevents instantiation 
     fi = new FooImpl(); 
    } 

    public static Bar createBar() { 
     Bar newBar = new Bar(); 
     newBar.fi.doFoo(); 

     return newBar; 
    } 
} 

My Boss nói: “những lời cảnh báo Sonar khoảng triệu chứng, không phải về bệnh . Tốt nhất là khi bạn có thể điều trị căn bệnh này. ”

Các vấn đề liên quan