如何使用Java Generics避免不安全的强制转换警告

时间:2012-02-29 08:44:38

标签: java generics casting warnings unsafe

我是Java Generics的新手。但我已经阅读了很多摘要链接和示例。但我无法获得最简单的方法。我希望somenoe可以提供帮助:

我想创建一个HashMap,它将一个未定义的Object映射到另一个。两个对象都可以是String或Integer之一。

所以我写了这个:

private final HashMap<L, R> left2Right = new HashMap<L, R>();

Extractor<?> extLeft  = Extractor.getInstance(0);
Extractor<?> extRight = Extractor.getInstance(1);

L leftVal = extLeft.extract(d, i);
R rightVal = extRight.extract(d, i);

this.left2Right.put(leftVal, rightVal);

到目前为止一直很好......但是我在实现提取器对象时遇到了问题。它们由工厂模式实现。我这样做了(简单地说):

abstract class Extractor<E> {
    abstract E extract(DTable source, int row);

    static <E> Extractor<E> getInstance(int type) {
        if(type == 0)
            return new IntExtractor();
        else
            return new StringExtractor();
    }
}

class IntExtractor extends Extractor<Integer> {

    @Override
    Integer extract(DTable source, int row) {
        int value = 5;
        return new Integer(value);
    }

}

class StringExtractor extends Extractor<String> {

    @Override
    String extract(DTable source, int row) {
        String retVal = "hello";
        return retVal;
    }

}

它编译,但是我在将整数/字符串转换为E时得到Unsave强制警告。我做错了什么?我知道,我可以简单地压制警告。但我认为这应该是Java泛型的优势?我不能让这个演员保存,因为我不知道,'E'真正“是”哪种类型......

或者我做的事情基本上是错的?

注意: 在我使用了第一个答案中的一些信息之后,我将我的代码编辑成了一个“新”问题......

4 个答案:

答案 0 :(得分:2)

你的提取器根本不是通用的。这听起来像你想要的东西:

public interface Extractor<P> {
    P extract(DTable source, int row);
}

然后使实现非通用:

class IntExtractor implements Extractor<Integer> {

    Integer extract(DTable source, int row) {
        int value = 5;
        return new Integer(value);
    }
}

从根本上说,你当前的代码已被破坏,因为我可以写:

IntExtractor<String> extractor = new IntExtractor<String>();
String x = extractor.extract(...);

......这显然会失败,但仅限于执行时间。

答案 1 :(得分:1)

我会说你做的事情基本上是错的。如果它是IntExtractor和StringExtractor,则不需要泛型。只需定义方法

Integer extract(DTable source, int row)

String extract(DTable source, int row)

答案 2 :(得分:1)

问题不在于您的代码本身。没有不安全的演员阵容,任务本身就无法解决。再读一遍你的句子:

  

我想创建一个HashMap,它将一个未定义的对象映射到   另一个。两个对象都可以是String或Integer之一。

Java Generics无法为您解决此问题,因为您必须事先知道该类型,否则您必须进行强制转换。

说实话,我不知道你想用你发布的代码实现什么,但是如果你想使用HashMap,你可以这样做:

private final HashMap<String, Integer> left2Right = new HashMap<String, Integer>();
left2Right.put("one", 1);
int numberOne = left2Right.get("one");

在这种情况下,您不必转换值,因为HashMap具有String键和Integer值。如果要将不同类型作为值,则必须使用所有值的超类型。此超类型可能是Object,即层次结构的根。但是在那些情况下你必须施放 - 因为你不知道这个价值是什么类型的对象。

    private final HashMap<String, Integer> left2Right = new HashMap<String, Object>();
    left2Right.put("one", 1);
    left2Right.put("two", new Date());
    // Because the compiler cannot know that type "one" might be, this isn't allowed and     you have to cast the value. It might be anything - in this example Date or Integer.
    int numberOne = left2Right.get("one");

我希望有所帮助。

答案 3 :(得分:0)

PE似乎都没有用于提取器的输入,那你为什么要使用它们呢?只需返回intString即可完成。