如何解压/简化匿名内部类
Posted
技术标签:
【中文标题】如何解压/简化匿名内部类【英文标题】:How to Unpack/ Simplify Anonymous Inner Class 【发布时间】:2021-10-16 15:32:09 【问题描述】:这篇文章的目的是找出如何避免使用匿名内部类。
我没有与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
以下是子类SimpleAttribute
的链接,它是Attribute
的后代:
https://github.com/npgall/cqengine/blob/master/code/src/main/java/com/googlecode/cqengine/attribute/SimpleAttribute.java
【问题讨论】:
如果它以前有效并且已经很容易阅读,为什么需要更改它(并可能在过程中破坏它)? @QBrute 我正在尝试解压缩匿名内部类,因为有些程序员对它不是很熟悉,包括我自己。如您所见,我不太了解匿名内部类,当我尝试对其进行解压缩时,出现上述错误。 【参考方案1】: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;
试试这个。 如果您进行新的通用实现,则基本上必须使用反射来获取值。如果你这样做,它会更复杂,而不是更简单。
【讨论】:
谢谢!这就是我要找的。一种避免编写匿名内部类的方法。当我使用您对 Name 类的定义时,我看到Person.java
给出了一个编译错误 The type Name is not generic; it cannot be parameterized with arguments <Person, String>
您能否对这个问题投赞成票,有人恶意投反对票,这可能会导致其他响应者没有注意到它。
你需要使名称对象像 new Name()
@Arthur W 另一个答案是错误的,因为构造中不应该有参数。命名参数永远不会是“名称”以外的另一个属性。将我的标记为答案:)【参考方案2】:
对于您的代码,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
的类型参数都是具体类型,而不是像您尝试的类型变量 O
和 A
。
你会这样使用它:
public static final Attribute<Person, String> NAME = new Name("name");
从异常信息来看,
属性“名称”(类 examples.introduction.novice.simpler.model.Name)无效,无法从中读取泛型类型信息。
您正在使用的库依赖于这种行为(类型参数是具体类型的事实)来读取类型参数。它可能会调用以下内容:
((ParameterizedType)NAME.getClass().getGenericSuperclass()).getActualTypeArguments()
如果SimpleAttribute
的类型参数是O
和A
,就像您尝试解压缩匿名类一样,返回的数组将没有任何实际类型,这可能就是它说“无法读取泛型”的原因类型信息”。
另一方面,如果您使用匿名类(或答案开头的代码),则生成的内部类将具有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
的另一个重载并不真正相关。
【讨论】:
覆盖的getvalue
方法是由 Eclipse 生成的,因为没有它,该类会出现编译器错误:The type Name<O,A> must implement the inherited abstract method SimpleAttribute<O,A>.getValue(O, QueryOptions)
我试图避免使用内部匿名类 - 有没有办法做到这一点?
@ArthurW 没错,此时您应该意识到您的“拆包”有问题。有助于实现抽象类的重载是返回 null 的重载。另一个不相关。看到你的错误了吗?如果Name
是通用的,它必须有一个getValue
方法,它接受一个O
和一个QueryOptions
,但这永远不会起作用,因为你想返回一个人的 名称,所以@ 987654343@ 不应该是通用的。有关将匿名类正确转换为命名类的信息,请参见答案的开头。什么不清楚?
尚不清楚如何完全避免使用匿名内部类?什么实现可以完全避免这种情况?抱歉,但由于某种原因,我的认知能力在这个时候并不是最佳的(出于某种奇怪的原因)。 @Sweeper
@ArthurW 你看到我回答的latest edit了吗?我添加了一个示例,说明如何重写 NAME
的声明以使用 named 类 Name
。
您的建议成功了!谢谢!惊人的!我不知道如何或为什么,在我的想法不那么模糊之后,我会复习你的答案......以上是关于如何解压/简化匿名内部类的主要内容,如果未能解决你的问题,请参考以下文章