Anonymous class as a general parameter


I want to create a class that gets an object from the definition of an anonymous class for storage. For this, I used a common typed class. Then I want to define some operations using functional interfaces that receive this object as a parameter to work with.
The code speaks more than words. So look at this:

public class Test<T> { @FunctionalInterface public interface operation<T> { void execute(T object); } private T obj; public Test(T _obj){ obj = _obj; } public void runOperation(operation<T> op){ op.execute(obj); } public static void main(String[] args){ Test<?> t = new Test<>(new Object(){ public String text = "Something"; }); t.runOperation((o) -> { System.out.println(o.text); // text cannot be resolved }); } } 

My problem is that o.text in the functional interface implementation cannot be resolved. Is this some kind of erasure?
The interesting thing is that I can make this code work when I implement the functional interface in the constructor.
Take a look at this code:

 public class Test<T> { @FunctionalInterface public interface operation<T> { void execute(T object); } private T obj; private operation<T> op; public Test(T _obj, operation<T> _op){ obj = _obj; op = _op; } public void runOperation(){ op.execute(obj); } public static void main(String[] args){ Test<?> t = new Test<>(new Object(){ public String text = "Something"; }, (o) -> { System.out.println(o.text); }); t.runOperation(); } } 

This works fine and prints "Something." But what is wrong with my first approach? I really don't understand the problem.

+6
source share
3 answers

In the second code snippet

  new Test<>(new Object(){ public String text = "Something"; }, (o) -> { System.out.println(o.text); }); 

it compiles because an argument of type Test to call the constructor is output (since the diamond operator is used), and it is inferred to an anonymous type, which evaluates the first argument (the type of the anonymous class) and, therefore, the second type of the argument - operation<that anonymous class type> , which is working.

In the first code snippet, the expression

  t.runOperation((o) -> { System.out.println(o.text); // text cannot be resolved }) 

not compiled. Here, the lambda type is inferred based on the type of the variable t , which is Test<?> . Thus, the runOperation argument must be operation<some unknown type> . The only runOperation argument that will work here is null .

+1
source

The problem is that your anonymous class still needs to match (extend or implement) some type, and the Object type you Object , which does not have your text property. To reference any properties, you need an actual class or interface to work with, so the compiler can provide guarantees about which properties and methods are available for the object.

It works.

 public class Test<T> { public static class Data { public String text; } @FunctionalInterface public interface Operation<K> { void execute(K object); } private T obj; private Operation<T> op; public Test(T obj) { this.obj = obj; } public void runOperation(Operation<T> op) { op.execute(obj); } public static void main(String[] args) { Test<Data> t = new Test<>(new Data() {{ this.text = "Something"; }}); t.runOperation((o) -> { System.out.println(o.text); }); } } 
+2
source
  Test<?> t = new Test<>(new Object(){ public String text = "Something"; }, (o) -> { System.out.println(o.text); }); 

The compiler here replaces T in Test with your anonymous class, and since this class contains the variable text , why does the second case work.

+1
source

All Articles