匿名类作为泛型参数

7
我想创建一个类,该类可以从匿名类定义中获取对象并进行存储。我使用了一个通用类型的类来实现这一点。然后,我希望使用函数式接口定义一些操作,这些操作将获取此对象作为参数进行处理。 代码胜过言语。看看这个例子:
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"。但是我的第一种方法出了什么问题呢?我真的不明白这里的问题在哪里。


新对象(){ public String text = "某物"; } - Grigory Kislin
3个回答

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

1
在第二段代码中,
    new Test<>(new Object(){
        public String text = "Something";
    }, (o) -> {
        System.out.println(o.text);
    });

这段代码之所以编译通过,是因为构造函数调用中的Test类型参数被推断出来(由于使用了钻石操作符),并且被推断为第一个参数求值得到的匿名类类型,因此第二个参数的类型为operation<该匿名类类型>,可以正常工作。

在第一段代码中,表达式

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

无法编译。在这里,lambda的类型是根据变量t的类型推断出来的,它是Test<?>。因此,runOperation的参数必须是operation<某个未知类型>。在这里唯一可用的runOperation参数是null


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

编译器在这里用您的匿名类替换Test中的T,因为该类包含一个变量text,所以第二种情况有效。

好的,但为什么编译器在第一种情况下没有用我的匿名类替换 T? - ArcticLord
它确实有影响,但是您的匿名类的类型是“Object”,它没有名为“text”的属性,因此会出现编译错误。 - Ian McLaird

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接