【问题标题】:Generic primitive type with casting带强制转换的通用原始类型
【发布时间】:2018-06-11 11:06:03
【问题描述】:

我的 Java 代码有问题。我想通过使用泛型类型使我的方法通用。用代码更容易解​​释:

public interface Destroyable {

    void destroy();

    default void destroyArray(byte[] array) {
        Arrays.fill(array, (byte)0);
    }

    default void destroyArray(char[] array) {
        Arrays.fill(array, (char)0);
    }

}

重点是,我希望我的默认方法 destroyArray 可以用于任何类型,如下所示:

public interface Destroyable {

    void destroy();

    default <E> void destroyArray(Class<E>[] array) {
        Arrays.fill(array, (E)0);
    }

}

它给了我错误:

不可转换的类型;不能将“int”转换为“E”

有没有简单的解决方案来实现这一点?

【问题讨论】:

  • 0 替换为nullClass&lt;E&gt;[] 也应该是 E[]
  • @Lino 哇,就这么简单,谢谢 :) 还有一个问题,是否有任何理由将其保留为Class&lt;E&gt;[] 或仅使用E[]
  • 这意味着完全不同的东西。 Class&lt;E&gt; 是一个 Class 对象,一个提供反射访问以分析类内容的包装器。就像获取方法的名称和类似的东西。而E 是类本身。所以Person 是一个person 类,Class&lt;Person&gt; 就像一个知道Person 类的东西的类,比如它的方法名。
  • 还有一件事:destroyArray() 不应该是一个实例方法,而应该是一个static 一个,因为它只是一个助手

标签: java generics casting


【解决方案1】:

对象的默认值

你的代码有问题:

default <E> void destroyArray(E[] array) {
    Arrays.fill(array, (E) 0);
}

一般E 类型当然不一定是int(或者像Integer 这样可以自动装箱的东西)。但是您想实际编写一些 default 值。因此,您需要创建E 的有效实例。一般来说,这很难,因为您对类型一无所知,包括它的构造函数。

但是,所有Objects 都有一个有效值,即null。这表明目前根本没有实例。

因此以下内容适用于任意类型E

default <E> void destroyArray(E[] array) {
    Arrays.fill(array, null);
}

原语

但是,您仍然无法填充像int[] 这样的原始类型数组,因为E 只能用于Objects,而不是原始类型。您需要为每个原语硬编码其他方法:

default void destroyArray(int[] array) {
    Arrays.fill(array, 0);
}

default void destroyArray(double[] array) {
    Arrays.fill(array, 0.0);
}

// ...

注意Class&lt;E&gt;

您的原始代码使用Class&lt;E&gt;[] 而不是E[]。请注意,Class&lt;E&gt; 的含义与 E[] 完全不同。

Class&lt;E&gt; 是一个Class 对象,它是一个包装器,它提供Reflection-API 访问以分析类的内容。就像获取方法的名称和类似的东西。而E 是类本身。

所以Person 将是一个Person 类,而Class&lt;Person&gt; 就像一个知道Person 类的东西的类,比如它的方法名称。

有关详细信息,请参阅 Classdocumentation

【讨论】:

  • “而E 是类的一个实例”。可能会更好
  • 可能不好,我只是想在这里感谢您的评论和投票......我已经在某个时候了;-)
【解决方案2】:
default <E> void destroyArray(E[] array) {
    Arrays.fill(array, null);
}

以上可能是您想要的。 然而,这不适用于原始类型。因为不允许将原始类型作为泛型类型参数传递,所以您仍然需要 destroyByteArraydestroyIntArray 等。

另外,destroyArray 似乎不属于Destroyable。它不应该只是在一个充满静态方法的辅助类中吗?如果我是你,我会把它移到那里。它甚至不调用destroy 方法,所以它没有理由在Destroyable

【讨论】:

  • 感谢您的回答!将destroyArray 移出Destroyable 接口绝对是个好主意,因为当我保留它时,每个实现此接口的类都不需要Destroyable 接口的默认方法,正如你所说,它们独立于destroy 方法
【解决方案3】:

您使用许多重载方法的原始方法很好。

对于原始类型,泛型适用于它们的数组

default <A> void destroyArray(A array) {
    Class<?> arrayType = array.getClass();
    if (!arrayType.isArray()) {
        return;
    }
    Class<?> type = arrayType.getComponentType();
    if (type == int.class) {
        Arrays.fill((int[])array, 0);
    } else if (type == char.class) {
        Arrays.fill((char[])array, '\0');
    }
    //...
}

如您所见:这几乎不是更紧凑、更慢、更不安全的类型,以及安全被遗忘的原始类型。

【讨论】:

    猜你喜欢
    • 2015-01-18
    • 2010-10-03
    • 2016-11-25
    • 2011-02-13
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 2021-01-24
    • 1970-01-01
    相关资源
    最近更新 更多