首页 > 解决方案 > 泛型方法中需要 Java 冗余强制转换

问题描述

我正在寻找一种方法来使用通用函数优化我们的代码库中的某些内容。有一个返回类型的函数List<Object>可能有返回类型List<SpecifiedType>

Bellow 是该函数的极简版本,称为function. 它接受一个参数类型,基于它调用一个相应的函数(这里限于String)或泛型函数。

public static ArrayList<String> forString(){
    ArrayList<String> res = new ArrayList<>();
    // Fetching and processing data specific to String
    return res;
}

public static <T> ArrayList<T> forGeneric(Class<T> type){
    ArrayList<T> res = new ArrayList<>();
    // Fetching data
    return res;
}

public static <T> ArrayList<T> function(Class<T> type){
    if(type == String.class)
        return (ArrayList<T>) forString();
    return forGeneric(type);
}

目标是像这样调用上面的函数:ArrayList<SomeType> someTypes = function(SomeType.class);

关于上面的代码,我注意到了两件事:

  1. Cast toArrayList<T>是必需的,即使我们知道如果类型String作为参数传递,它将ArrayList<String>forString()方法一样返回

  2. Cast toArrayList<T>给出Unchecked cast警告,即使返回类型为ArrayList<String>

我的问题是有没有更好的方法(最好没有演员表),如果没有,那为什么

标签: javagenericsinstanceof

解决方案


首先,这个说法在逻辑上是错误的

if(type.isInstance(String.class))

If typeis Class<String>thenisInstance检查参数是否为字符串实例。您传递的参数是一个类实例(特别是 a Class<String>)。

如果你更喜欢,

String.class.isInstance(String.class) == false

你的意思是

if(type == String.class)

但是,即使解决了这个逻辑错误,您的代码仍然会有未经检查的强制转换警告。

你缺少的部分就在这里

Cast toArrayList<T>是必需的,即使我们知道如果类型 String 作为参数传递,它将ArrayList<String>forString()方法一样返回

确切地。我们知道。但是我们知道的和编译器知道的是两件不同的事情。编译器不够聪明,无法检查条件并意识到类型没问题。可以想象它可能足够聪明,但事实并非如此。

这正是为什么这表现为警告而不是错误的原因。这是一个警告,因为您正在做的事情可能是错误的;这不是绝对错误的,否则它根本不会编译。在这种情况下,警告应该提示您仔细检查您正在做的事情是否正确,然后您可以愉快地抑制它。

@SuppressWarnings("unchecked")
public static <T> ArrayList<T> function(Class<T> type){
    if(type == String.class)
        return (ArrayList<T>) forString();
    return forGeneric(type);
}

最后——它可能是你人为的例子的产物——但所有这些方法都是无用的。与直接调用相比,似乎没有任何优势new ArrayList<>()。在运行时,无论它来自 3 个方法中的哪一个,实际实例都是相同的。


推荐阅读