使用“原始类型”作为静态字段/返回类型时如何避免泛型警告?

时间:2016-04-21 11:49:35

标签: java generics unchecked raw-types

这基本上是昨天从question开始的。我试图实现“最通用的方式”(我能想到),以便构建“真正”不可修改的集合。下面的代码工作正常;但它需要抑制警告(“rawtypes”和“unchecked”)。

我尝试了各种各样的事情以避免这些警告;但根本找不到替代方案。所以,我的问题是:是否有一种干净的方法来避免我压制的警告?

(我看到了另一个question;但我并不是100%确定它是否真的适用于我的代码;因为我不确定我是否可以在不使用原始类型的情况下写下“Generator”界面)。

private interface Generator<T> {
    T generateNewInstance();
}

@SuppressWarnings("rawtypes")
private final static Generator ListGenerator = new Generator<List>() {
    @Override
    public List generateNewInstance() {
        return new ArrayList();
    }
};

public static <T> List<T> unmodifiableListBasedOnCloneOf(List<T> elements) {
    @SuppressWarnings("unchecked")
    List<T> newInstance = makeNewInstanceOf(elements.getClass(), ListGenerator);
    newInstance.addAll(elements);
    return Collections.unmodifiableList(newInstance);
}

private static <T> T makeNewInstanceOf(Class<T> incomingClass, Generator<T> fallbackGenerator) {
    try {
        return (T) incomingClass.newInstance();
    } catch (IllegalAccessException | InstantiationException e) {
        return fallbackGenerator.generateNewInstance();
    }
}

2 个答案:

答案 0 :(得分:4)

如果您将List<T>的副本复制到新的ArrayList<T>中,并将该引用内联传递给Collections.unmodifiableList,则除了不可修改的装饰器之外的任何内容都无法访问该副本以对其进行修改:

    List<String> original = new ArrayList<>(Arrays.asList("Hello", "World"));

    // This simply decorates original, so updates to original are
    // reflected in this list.
    List<String> unmodifiableDecorator = Collections.unmodifiableList(original);

    // The reference to the new ArrayList is scoped to the call to
    // Collections.unmodifiableList, so nothing else can have a
    // reference to it.
    List<String> unmodifiableCopy =
        Collections.unmodifiableList(new ArrayList<>(original));

    System.out.println("Before clear:");
    System.out.println(original);
    System.out.println(unmodifiableDecorator);
    System.out.println(unmodifiableCopy);

    original.clear();

    System.out.println("After clear:");
    System.out.println(original);
    System.out.println(unmodifiableDecorator);
    System.out.println(unmodifiableCopy);

输出:

Before clear:
[Hello, World]
[Hello, World]
[Hello, World]
After clear:
[]
[]
[Hello, World]

因此,unmodifiableCopy未被修改,并且无法修改,除非您能够以某种方式说服unmodifiableList向您提供代理人引用。

由于您无法对其进行修改,因此您无需使用与输入列表相同的具体列表类型。只需将其设为ArrayList,因为它具有List实现可以实现的最佳读取性能。

所以你的方法,没有警告或额外的类,可以是:

public static <T> List<T> unmodifiableListBasedOnCloneOf(List<T> elements) {
  return Collections.unmodifiableList(new ArrayList<>(elements));
}

答案 1 :(得分:2)

并不总是可以避免@SuppressWarnings注释。我尝试将其范围限制为局部变量。

我想出了这个:

private interface Generator<T> {

    T generateNewInstance();
}

private static class ListGenerator<T> implements Generator<List<T>> {
    @Override
    public List<T> generateNewInstance() {
        return new ArrayList<>();
    }
};

public static <T> List<T> unmodifiableListBasedOnCloneOf(List<T> elements) {
    @SuppressWarnings("unchecked")
    Class<List<T>> clazz = (Class<List<T>>)elements.getClass();
    List<T> newInstance = makeNewInstanceOf(clazz , new ListGenerator<T>());
    newInstance.addAll(elements);
    return Collections.unmodifiableList(newInstance);
}

private static <T> T makeNewInstanceOf(Class<T> incomingClass, Generator<T> fallbackGenerator) {
    try {
        return (T) incomingClass.newInstance();
    } catch (IllegalAccessException | InstantiationException e) {
        return fallbackGenerator.generateNewInstance();
    }
}