Java 对象返回类型与泛型方法

2022-09-02 04:25:47

我看到几个关于通用返回类型的问题,但没有一个回答我的问题。
如果没有任何参数的边界,例如 JayWay 中的以下方法:

public static <T> T read(String json, String jsonPath, Filter... filters) {
    return new JsonReader().parse(json).read(jsonPath, filters);
}

将其用作通用值有什么意义?
我告诉我团队的人,这种方法应该用作:

JsonPath.<Boolean>read(currentRule, "$.logged")

而不是:

(boolean) JsonPath.read(currentRule, "$.logged")

但我真的分不清区别...


答案 1

泛型的工作原理是编译器将不可见的强制转换插入到代码中。

例如,在将泛型添加到语言之前,您必须执行此操作。

List list = new ArrayList();
list.add("Foo");
list.add("Bar");
String str0 = (String) list.get(0);
String str1 = (String) list.get(1);

这很烦人。因为返回,你必须投掷每一次你想从.get()ObjectStringList

如今,它是通用的,并且返回 ,因此您可以执行此操作。Listget()T

List<String> list = new ArrayList<>();
list.add("Foo");
list.add("Bar");
String str0 = list.get(0);
String str1 = list.get(1);

这里发生的事情是,编译器通过为您添加强制转换将新版本转换为旧版本,但它们仍然存在。

然而,泛型的全部意义在于,这些编译器生成的强制转换保证是安全的 - 即它们不可能在运行时抛出。ClassCastException

在我看来,如果你使用泛型来隐藏不能保证安全的投射,仅仅因为它们很烦人,那就是滥用这个功能。

无论是通用方法,你做

Boolean a = JsonPath.<Boolean>read(currentRule, "$.logged");

或者它返回,你做Object

Boolean a = (Boolean) JsonPath.read(currentRule, "$.logged");

这两个版本都可以在运行时抛出,所以我认为如果你被迫投射会更好,这样至少你知道你正在做一些可能失败的事情。ClassCastException

我认为,如果方法参数不涉及类型参数,则泛型方法的返回类型类型是不好的做法,除非返回的对象不能以损害类型安全的方式使用。例如T

public static <T> List<T> emptyList()

in 是可以的(列表是空的,所以它不能包含错误类型的元素)。Collections

在你的情况下,我认为该方法不应该是通用的,而应该只返回。readObject


答案 2

我会远离的主要原因

JsonPath.<Boolean>read(currentRule, "$.logged")

是它在内部执行了不受约束的演员表,并隐藏了这一事实。例如,您可以在同一位置调用此方法:

JsonPath.<String>read(currentRule, "$.logged")

在运行时实际发生之前,您不可能知道可能存在问题 - 它仍然会编译,您甚至不会收到警告。

无法摆脱未经检查的演员阵容 - 我宁愿在代码中将其放在我面前,这样我就知道存在潜在的危险;这使我能够采取合理的步骤来缓解此问题。

@SuppressWarnings("unchecked")  // I know something might go wrong here!
boolean value = (boolean) JsonPath.read(currentRule, "$.logged")

推荐