【问题标题】:anonymous class as generic parameter匿名类作为泛型参数
【发布时间】:2015-11-20 11:25:47
【问题描述】:


我想创建一个从匿名类定义中获取对象的类来存储。我使用了一个泛型类型的类来实现这一点。然后我想使用功能接口定义一些操作,这些接口将这个对象作为参数来使用。
代码比文字更能说明问题。所以看看这个:

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

这很完美,可以打印出“Something”。但是我的第一种方法有什么问题?我真的不明白这里的问题。

【问题讨论】:

  • new Object(){ public String text = "Something"; })

标签: java generics lambda anonymous-class


【解决方案1】:

问题是您的匿名类仍然必须符合(扩展或实现)某种类型,而您选择的类型是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);
        });
    }
}

【讨论】:

    【解决方案2】:

    在第二段代码中,

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

    编译是因为 Test 的构造函数调用的类型参数被推断(因为使用了菱形运算符),并且它被推断为第一个参数评估为的匿名类型(匿名类类型),因此第二个参数的类型是operation&lt;that anonymous class type&gt;,它有效。

    在第一段代码中,表达式

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

    不编译。这里,lambda 的类型是根据变量t 的类型推断出来的,即Test&lt;?&gt;。因此,runOperation 的参数必须是operation&lt;some unknown type&gt;runOperation 的唯一参数是 null

    【讨论】:

      【解决方案3】:
        Test<?> t = new Test<>(new Object(){
                  public String text = "Something";
              }, (o) -> {
                  System.out.println(o.text);
              });
      

      这里的编译器将Test 中的T 替换为您的匿名类,并且由于该类包含变量text,这就是第二种情况起作用的原因。

      【讨论】:

      • 好的,但是为什么编译器在第一种情况下不将 T 替换为我的匿名类?
      • 可以,但是你的匿名类的类型是Object,它没有名为text的属性,所以你会得到编译错误。
      猜你喜欢
      • 2013-02-19
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-01
      相关资源
      最近更新 更多