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

Java对象返回类型与泛型方法,java,generics,Java,Generics,我看到了几个关于泛型返回类型的问题,但没有一个回答我的问题。 如果任何参数都没有绑定,例如中的以下方法: 但是我真的看不出有什么不同…我不想去的主要原因是什么 JsonPath.<Boolean>read(currentRule, "$.logged") 两者在功能上没有什么不同。字节码可能是相同的 核心区别在于,一个使用cast,而另一个使用泛型 如果有任何替代机制,我通常会尽量避免使用强制转换,因为通用形式是一种非常有效的替代方式,所以我会选择它 // The right wa

我看到了几个关于泛型返回类型的问题,但没有一个回答我的问题。
如果任何参数都没有绑定,例如中的以下方法:


但是我真的看不出有什么不同…

我不想去的主要原因是什么

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

两者在功能上没有什么不同。字节码可能是相同的

核心区别在于,一个使用cast,而另一个使用泛型

如果有任何替代机制,我通常会尽量避免使用强制转换,因为通用形式是一种非常有效的替代方式,所以我会选择它

// The right way.
JsonPath.<Boolean>read(currentRule, "$.logged");
//正确的方法。
JsonPath.read(currentRule,“$.logged”);

有一个从未设置过的类型参数(当调用
JsonPath.read(currentRule,“$.logged”)
时),实际上会使编译器完全忽略方法中的所有泛型信息,并将所有类型参数替换为:

  • 对象
    ,如果类型参数没有上限。(就像你的情况一样)
  • U
    ,如果类型参数像
    一样有界。例如,如果您将一个
    作为类型参数,并通过调用
    JsonPath.read(…)
    忽略它,那么编译器将用
    数字
    替换该类型参数
对于强制转换(
(boolean)JsonPath.read(…)
),类型参数将替换为
对象
。然后,通过首先返回一个
boolean
(可能),然后将此包装自动取消装箱为
boolean
,将此类型安全地转换为
boolean
。这根本不安全。事实上,每一个强制转换都是不安全的——你可以告诉编译器:“我知道这种类型在运行时是什么,所以请相信我,让我将它强制转换为与之兼容的其他类型。”。你卑微的仆人,编译器,允许这样做,但如果你错了,那是不安全的

你的方法还有一点。类型参数从未在方法体或参数中使用-这使得它非常冗余。因为通过对
boolean
进行强制转换,您坚持要知道
new JsonReader().parse(json).read(jsonPath,filters)的返回类型
,那么您只需将返回类型设置为
boolean
(或
boolean
):


泛型通过编译器在代码中插入不可见的强制转换来工作

例如,在将泛型添加到语言之前,您必须这样做

List list = new ArrayList();
list.add("Foo");
list.add("Bar");
String str0 = (String) list.get(0);
String str1 = (String) list.get(1);
这很烦人。因为
get()
返回了
Object
,所以每次想从
列表中获取
字符串时都必须强制转换

现在,
List
是通用的,
get()
返回
T
,所以您可以这样做

List<String> list = new ArrayList<>();
list.add("Foo");
list.add("Bar");
String str0 = list.get(0);
String str1 = list.get(1);
或者它返回
对象
,而您确实这样做了

Boolean a = JsonPath.<Boolean>read(currentRule, "$.logged");
Boolean a = (Boolean) JsonPath.read(currentRule, "$.logged");
两个版本都可能在运行时抛出一个
ClassCastException
,因此我认为最好是强制执行cast,这样至少你会意识到你正在做一些可能失败的事情

我认为,如果方法参数没有,则返回类型的泛型方法涉及类型参数<代码> t>代码>的不良做法,除非返回的对象不能以破坏类型安全的方式使用。比如说,

public static <T> List<T> emptyList()
公共静态列表emptyList()
集合中
正常(列表为空,因此不能包含错误类型的元素)


在你的例子中,我认为
read
方法不应该是泛型的,应该在类型擦除后返回
Object

,我不认为有什么区别。方法体中表面上没有使用类型变量
t
JsonPath.read(currentRule,$.logged)
如何安全地返回一个
Boolean
,而
JsonPath.read(currentRule,$.logged)
如何安全地返回一个
String
?您是否愿意将强制转换更改为
Boolean
,以避免将自动装箱拖入问题?实际上,我看不出泛型在这里有什么优势。如前所述,T从未被使用。@JFMeier主要的缺点是未经检查的强制转换隐藏在方法中,而不是当着你的面告诉你你正在做一些类型不确定的事情。那么你实际上是在说,该方法最好返回一个
对象
,而不是泛型,因为施法是可入侵的?@Nati-yes。正如我在上面所评论的,除了执行未经检查的强制转换之外,您实际上没有使用
t
。按照方法的声明方式,他可以这样做:
String value=JsonPath.read(currentRule,“$.logged”)无论您是否提供显式类型见证,它都将以任何方式在内部执行未经检查的强制转换。这不是我的代码,我只是想知道使用它的最佳方式是什么。无论您是否提供,我希望我能有所帮助。干杯:)我的意思是-这是我使用的一个依赖项,一个第三方代码。你会自己投还是作为泛型通过?我会设置
。我的想法完全正确。我认为它看起来更干净,尽管JayWay内部确实对(T)…@Nati进行了强制转换-它们都进行了运行时强制转换,因此在功能上没有区别。
read
方法是我正在使用的第三方库。如果你在我的位置,你会怎么用它?您可以自己强制转换,也可以在内部强制转换,并捕获
ClassCastException
?@Nati我会使用do
Boolean a=JsonPath.read
Boolean a=JsonPath.read
,并在代码中留下注释,说明
//警告:此方法涉及不安全的强制转换
。这个建议与AndyTurner的(留下评论并使用
@SuppressWarnings(“unchecked”)
)几乎相同,只是实际上没有对Suppress的警告。从我到目前为止看到的情况来看,没有太大的区别,如果有的话。Invable中的unchecked casting,所以它几乎是一个样式化的iss
public static Boolean read(String json, String jsonPath, Filter... filters) {
    return new JsonReader().parse(json).read(jsonPath, filters);
}
List list = new ArrayList();
list.add("Foo");
list.add("Bar");
String str0 = (String) list.get(0);
String str1 = (String) list.get(1);
List<String> list = new ArrayList<>();
list.add("Foo");
list.add("Bar");
String str0 = list.get(0);
String str1 = list.get(1);
Boolean a = JsonPath.<Boolean>read(currentRule, "$.logged");
Boolean a = (Boolean) JsonPath.read(currentRule, "$.logged");
public static <T> List<T> emptyList()