2015-11-20 2 views
6


Я хочу создать класс, который получает объект из определения анонимного класса для хранения. Для этого я использовал общий типизированный класс. Затем я хочу определить некоторые операции, используя функциональные интерфейсы, которые получают этот объект в качестве параметра для работы.
Код говорит больше, чем слова. Так что посмотрите на это:анонимный класс как общий параметр

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 
     }); 
    } 
} 

Моя проблема заключается в том, что o.text в реализации функционального интерфейса не может быть решена. Это какой-то тип стирания?
Интересно, что я могу заставить этот код работать, когда я реализую функциональный интерфейс в конструкторе.
Посмотрите на этот код:

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(); 
    } 
} 

Это отлично работает и печатает «нечто». Но что не так с моим первым подходом? У меня действительно не проблема.

+0

новый объект() { public String text = "Something"; }) – GKislin

ответ

1

Во второй части кода,

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

компилирует, поскольку тип аргумента Test для вызова конструктора выводится (так как используется оператор алмаза), и выводится на анонимный тип, который первый аргумент оценивает (тип анонимного класса), и, следовательно, тип второго аргумента - operation<that anonymous class type>, который работает.

В первой части кода, выражение

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

не компилируется. Здесь тип лямбда выведен на основании типа переменной t, которая равна Test<?>. Таким образом, аргумент runOperation должен быть operation<some unknown type>. Единственный аргумент runOperation, который будет работать здесь, - null.

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

Компилятор здесь заменяет T в Test с анонимного класса и так как этот класс содержит переменную text именно поэтому второй случай работает.

+0

Хорошо, но почему компилятор не заменит T моим анонимным классом в первом случае? – ArcticLord

+0

Это так, но тип вашего анонимного класса - это 'Object', который не имеет свойства с именем' text', поэтому вы получаете ошибку компиляции. –

2

Проблема заключается в том, что ваш анонимный класс по-прежнему должен соответствовать (расширять или осуществлять) какой-либо тип, а выбранный вами тип - Object, который не имеет вашего text. Чтобы ссылаться на какие-либо свойства, вам понадобится фактический класс или интерфейс для работы, поэтому компилятор может предоставить гарантии о том, какие свойства и методы доступны на объекте.

Это работает.

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); 
     }); 
    } 
} 
Смежные вопросы