如何解包/简化匿名内部类



这篇文章的目的是找出如何避免使用匿名内部类。

我没有广泛地使用inner anonymous classes,但我正试图简化某人的包examples.introduction.novice.simpler.model;

中的以下代码行
public class Person {
public final String name;
// --- Attribute
public static final Attribute<Person, String> NAME = new SimpleAttribute<Person, String>("name") {
public String getValue(Person person, QueryOptions queryOptions) { return person.name; }
};
}

打开上面的&我重写了它,所以(如果我错了请纠正我):

public class Person {
public final String name;

public Person(String name) {
this.name = name;
}


// TODO: Simplify
// ----------- Attributes -------------
public static final Attribute<Person, String> NAME = new Name<Person, String>("name") ;
}

当然,我创建了Name类,所以:

public class Name<O, A> extends SimpleAttribute<O, A> {
public Name(String attributeName) {
super(attributeName);
// TODO Auto-generated constructor stub
}
public String getValue(Person person, QueryOptions queryOptions) { return person.name; }
@Override
public A getValue(O arg0, QueryOptions arg1) {
// TODO Auto-generated method stub
return null;
}

}

然而,我得到一个错误,所以:

Exception in thread "main" java.lang.ExceptionInInitializerError
at examples.introduction.novice.simpler.model.Introduction.main(Introduction.java:17)
Caused by: java.lang.IllegalStateException: Attribute 'name' (class examples.introduction.novice.simpler.model.Name) is invalid, cannot read generic type information from it. Attributes should typically EITHER be declared in code with generic type information as a (possibly anonymous) subclass of one of the provided attribute types, OR you can use a constructor of the attribute which allows the types to be specified manually.
at com.googlecode.cqengine.attribute.support.AbstractAttribute.readGenericObjectType(AbstractAttribute.java:139)
at com.googlecode.cqengine.attribute.support.AbstractAttribute.<init>(AbstractAttribute.java:43)
at com.googlecode.cqengine.attribute.SimpleAttribute.<init>(SimpleAttribute.java:55)
at examples.introduction.novice.simpler.model.Name.<init>(Name.java:11)
at examples.introduction.novice.simpler.model.Person.<clinit>(Person.java:23)
... 1 more

回顾一下:我试图在以下包中简化以下示例(这是我试图简化的原始工作示例,它有两个类:主类称为Introduction.java和伴随的类称为Person.java):https://github.com/mrarthurwhite/CQEngineIntroExample/tree/master/src/examples/introduction/novice

尝试简化它在下面的包中(它只是试图解包Person.java类:https://github.com/mrarthurwhite/CQEngineIntroExample/tree/master/src/examples/introduction/novice/simpler/model

与&耐心的读者可以从上面看到,我正试图解包Attribute的匿名内部类。这是Attribute类的链接&cqengine库:https://github.com/npgall/cqengine/blob/master/code/src/main/java/com/googlecode/cqengine/attribute/Attribute.java

下面是Attribute的子类SimpleAttribute的链接:https://github.com/npgall/cqengine/blob/master/code/src/main/java/com/googlecode/cqengine/attribute/SimpleAttribute.java

public class Name extends SimpleAttribute<Person, String> {
public Name() {
super("name");
// TODO Auto-generated constructor stub
}
@Override
public String getValue(Person person, QueryOptions queryOptions) { 
return person.name; 
}
}

试试这个。如果你做一个新的泛型实现,你基本上必须使用反射来获取值。如果你这样做,它会变得更复杂,而不是更简单。

对于您的代码,Java编译器将生成一个更具体的、非泛型的具体类,如下所示(当然名称会有所不同):

public class Name extends SimpleAttribute<Person, String> {
public Name(String attributeName) {
super(attributeName);
}
@Override
public String getValue(Person person, QueryOptions queryOptions) { return person.name; }
}

注意超类的类型是SimpleAttribute<Person, String>SimpleAttribute的类型参数都是具体类型,而不是像你尝试的OA那样的类型变量。

你可以这样使用:

public static final Attribute<Person, String> NAME = new Name("name");

从异常消息判断,

属性'name'(类examples.introduction.novice.simpler.model.Name)无效,无法从中读取泛型类型信息。

您正在使用的库依赖于这种行为(类型参数是具体类型的事实)来读取类型参数。它可能调用了以下内容:

((ParameterizedType)NAME.getClass().getGenericSuperclass()).getActualTypeArguments()

如果SimpleAttribute的类型参数是OA,就像你试图解包匿名类一样,返回的数组将没有任何真正的类型,这可能就是为什么它说"不能读取泛型类型信息"的原因。

另一方面,如果您使用匿名类(或答案开头的代码),则生成的内部类将以SimpleAttribute<Person, String>作为超类,库将能够从中读取有用的信息。

还要注意,即使库没有碰巧读取泛型类型参数,您对匿名类的解包仍然不会做与原始代码相同的事情。也就是说,您重写抽象方法的方式:

@Override
public A getValue(O arg0, QueryOptions arg1) {
// TODO Auto-generated method stub
return null;
}

与原始代码中重写抽象方法的方式不同:

public String getValue(Person person, QueryOptions queryOptions) { return person.name; }

您在Name中定义的getValue的另一个重载并不真正相关。

最新更新