Is there any way other than using reflection to access the members of a anonymous inner class?
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);
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.
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
}
}
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.
If it implements an interface or extends an existing class, you can access the members defined in the interface or base class.
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).
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.
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.
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.
© 2022 - 2024 — McMap. All rights reserved.