假设我有两个班级
class A{
int a;
int getA(){
return this.a;
}
}
和
class B extends A{
String b;
String getB(){
return this.b;
}
}
我想有一个枚举,包含所有可能的值和继承树的getter(不要问,我只是想)。
enum ValueGetters{
A("a", A::getA),
B("b", B::getB);
String parameterName;
Function parameterGetter;
}
我在编写这个类的构造函数时遇到了问题。
ValueGetters(String parameterName, Function parameterGetter){
this.parameterName = parameterName;
this.parameterGetter = parameterGetter;
}
返回A和B(Error:(12, 14) java: incompatible types: invalid method reference
)的错误。
同样的情况适用于ValueGetters(String parameterName, Function<?,?> parameterGetter)
对于ValueGetters(String parameterName, Function<? extends A,?> parameterGetter)
,这仅为B提供错误,如果我尝试使用ValueGetters(String parameterName, Function<? extends B,?> parameterGetter)
重载构造函数,则会出现新错误,即两种类型都具有相同类型的擦除。
另一方面,ValueGetters(String parameterName, Object parameterGetter)
返回错误,指出Object
不是Function
。
我尝试定义自己的@FunctionalInterface
,但它给了我同样的错误,重载@FunctionalInterface
的方法以接受A
和B
显然不是选项(或不是一个明显的选项)。
如果有人可以提出我的问题的解决方案,我将非常感激。
编辑&amp;解
我知道它不是一个枚举,但它以相同的方式工作并提供我需要的功能:
......现在,代码:
public class ValueGetter<T extends A, R> {
private String name;
private Function<A,R> getter;
private ValueGetter(String name, Function<A, R> getter){
this.name = name;
this.getter = getter;
}
private static <T extends A, R> ValueGetter create(String name, Function<T,R> valueGetter){
return new ValueGetter(name, valueGetter);
}
public static ValueGetter<A, Integer> AA = create("a", A::getA);
public static ValueGetter<B, Integer> BB = create("a", B::getB);
public Function<T, R> getGetter(){
return (Function<T, R>) this.getter;
}
}
有了这个实现
A a1 = new A(12345);
B b1 = new B(54321, "sdfghjk");
System.out.println(ValueGetter.AA.getGetter().apply(a1));
System.out.println(ValueGetter.AA.getGetter().apply(b1));
System.out.println(ValueGetter.BB.getGetter().apply(b1));
编译并工作,而行
System.out.println(ValueGetter.BB.getGetter().apply(a1));
给出了编译错误apply(B) in function cannot be applied to (A)
答案 0 :(得分:1)
实现它的一个问题是使用每个类的单例实例:
class BB { // Renamed B to BB to make it work with enum
String b;
private static final BB instance = new BB();
public static BB getInstance() {
return instance;
}
public String getB(){
return this.b;
}
// Example usage with cast
public String getB(Object b) {
return ((BB) b).getB();
}
}
public enum ValueGetters{
B("b", BB.getInstance()::getB);
String parameterName;
Function parameterGetter;
ValueGetters(String parameterName, Function parameterGetter){
this.parameterName = parameterName;
this.parameterGetter = parameterGetter;
}
}
你可以这样使用它:
ValueGetters.B.getGetter().apply(b);
答案 1 :(得分:1)
您的enum
有两个基本问题。首先,有一个名字冲突。您的类名为A
和B
,enum
常量的名称为A
和B
。在所有上下文中,标识符可以引用类,类或变量,Java会更喜欢变量,因此,您指的是enum
常量A
和B
在您的A::getA
和B::getB
。
此外,您使用的是原始类型 Function
,它不支持此类特定方法引用。解决这个问题的一种方法是
package somepackage;
import java.util.function.Function;
class A{
int a;
int getA(){
return this.a;
}
}
class B extends A{
String b;
String getB(){
return this.b;
}
}
enum ValueGetters{
A("a", somepackage.A::getA),
B("b", somepackage.B::getB);
String parameterName;
Function parameterGetter;
<T> ValueGetters(String pName, Function<T,Object> f) {
parameterName=pName;
parameterGetter=f;
}
}
请注意,您需要将类放在命名的package
中才能消除名称的歧义。对于未命名的默认包,无法做到这一点。
此外,parameterGetter
变量仍然具有原始类型 Function
,因为无法为具有签名{{}的两个函数表达公共函数类型。 1}}和A -> Integer
。你不能在这里使用泛型来解决这个问题,因为B -> String
不支持在常量上使用不同的类型参数。
您已经找到了正确的解决方案,从enum
转到普通的泛型类,它可以定义不同类型的常量。命名常量enum
和AA
而不是BB
和A
也可以解决名称冲突。但是,如果有B
,则不应使用Function<A,R>
,此外,您还有复制和粘贴错误。
您可以清理它,简化您的解决方案:
Function<T,R>