下面的方法完美无瑕
public <T> void fromJsonArray(String jsonString,Type tToken) {
Gson g = new Gson();
T list = g.fromJson(jsonString,tToken);
System.out.println(list);
}
但是我没有指定此方法中的
fromJson
方法返回的值分配给
list
未指定类型i 的变量?
我只是测试了答案的有效性,指出了<T>
从该方法的返回类型推断出的答案。它似乎没有解决。请检查以下代码。它甚至不编译
import java.util.*;
class Sample {
public List<String> getT(String s) {
List<String> list = new ArrayList<String>();
list.add(s);
return list;
}
public <T> void test(){
T list = getT("test");
System.out.println(l);
}
public static void main(String[] a) {
new Sample().test();
}
}
再次修改源代码并对其进行测试,结果导致编译时错误
public <T> List<T> getT(T s) {
List<T> list = new ArrayList<T>();
list.add(s);
return list;
}
public <T> void test(){
T list = getT("test"); //incompatible types compilation error here
System.out.println(list);
}
Sample1.java:13: error: incompatible types T list = getT("test"); ^ required: T found: List where T is a type-variable: T extends Object declared in method test()
该方法如何推断类型
<T>
没有。泛型方法不推断其泛型类型-这就是为什么T
称为 类型参数 的原因。方法的 调用者 提供的类型参数T
。如果这样做,编译器 可能
会根据方法调用的参数和目标类型的上下文来推断出它。
例如:
Set<String> c = Collections.emptySet();
emptySet
声明类型参数T
,不带参数,并返回Set<T>
。在此,编译器推断T
是String
基于目标类型Set<String>
。
另一个例子:
Collections.singleton("asdf");
singleton
声明一个类型参数T
,使用T
,然后返回Set<T>
。在这里,没有目标类型,但是编译器推断T
是String
基于参数"asdf"
。
但是泛型类型推断只是一种方便。没有它,我们仍然可以使用 类型见证 来显式提供类型参数:
Set<String> c = Collections.<String>emptySet();
Collections.<String>singleton("asdf");
这将我们带到您的方法签名:
public <T> void fromJsonArray(String jsonString, Type tToken)
fromJsonArray
声明类型参数T
,但不返回与类型相关的任何东西T
或接受与类型有关的参数T
。在调用时fromJsonArray
,编译器没有从中进行推断的信息T
。Object
除非使用类型见证,否则其类型参数将默认为其上限。
myObj.<String>fromJsonArray(jsonString, tToken);
但这没关系,因为<String>
对方法调用或其编译的行为没有影响。T
是没有意义的*,可以从的声明中删除fromJsonArray
。
编译器如何将
fromJson
方法返回的值分配给list
未指定类型i 的变量?
这是来源Gson.fromJson(String, Type)
:
@SuppressWarnings("unchecked")
public <T> T fromJson(String json, Type typeOfT) throws JsonParseException {
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
您可以看到它声明了一个任意类型的参数T
,并将反序列化的对象强制转换为T
。这称为 未检查的强制转换
,因为如果出错,它不会快速失败。那是因为在运行时T
已被擦除。您可以看到代码抑制了这样做的警告,因为通常这是一个坏主意。通过不限制T
基于方法参数的内容,Gson代码已有效地将其控制权转让给了调用者。如果您写:
List<String> list = g.fromJson(jsonString, tToken);
但用tToken
表示HashSet<String>
,您将ClassCastException
在运行时在该行上得到一个。更糟糕的是,如果tToken
表示的话ArrayList<Integer>
,它甚至不会在那条线上失败,因为JVM只会看到List
并允许分配发生。ClassCastException
一旦您的代码尝试将列表的Integer
元素处理为String
s
,便会在以后的某个时间抛出A (并且此异常会导致调试混乱)。
因此,要回答有关分配的问题,编译器可让您将结果分配给所需的fromJson
任何对象。正确无误取决于您。
您可能会问, 为什么Gson会进行未经检查的强制转换并允许使用不安全的代码? 答案是由于语言限制,这很方便。他们的其他签名更安全:
public <T> T fromJson(String json, Class<T> classOfT)
但是没有办法用Class
-
来表示通用类型List<String>.class
。只有一个Type
可以做到这一点,它本身并不是通用的。fromJson
可能需要一个TypeToken<T>
,但是还有其他方法可以获取Type
,因此这是限制性的。
返回Object
并强制调用者进行未经检查的强制转换会更加透明,但是Gson开发人员可能希望避免这种“丑陋”。
我的分类测试应用程序有一个问题,我使用了一个比较器。我收到一条信息: 线程“主”java.lang 中的异常:未解决的编译问题:无法推断排序器的类型参数 对于该代码: 分拣机类: 可比接口: id比较器类: 比较器接口: 这样用有什么错?我怎样才能做得更好?
主要内容:1 Java8 类型推断的介绍,2 Java8 类型推断的案例1,3 Java8 类型推断的案例21 Java8 类型推断的介绍 类型推断是Java的一项功能,它使编译器可以查看每个方法调用和相应的声明以确定参数的类型。 Java在Java 8中提供了类型推断的改进版本。 1.1 Java8以前 在下面的声明中,我们在一侧提到了arraylist的类型。这种方法是在Java 7中引入的。在这里,您可以将第二面留为<>,并且编译器将通过引用变量的类型来推断其类型。 1.2 Java8以后
TypeScript 类型检查机制包含三个部分: 类型推断 类型保护 类型兼容性 本节介绍其中的类型推断,类型推断主要用于那些没有明确指出类型的地方帮助确定和提供类型,这是 TypeScript 的一种能力。 类型推断是有方向的,要注意区分从左向右和从右向左两种推断的不同应用。 1. 慕课解释 类型推断的含义是不需要指定变量类型或函数的返回值类型,TypeScript 可以根据一些简单的规则推断其
01 模板类型推断机制 auto 推断的基础是模板类型推断机制,但部分特殊情况下,模板推断机制不适用于 auto 模板的形式可以看成如下伪代码 template<typename T> void f(ParamType x); // ParamType 即 x 的类型 调用可看成 f(expr); 编译期间,编译器用 expr 推断 T 和 ParamType,实际上两者通常不一致,比如 te
有没有办法告诉Java不要试图从使用基元类型的方法引用中推断类型? 这是我写的一个方法,原因现在无关紧要: 现在,如果您将方法引用传递给返回原始类型的“isEquals”,该怎么办? 这一切都很好,但Java也会接受这种奇怪的用法: 这是因为编译器将推断类型参数T为"