匿名 class 作为通用参数

anonymous class as generic parameter


我想创建一个 class 来从匿名 class 定义中获取对象进行存储。我使用通用类型 class 来实现这一点。然后我想使用函数接口定义一些操作,将此对象作为参数使用。
代码胜于雄辩。所以看看这个:

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"。但是我的第一种方法有什么问题?我真的不明白这里的问题。

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

此处的编译器正在用您的匿名 class 替换 Test 中的 T,因为 class 包含一个变量 text 这就是第二种情况的原因作品。

问题是您的匿名 class 仍然必须符合(扩展或实现)某种类型,而您选择的类型 Object 没有您的 text 属性。为了引用某种属性,您需要一个实际的 class 或接口才能使用,因此编译器可以保证对象上可用的属性和方法。

这有效。

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

第二段代码中,

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

编译是因为构造函数调用的 Test 的类型参数被推断(因为使用了菱形运算符),并且它被推断为第一个参数计算结果的匿名类型(匿名 class 类型),因此第二个参数的类型是 operation<that anonymous class type>,这是有效的。

在第一段代码中,表达式

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

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