Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access anonymous inner class variables

How to access i from the outer class?

  HashSet<Integer> hs=new HashSet<Integer>(){
        int i=30;
    };

I can do it like this

int k=new HashSet<Integer>(){
    int i=30;
}.i;

But if I get 'i' then I cannot get the instance of hashset.Is there a way to get both?The question just out of curiosity.It doesn't have much practical applications.I just want to know whether it can be done.

like image 650
Emil Avatar asked Aug 18 '10 07:08

Emil


1 Answers

Solution 1: Object registration system

The two snippets presented essentially made a choice between storing the reference to the anonymous class instance just created, or to immediately access its custom field. Doing one would seem to forfeit the ability to do the other.

One way to achieve a compromise is to have an object registration system, and use an instance initializer (JLS 8.6) in your anonymous class to self-register to this sytem.

Here's a simple proof-of-concept, using Object[] for a simple registration system:

    final Object[] registrar = { null };
    int k = new HashSet<Integer>(){
        { registrar[0] = this; }
        int i= 666;
    }.i;
    Set<Integer> set = (Set<Integer>) registrar[0];

    System.out.println(k); // 666
    System.out.println(set.getClass().isAnonymousClass()); // true

Essentially we use a 1-element Object[], and in the instance initializer of our anonymous class, we "register" this to this array. Note that this is just a proof-of-concept; in production code, you'd use a more robust and typesafe object registration system than this.


Solution 2: Tuples

This approach works nicely if your anonymous class may have multiple "fields". Simply pack them all into a tuple, making sure to include a reference to this in the anonymous class.

Here's a simple proof-of-concept, using Object[] for a tuple:

    Object[] tuple = new HashSet<Integer>(){
        Object[] tuple = { this, 666, 13, "XXX", "OMG ABUZE" };
    }.tuple;
    Set<Integer> set = (Set<Integer>) tuple[0];
    set.add(null);
    System.out.println(set.getClass().isAnonymousClass()); // true
    System.out.println(Arrays.toString(tuple));
    // [[null], 666, 13, XXX, OMG ABUZE]

In production code, you'd use a CustomTuple class that is more object-oriented and typesafe. Note that this is an analogous solution to the "how can my method return 2 values" problem: simply return 1 value that captures all of those information.

like image 75
polygenelubricants Avatar answered Sep 27 '22 00:09

polygenelubricants