【问题标题】: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 我正在尝试解压缩匿名内部类,因为有些程序员对它不是很熟悉,包括我自己。如您所见,我不太了解匿名内部类,当我尝试对其进行解压缩时,出现上述错误。

标签: java anonymous-class simplify anonymous-inner-class cqengine


【解决方案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 &lt;Person, String&gt; 您能否对这个问题投赞成票,有人恶意投反对票,这可能会导致其他响应者没有注意到它。
  • 你需要使名称对象像 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&lt;Person, String&gt;SimpleAttribute 的类型参数都是具体类型,而不是像您尝试的类型变量 OA

你会这样使用它:

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

从异常信息来看,

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

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

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

如果SimpleAttribute 的类型参数是OA,就像您尝试解压缩匿名类一样,返回的数组将没有任何实际类型,这可能就是它说“无法读取泛型”的原因类型信息”。

另一方面,如果您使用匿名类(或答案开头的代码),则生成的内部类将具有SimpleAttribute&lt;Person, String&gt; 作为超类,并且库将能够读取有用的信息来自它。

还要注意,即使库没有碰巧读取泛型类型参数,您对匿名类的解包仍然不会与原始代码执行相同的操作。即,您覆盖抽象方法的方式:

@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&lt;O,A&gt; must implement the inherited abstract method SimpleAttribute&lt;O,A&gt;.getValue(O, QueryOptions) 我试图避免使用内部匿名类 - 有没有办法做到这一点?
  • @ArthurW 没错,此时您应该意识到您的“拆包”有问题。有助于实现抽象类的重载是返回 null 的重载。另一个不相关。看到你的错误了吗?如果Name 是通用的,它必须有一个getValue 方法,它接受一个O 和一个QueryOptions,但这永远不会起作用,因为你想返回一个人的 名称,所以@ 987654343@ 不应该是通用的。有关将匿名类正确转换为命名类的信息,请参见答案的开头。什么不清楚?
  • 尚不清楚如何完全避免使用匿名内部类?什么实现可以完全避免这种情况?抱歉,但由于某种原因,我的认知能力在这个时候并不是最佳的(出于某种奇怪的原因)。 @Sweeper
  • @ArthurW 你看到我回答的latest edit了吗?我添加了一个示例,说明如何重写 NAME 的声明以使用 namedName
  • 您的建议成功了!谢谢!惊人的!我不知道如何或为什么,在我的想法不那么模糊之后,我会复习你的答案......
猜你喜欢
  • 2023-03-24
  • 2011-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多