Accessing inner anonymous class members
Asked Answered
O

9

8

Is there any way other than using reflection to access the members of a anonymous inner class?

Orleans answered 26/11, 2008 at 4:47 Comment(2)
may i ask Why would you want to do that? Some context.. Not sure if its a good idea even if its possible.Constitutionalism
I dont have any specific usecase. Just wanted to know if there is any mechanism other than reflection to query/access object membersOrleans
E
10

Anonymous inner classes have a type but no name.

You can access fields not defined by the named supertype. However once assigned to a named type variable, the interface is lost.

Obviously, you can access the fields from within the inner class itself. One way of adding code is through an instance initialiser:

final AtomicInteger y = new AtomicInteger();
new Runnable() {
    int x;
    {
        x = 5;
        doRun(this);
        y.set(x);
    }
    public void run() {
        ... blah ...
    }
};

The value returned by the anonymous inner class expression has the anonymous type, so you have one chance to use it outside of the class itself:

final int y = new Runnable() {
    int x;
    {
        x = 5;
        doRun(this);
    }
    public void run() {
        ... blah ...
    }
}.x;

You can also pass it through a method declared similar to:

<T extends Runnable> T doRun(T runnable);
Expugnable answered 26/11, 2008 at 11:44 Comment(0)
E
9

You can use local classes instead anonymous class. Look:

public class Test {
    public static void main(String... args) {
        class MyInner {
            private int value = 10;
        }

        MyInner inner = new MyInner();
        System.out.println(inner.value);
    }
}

You can have reference of MyInner type only in the method body though. So outside of the method you will not be able to use its fields/methods that are not declared in its super class (java.lang.Object in this case) or interface.

Evasive answered 26/11, 2008 at 7:8 Comment(3)
Wow... never seen those before. Bizarre. Can't say I like it a lot, but it's interesting nonetheless :)Jacquenette
They are called local classes.Expugnable
If I'm not wrong, the class that you have shown is just another class with limited visibility.. right? I meant the question to know possible access to members of an anonymous class object.Orleans
V
1

public class AccessAnonymous {
    private Runnable runnable; // to have instance of the class

    public static void main(String[] args) throws Exception {
        AccessAnonymous a = new AccessAnonymous();
        a.a(); // init field

        Class clazz = a.runnable.getClass();
        Field field = clazz.getDeclaredField("i");
        field.setAccessible(true);

        int int1 = field.getInt(a.runnable);
        System.out.println("int1=" + int1);
    }

    public void a() {
        runnable = new Runnable() {
            private int i = 1;

            public void run() {
                i = 90;
            }

        };
        runnable.run();// change value
    }
}
Vegetable answered 26/11, 2008 at 9:4 Comment(0)
A
1

In the case of anonymous classes, there is also a tradeoff between the clutter caused by the class and the convenience of having it anonymous. Complicated classes rarely belong as anonymous but rather as named private inner.

In most anonymous classes, we only need to "feed" knowledge and can do it at construction. In a few anonymous classes (e.g., return value vehicles) we also care about one return value.

As we know, data members should not directly be accessed but rather with a getter setter. This, if you find yourself in a situation that you have added lots of getters and setters, you are probably doing something wrong anyway and shouldn't be using an anonymous class.

Aurie answered 27/11, 2008 at 3:51 Comment(0)
P
0

If it implements an interface or extends an existing class, you can access the members defined in the interface or base class.

Practise answered 26/11, 2008 at 6:8 Comment(0)
C
0

Mr Fooz is right, except that interfaces can only define constant members. the best way would be to add getter/setter methods to your interface and then use those to get your value. but then for each anonymous class you would have to define those methods (kind of a pain).

Claycomb answered 26/11, 2008 at 6:12 Comment(1)
Method are members of their types just as fields are.Edlun
F
0

If you want readable, maintainable code, don't use anonymous classes. If you use anonymous classes and want readable, maintainable code, don't use anonymous classes when you need to access the element in that inner class. There are ways of doing so, but I beg of you to not use any of those hacks. Readability trumps all other virtues.

Finisterre answered 27/11, 2008 at 1:0 Comment(0)
P
0

This question is 15 years old, but I think there is another way to do this!

The example concerns writing a unit test for MyService:

public class MyService {

    public Result doSomething() {
        Result result = new Result();
        result.setToday(today();
        return result;
    }

    // not private but package-private so it can be overridden
    Date today() {
        return new Date();
    }
}

Here is the unit test:

public class MyServiceTest {

    private Date capturedToday;

    // anonymous inner class
    private final MyService testSubject = new MyService() {

        @Override
        Date today() {
            // capture the Date instance created by MyService
            Date today = super.today();
            MyServiceTest.this.capturedToday = today;
            return today;
        }
    };

    @Test
    void myTest() {

        MyResult result = testSubject.doSomething();            
        assertSame(capturedToday, result.getToday());

In this example MyService creates a Date internally and sets it on its result. To check this logic I created an anonymous inner class which captures the instance when it is created and stores it in the capturedToday field:

MyServiceTest.this.capturedToday = today;

This syntax allows an inner class to access fields of its outer class and thus to expose its values.

Pricefixing answered 26/9, 2023 at 11:47 Comment(0)
S
0

You can access the members of an anonymous class from inside the block (or sub-block) it was declared in, if using var. Example:

public static void main(String[] args) {
    var annon = new Object() {
        int field;
        void method() {
            System.out.println("method called with field=" + field);
        }
    };

    annon.field = 123;
    annon.method();  // prints "method called with field=123"
}

This even works if the members were declared static.

If we had declared Object annon = new Object() { ... we would get compilation errors since Object does not have any field or method() members.

Surrebutter answered 26/9, 2023 at 14:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.