java - 扩展泛型类时出现 ClassCastException

标签 java arrays generics libgdx

假设我有一个 Text 类,它实现了一个名为 Drawable 的接口(interface),定义如下:

public interface Drawable {

  public void draw (DrawConfig drawConfig);
}

我想要一个对象,它的行为类似于一个包含项目的数组,但它也实现了 Drawable,以便能够编写 drawables.draw(drawConfig) 并具有它将调用转发给它的所有子节点,而不必执行 for 循环。所以我首先创建了一个包装类,如下所示:

public class Drawables implements Drawable {

  private final Array<Drawable> items = new Array<Drawable>();

  public void add (final Drawable value) {
    this.items.add(value);
  }

  @Override
  public void draw (final DrawConfig drawConfig) {
    for (final T item : this.items)
      item.draw(drawConfig);
  }
}

第一个问题 是因为它是一个包装器,所以它没有任何 Array 类方法,我必须手动添加我需要的方法(比如 add() 在上面的例子中)。

第二个问题是如果我只在其中存储Text对象,我不能写:

for (Text t : drawables)
    t.setText("blablabla");

这意味着我必须创建另一个 数组,为此我将得到两个数组。我想避免这种情况,所以我考虑使用通用性,因为 Array 类是通用的,我将我的 Drawables 类变成了这个:

public class Drawables<T extends Drawable> extends Array<T> implements Drawable {

  @Override
  public void draw (final DrawConfig drawConfig) {
    for (final T item : this.items) // Line 17
      item.draw(drawConfig);
  }
}

现在我可以写了:

Drawables<Text> drawables = new Drawables<Text>();

drawables.add(new Text());
drawables.add(new Text());

for (Text t : drawables)
    t.setText("blablabla");

drawables.draw(drawConfig);

它编译了!! 除了在运行时我得到以下错误:

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [La.b.c.ui.Drawable;
    at a.b.c.Drawables.draw(Drawables.java:17)
    at a.b.c.ui.components.Text_UseTest.render(Text_UseTest.java:80)
    at com.badlogic.gdx.backends.lwjgl.LwjglApplication.mainLoop(LwjglApplication.java:215)
    at com.badlogic.gdx.backends.lwjgl.LwjglApplication$1.run(LwjglApplication.java:120)

请参阅我的代码中第 17 行的注释。

问题是什么?甚至有可能实现我想做的事情吗?

最佳答案

我认为您的设计不正确。 Drawable 不是分开绘制单个项目和绘制多个项目应该只在其契约(Contract)中指定它根据某些配置绘制。它是如何做到这一点的,或者它使用什么其他对象来做到这一点并不重要。

因此,我首先会这样做:

public interface Drawable {
    void draw (DrawConfig drawConfig);    
}

现在看来你想要你的 Drawable维护私有(private)成员。这个私有(private)成员对事物的绘制方式有一定影响。有趣的一点是,它可能是被绘制的东西本身,或者它可能包含需要绘制的东西,或者它可能完全是其他东西。目前我们不知道如何它会影响 draw 的行为.那么我们如何处理呢?那么我们可以创建一个抽象类来维护这个私有(private)成员并实现 Drawable :

public abstract class AbstractDrawable<T> implements Drawable {    
    protected T data;           
}

注意 draw 没有实现.这是有目的的,因为只有在具体实现中,我们才会真正为 draw 定义行为。 .您现在可以很容易地看到我们如何拆分两个关注点(维护状态和实现行为)。现在我们可以定义一个具体的实现,它定义如何它将保持状态以及如何它将实现行为:

public class Drawables<T extends Drawable> extends AbstractDrawable<List<T>> {

    public Drawables() {
        this.data = new ArrayList<T>();
    }

    public void addDrawable(T item) {
        this.data.add(item);
    }

    @Override
    public void draw (final DrawConfig drawConfig) {
        for (final T item : this.data) {
            item.draw(drawConfig);
        }
    }
}

这里我们有一个非常具体的 AbstractDrawable<T> 实现它本身与可绘制对象列表一起使用。这个具体的实现已经定义了它如何管理状态(它使用 Drawable 实例的内部列表)以及它如何管理行为(它的“绘制”行为是“绘制”它维护的每个 Drawable 实例)。

您提到您想要所有的列表方法等。仅仅为了访问其方法而扩展一个类并不是一个好主意。您的可绘制项目列表并不是真正的列表。它是一个恰好与可绘制对象列表一起使用的可绘制对象。上面的方法隐式地使用组合而不是继承,因为 AbstractDrawable<T>封装一些将以某种方式绘制的内部数据(不重要如何这是完成的;只是完成了)。所以不是扩展 List<T> ,您现在可以维护一个内部列表,然后您可以按照您选择的方式“绘制”该列表。这正是具体实现中发生的事情 Drawables<T extends Drawable> .

您的下一个问题是关于无法调用 t.setText()Text实例。你能做到这一点的唯一方法是,如果你有一个具体的实例,专门适用于 Text实例,或者如果您执行了 instanceof检查内部 draw .这是因为你只有 T extends Drawable ;类知道它是某种 Drawable ,它能够draw .除此之外,它不知 Prop 体的实现。

关于java - 扩展泛型类时出现 ClassCastException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31278329/

相关文章:

python - 数组解释的循环旋转

ios - 按特定单词将 NSString 拆分为数组

java - 泛型方法参数的类型

java - 从多线程设置和更新并发 HashMap

c 扫描二维数组

Java异常: unknown protocol: udp

actionscript-3 - 可以使用类型引用声明 AS3 向量吗?

java - 获取父类(super class)的超接口(interface)参数的类

java - 如何使用 OpenCV 将图像转换为黑白图像并去除 android 中的阴影

java - 这个 "s"实际上是最终的吗?