2009-11-29 37 views
177

Tôi có mã sau đây. Tôi muốn giữ đối tượng lớp ngoài bằng cách sử dụng mà tôi đã tạo đối tượng lớp bên trong inner. Tôi làm nó như thế nào?Nhận giữ đối tượng lớp ngoài từ đối tượng lớp bên trong

public class OuterClass { 

    public class InnerClass { 
     private String name = "Peakit"; 
    } 

    public static void main(String[] args) { 
     OuterClass outer = new OuterClass(); 
     InnerClass inner = outer.new InnerClass(); 
     // How to get the same outer object which created the inner object back? 
     OuterClass anotherOuter = ?? ; 

     if(anotherOuter == outer) { 
      System.out.println("Was able to reach out to the outer object via inner !!"); 
     } else { 
      System.out.println("No luck :-("); 
     } 
    } 
} 

EDIT: Vâng, một số bạn guys đề nghị thay đổi những lớp bên trong bằng cách bổ sung một phương pháp:

public OuterClass outer() { 
    return OuterClass.this; 
} 

Nhưng nếu tôi không có quyền kiểm soát để sửa đổi các lớp bên trong, sau đó (chỉ để xác nhận) chúng ta có một số cách khác để nhận đối tượng lớp ngoài tương ứng từ đối tượng lớp bên trong không?

Trả lời

250

Trong chính lớp bên trong, bạn có thể sử dụng OuterClass.this. Biểu thức này, cho phép tham chiếu đến bất kỳ thể hiện kèm theo từ điển nào, được mô tả trong JLS là Qualified this.

Tôi không nghĩ rằng có cách để lấy ví dụ từ bên ngoài mã của lớp bên trong. Tất nhiên, bạn luôn có thể giới thiệu tài sản riêng của bạn:

public OuterClass getOuter() { 
    return OuterClass.this; 
} 

EDIT: Bằng thực nghiệm, có vẻ như lĩnh vực giữ tham chiếu đến các lớp bên ngoài đã truy cập ở mức gói - ít nhất là với JDK Tôi đang sử dụng.

EDIT: Tên sử dụng (this$0) thực hợp lệ trong Java, mặc dù JLS không khuyến khích việc sử dụng nó:

Nhân vật $ nên được sử dụng chỉ trong mã nguồn một cách máy móc được tạo ra hoặc, hiếm , để truy cập các tên có sẵn trên các hệ thống cũ.

+0

Cảm ơn Jon! Nhưng nếu tôi không có quyền kiểm soát để sửa đổi lớp bên trong (kiểm tra chỉnh sửa của tôi). – peakit

+5

@peakit: Sau đó, theo như tôi biết, bạn đã hết may mắn trừ khi bạn sử dụng sự phản chiếu. Nó cảm thấy như nó là một vi phạm đóng gói mặc dù thực sự - nếu lớp bên trong không muốn nói cho bạn biết ví dụ bên ngoài của nó là gì, bạn nên tôn trọng điều đó và cố gắng thiết kế sao cho bạn không cần nó. –

+0

Điều này vẫn còn hợp lệ trong Java 8? – misty

24

OuterClass.this tham chiếu đến lớp bên ngoài.

+4

Nhưng chỉ trong/bên trong nguồn của OuterClass. Và tôi không nghĩ đó là những gì OP muốn. –

0

Tôi nghĩ điều này có thể lạm dụng việc sử dụng lớp bên trong. Dường như với tôi rằng những gì bạn muốn làm là vi phạm các khái niệm cơ bản của lập trình hướng đối tượng. Nếu bạn muốn truy cập lớp bên ngoài từ lớp bên trong, sau đó bao gồm một tham chiếu đến lớp bên ngoài để bạn có quyền truy cập vào nó. Khi bạn phải làm những điều phức tạp như thế này thường là một dấu hiệu cho thấy bạn nên xem xét lại các lựa chọn thiết kế của mình.

17

Bạn có thể (nhưng bạn không nên) sử dụng phản ánh cho công việc:

import java.lang.reflect.Field; 

public class Outer { 
    public class Inner { 
    } 

    public static void main(String[] args) throws Exception { 

     // Create the inner instance 
     Inner inner = new Outer().new Inner(); 

     // Get the implicit reference from the inner to the outer instance 
     // ... make it accessible, as it has default visibility 
     Field field = Inner.class.getDeclaredField("this$0"); 
     field.setAccessible(true); 

     // Dereference and cast it 
     Outer outer = (Outer) field.get(inner); 
     System.out.println(outer); 
    } 
} 

Tất nhiên, tên của các tài liệu tham khảo ngầm là hoàn toàn không đáng tin cậy, vì vậy như tôi đã nói, bạn không nên: -)

0

Dưới đây là ví dụ:

// Test 
public void foo() { 
    C c = new C(); 
    A s; 
    s = ((A.B)c).get(); 
    System.out.println(s.getR()); 
} 

// classes 
class C {} 

class A { 
    public class B extends C{ 
    A get() {return A.this;} 
    } 
    public String getR() { 
    return "This is string"; 
    } 
} 
0

tôi chỉ làm nó như thế này:

public class CherryTree { 
    public class Cherry { 
     public final CherryTree cherryTree = CherryTree.this; 
     // [...] 
    } 
    // [...] 
} 

Tất nhiên bạn cần có khả năng sửa đổi lớp bên trong và mọi người nhận đối tượng lớp bên trong đều có quyền truy cập vào đối tượng lớp ngoài bây giờ. Trong trường hợp của tôi nó chỉ là tốt.

0

Câu trả lời chung chung hơn cho câu hỏi này bao gồm các biến được tô bóng và cách chúng được truy cập.

Trong ví dụ sau (từ Oracle), biến x trong main() được shadowing Test.x:

class Test { 
    static int x = 1; 
    public static void main(String[] args) { 
     InnerClass innerClassInstance = new InnerClass() 
     { 
      public void printX() 
      { 
       System.out.print("x=" + x); 
       System.out.println(", Test.this.x=" + Test.this.x); 
      } 
     } 
     innerClassInstance.printX(); 
    } 

    public abstract static class InnerClass 
    { 
     int x = 0; 

     public InnerClass() { } 

     public abstract void printX(); 
    } 
} 

Chạy chương trình này sẽ in:

x=0, Test.this.x=1 

Thêm tại: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

0

nếu bạn không có quyền kiểm soát để sửa đổi lớp bên trong, việc sửa chữa có thể giúp bạn (nhưng không khuyến nghị). $ 0 này là tham chiếu trong lớp Inner cho biết instance nào của lớp Outer được sử dụng để tạo cá thể hiện tại của lớp Inner.

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