2011-08-12 20 views
5

Tôi có một lớp siêu với các nhà xây dựng lồng ghép với phương thức finalize(). Để bảo vệ chống lại các lớp con quên gọi super.finalize, tôi đã viết một trình bảo vệ finalizer (EJ Item 7) như vậy.Trình bảo vệ Java finalizer dường như không hoạt động?

public class Super { 

    public Super() {} 

    { 
     Object finalizerGuardian = new Object() { 
      @Override 
      protected void finalize() { 
       System.out.println("Finalizer guardian finalize"); 
       Super.this.finalize(); 
      } 
     }; 
    } 

    protected void finalize() { 
     System.out.println("Super finalize"); 
    } 

} 

Dưới đây là một lớp con mẫu -

public class Sub extends Super { 

    public Sub() {} 

    protected void finalize() { 
     System.out.println("Sub finalize"); 
    } 

    public static void main(String[] args) 
      throws InterruptedException { 
     if (1 == 1) { 
      Sub s1 = new Sub(); 
     } 
     Runtime.getRuntime().gc(); 
     Thread.sleep(10000); 
    } 
} 

Khi đối tượng s1 đi ra khỏi phạm vi, hoàn thiện finalizer giám hộ() được gọi, và tôi nhận được SYSO từ phương pháp hoàn thiện của lớp con, nhưng không bao giờ có được một từ cuối cùng của siêu.

Tôi đang bối rối. Tôi có hiểu lầm điều gì đó về cơ bản không?

Tuyên bố từ chối: Tôi nhận thấy các trình kết thúc là nguy hiểm và không được khuyến khích, v.v. Vẫn đang cố gắng tìm hiểu vấn đề ở đây.

Trả lời

8

Effective Java của finalizer người giám hộ nên thực hiện việc quyết toán logic cần thiết riêng của mình (ví dụ, hãy gọi một số phương pháp Super mà thực hiện việc quyết toán thực tế) chứ không phải là gọi phương thức finalize(), bởi vì trong trường hợp của bạn Super.this.finalize(); thực sự gọi là phương pháp overriden từ lớp con .

Cũng lưu ý rằng finalizer người giám hộ phải là một lĩnh vực của lớp:

public class Super { 
    private final Object finalizerGuardian = new Object() { 
      @Override 
      protected void finalize() { 
       Super.this.doFinalize(); 
      } 
    }; 

    private void doFinalize() { 
     System.out.println("Super finalize"); 
    } 
} 
+0

Quá bắt kịp trong "nó không hoạt động" để xem vấn đề rõ ràng. Cảm ơn!! – Kal

2

Bạn đang quá tải phương pháp Super.finalize() trong Sub. Đó là lý do tại sao nó không được gọi.

Vì vậy, khi bạn ở "finalizerGuardian", hãy gọi Super.this.finalize(); bạn đang thực sự gọi Sub.finalize().

2

Vì những người khác đã cho biết công văn động là vấn đề của bạn ở đây. NHƯNG có một lỗi lớn khác trong mã của bạn như tôi thấy: finalizerGuardian của bạn chỉ được xác định bên trong khối khởi tạo, điều này có nghĩa là ngay sau khi đối tượng được khởi tạo, đối tượng nằm ngoài phạm vi và có thể được GC.

Tức là ngay cả khi bạn khắc phục vấn đề đầu tiên của mình (bằng cách xác định phương thức cuối cùng trong lớp của bạn để xử lý công cụ hoàn thành), bạn vẫn sẽ cần lưu finalizerGuardian trong một biến mẫu.

2

Super.finalize() không được gọi vì Sub ghi đè lên. Hãy thử thêm phương thức Super._finalize() và gọi điện từ số Super.finalize() và người giám hộ cuối cùng.

Ngoài ra, tôi nghĩ rằng finalizerGuardian cần phải là trường của Super. Nếu không, nó có thể lấy rác được thu thập ngay cả khi đối tượng Super vẫn có thể truy cập mạnh.