Java 通用功能接口和类型擦除

Java 通用功能接口和类型擦除,java,generics,lambda,java-8,Java,Generics,Lambda,Java 8,以下编译错误是什么意思 类型FooSetter中的方法apply(Sample.Foo,capture#5-of?)不适用于参数(Sample.Foo, 捕获#6-of? 它出现在下面的代码中(在我用注释指出的底部),该代码尝试将一个bean的setter映射到另一个bean的getter,而无需强制转换(是的,我知道有一些实用程序可以做到这一点,但这是一个示例)。我使用以下两个功能接口 @FunctionalInterface public interface FooSetter<V&g

以下编译错误是什么意思

类型FooSetter中的方法apply(Sample.Foo,capture#5-of?)不适用于参数(Sample.Foo, 捕获#6-of?

它出现在下面的代码中(在我用注释指出的底部),该代码尝试将一个bean的setter映射到另一个bean的getter,而无需强制转换(是的,我知道有一些实用程序可以做到这一点,但这是一个示例)。我使用以下两个功能接口

@FunctionalInterface
public interface FooSetter<V> {
    void apply(Foo foo, V value);
} 
@functioninterface
公共接口FooSetter{
无效应用(Foo-Foo,V值);
} 

@functioninterface
公共接口讨价还价器{
不适用(禁止使用);
}

public class Sample {

public static class Bar{
    public String description;
    public Integer num;

    public String getDecription(){
        return description;
    }
    public void setDescription(String desc){
        this.description = desc;
    }
    public Integer getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
}

public static class Foo{

    private String name;
    private Integer age;

    public Foo setName(String name){
        this.name = name;
        return this;
    }

    public Foo setAge(int age){
        this.age = age;
        return this;
    }

    @Override
    public String toString(){
        return "Name" + name + "  Age " + age;
    }
}

public static void main(String[] args) throws Exception  {

    HashMap<String, BarGetter<?>> barGetters= Maps.newHashMap();
    barGetters.put("description", (BarGetter<String>)(Bar b) -> b.getDecription());
    barGetters.put("num", (BarGetter<Integer>)(Bar b) -> b.getNum());

    HashMap<String, FooSetter<?>> fooSetters= Maps.newHashMap();
    fooSetters.put("name",   (Foo f, String name) -> f.setName(name));
    fooSetters.put("age",   (Foo f, Integer age) -> f.setAge(age));

    HashMap<String,String> fooFromBar = Maps.newHashMap();
                 // FOO      BAR
    fooFromBar.put("name", "description");
    fooFromBar.put("age", "num");

    Bar bar  = new Bar();
    bar.setDescription("bar desc");
    bar.setNum(5);

    Foo newFoo = new Foo();
    for (String key : fooFromBar.keySet()) {
       //COMPILATION ERROR  
       fooSetters.get(key).apply(newFoo, barGetters.get( fooFromBar.get(key) ).apply(bar) );
    }
 }
}
公共类示例{
公共静态类栏{
公共字符串描述;
公共整数num;
公共字符串getDecription(){
返回说明;
}
公共void setDescription(字符串描述){
this.description=desc;
}
公共整数getNum(){
返回num;
}
公共void setNum(int num){
this.num=num;
}
}
公共静态类Foo{
私有字符串名称;
私人整数年龄;
public Foo setName(字符串名称){
this.name=名称;
归还这个;
}
公共食品设置(国际年龄){
这个。年龄=年龄;
归还这个;
}
@凌驾
公共字符串toString(){
返回“姓名”+姓名+“年龄”+年龄;
}
}
公共静态void main(字符串[]args)引发异常{
HashMap>fooSetters=Maps.newHashMap();
put(“name”,(Foo f,String name)->f.setName(name));
fooSetters.put(“年龄”,(Foo f,整数年龄)->f.setAge(年龄));
HashMap fooFromBar=Maps.newHashMap();
//富吧
fooFromBar.put(“名称”、“说明”);
fooFromBar.put(“年龄”、“数量”);
条形=新条形();
条形图说明(“条形图说明”);
bar.setNum(5);
Foo newFoo=新Foo();
for(字符串键:fooFromBar.keySet()){
//编译错误
fooSetters.get(key).apply(newFoo,barGetters.get(fooFromBar.get(key)).apply(bar));
}
}
}
关于类型擦除,这里有什么我没有看到的吗?

这个

fooSetters.get(key)
返回类型为
FooSetter
的值,即不知道所设置类型的
FooSetter
。因此,其
apply
方法具有以下(推断)定义

void apply(Foo foo, ? value);
您不能将此方法用于任何对象(对于其第二个参数),但
null
(可用于任何引用类型),因为您不知道它是什么类型

这个

返回一个类型为
BarGetter
的值,即不知道得到什么的
BarGetter
。因此,其
apply
方法显示为

? apply(Bar from);
可能与
fooSetter.apply所期望的完全不同

因此,类型系统不能允许它,并给您一个编译错误。

fooSetters.get(key)
返回类型为
FooSetter
的值,即不知道所设置类型的
FooSetter
。因此,其
apply
方法具有以下(推断)定义

void apply(Foo foo, ? value);
您不能将此方法用于任何对象(对于其第二个参数),但
null
(可用于任何引用类型),因为您不知道它是什么类型

这个

返回一个类型为
BarGetter
的值,即不知道得到什么的
BarGetter
。因此,其
apply
方法显示为

? apply(Bar from);
可能与
fooSetter.apply所期望的完全不同

因此,类型系统不能允许它,并给您一个编译错误。

fooSetters.get(key)
返回类型为
FooSetter
的值,即不知道所设置类型的
FooSetter
。因此,其
apply
方法具有以下(推断)定义

void apply(Foo foo, ? value);
您不能将此方法用于任何对象(对于其第二个参数),但
null
(可用于任何引用类型),因为您不知道它是什么类型

这个

返回一个类型为
BarGetter
的值,即不知道得到什么的
BarGetter
。因此,其
apply
方法显示为

? apply(Bar from);
可能与
fooSetter.apply所期望的完全不同

因此,类型系统不能允许它,并给您一个编译错误。

fooSetters.get(key)
返回类型为
FooSetter
的值,即不知道所设置类型的
FooSetter
。因此,其
apply
方法具有以下(推断)定义

void apply(Foo foo, ? value);
您不能将此方法用于任何对象(对于其第二个参数),但
null
(可用于任何引用类型),因为您不知道它是什么类型

这个

返回一个类型为
BarGetter
的值,即不知道得到什么的
BarGetter
。因此,其
apply
方法显示为

? apply(Bar from);
可能与
fooSetter.apply所期望的完全不同


因此,类型系统不能允许它,并给您一个编译错误。

如果您有一个不同类型的泛型元素集合,您需要一个helper
,它包装实际元素,并用运行时检查来保护它的访问,该检查将替换在这种情况下不起作用的编译时检查

例如


但不会造成堆污染,而是抛出一个带有消息“
无法将FooSetterHolder强制转换为FooSetterHolder
”的
ClassCastException,这与普通的非泛型类型强制转换非常相似。

如果您有一个不同类型的泛型元素集合,您需要一个帮助器
,用于包装actu