我是否破坏了Java';s局部变量类型推断?

我是否破坏了Java';s局部变量类型推断?,java,type-inference,Java,Type Inference,我编写了一个方法,该方法“典型化”一个字符串,并试图推断其中包含的数据类型。(略加修改的版本)。该方法返回一个数组中推断的类和原始的字符串(可能稍有修改——周围的空格被修剪,等等)。例如,typeify(“3f”)返回,typeify(“c”)返回等等 我的下一步是编写第二个方法,该方法“解码”这些返回的Map.Entry对象,以便将它们直接分配给推断类型的对象。例如: Float f=decodeTypify(典型化(“3.14f”)) 布尔b=解码类型化(类型化(“假”)) ……等等。该代

我编写了一个方法,该方法“典型化”一个
字符串
,并试图推断其中包含的数据类型。(略加修改的版本)。该方法返回一个数组中推断的
和原始的
字符串
(可能稍有修改——周围的空格被修剪,等等)。例如,
typeify(“3f”)
返回
typeify(“c”)
返回
等等

我的下一步是编写第二个方法,该方法“解码”这些返回的
Map.Entry
对象,以便将它们直接分配给推断类型的对象。例如:

Float f=decodeTypify(典型化(“3.14f”))
布尔b=解码类型化(类型化(“假”))
……等等。该代码如下:

@SuppressWarnings(“未选中”)
公共静态解码T类型化(条目){
//串
if(entry.getKey()==String.class)
return(T)entry.getValue();
//布尔值
else if(entry.getKey()==Boolean.class)
return(T)(Boolean)Boolean.parseBoolean(entry.getValue());
//字节
else if(entry.getKey()==Byte.class)
返回(T)(Byte)Byte.parseByte(entry.getValue());
//性格
else if(entry.getKey()==Character.class)
return(T)(Character)entry.getValue().charAt(0);
//短
else if(entry.getKey()==Short.class)
return(T)(Short)Short.parseShort(entry.getValue());
//整数
else if(entry.getKey()==Integer.class)
返回(T)(整数)Integer.parseInt(entry.getValue());
//长的
else if(entry.getKey()==Long.class)
return(T)(Long)Long.parseLong(entry.getValue());
//浮动
else if(entry.getKey()==Float.class)
return(T)(Float)Float.parseFloat(entry.getValue());
//双重的
else if(entry.getKey()==Double.class)
return(T)(Double)Double.parseDouble(entry.getValue());
//LocalDateTime
else if(entry.getKey()==LocalDateTime.class)
return(T)(LocalDateTime)stringAsDate(entry.getValue());
否则返回null;
}
这似乎非常有效,尤其是与Java新的局部变量类型推断相结合时:

var f=decodeTypify(典型化(“字面上的任何东西”))
现在我根本不需要关心返回的类型,因为Java负责为
f
提供正确的类型。但是请注意,如果
decodeTypify()
entry
参数的键与大
if else
树中的任何选项都不匹配,则
decodeTypify()
返回
null
。以下是使用Java 11.0.1在jshell中运行的方法:

jshell>var x=decodeTypify(typing(null))
x==>null
我给一个本地类型推断变量分配了一个
null
值!这这(似乎)的一个副作用是,我实际上可以告诉
x
有任何类型,而没有任何警告:

jshell>objectx=decodeTypify(typing(null))
x==>null
jshell>String x=decodeTypify(typeify(null))
x==>null
jshell>Byte x=decodeTypify(typing(null))
x==>null
请注意,非空返回的情况并非如此:

jshell>var x=decodeTypify(typeify(“3”))
x==>3.0
jshell>booleanX=decodeTypify(typing(“3”))
|异常java.lang.ClassCastException:无法将类java.lang.Double转换为类java.lang.Boolean(java.lang.Double和java.lang.Boolean位于加载程序“bootstrap”的模块java.base中)
|在(21:1)

我打碎了什么东西吗?如果没有,有人能解释一下这里发生了什么吗?

你没有弄坏任何东西。您不能直接分配null,但是通过方法调用间接分配null是完全可以的

原因是,仅通过赋值
null
编译器就没有信息知道您想要什么类型。唯一可以进行的推断是针对最通用的类型,
Object
,如果这是正确的推断,那么就显式地声明它!这是3个额外的字符

当编译器有方法调用要使用时,它可以使用方法的返回类型进行类型推断

public static String foo() {
    return null;
}

public static <T> T bar() {
    return null;
}

public static <T> T baz(Class<T> clazz) {
    return null;
}

public static void main(String[] args) {
   var a = null;  // compile error
   var b = foo(); // fine
   var c = bar(); // fine
   var d = baz(String.class); //fine
}
公共静态字符串foo(){
返回null;
}
公共静态T形条(){
返回null;
}
公共静态T baz(类clazz){
返回null;
}
公共静态void main(字符串[]args){
var a=null;//编译错误
var b=foo();//很好
var c=bar();//很好
var d=baz(String.class);//很好
}

您可以将空值分配给本地类型推断变量。您不能使用空初始值设定项实例化此类变量

我检查了您引用的gist,很明显,如果您在输入中为方法'null'(值,而不是字符串),那么它将设置对象类型。您正在初始化一个空对象,这是“var”可以处理的。至少,编译器知道您正在使用对象类。另外,一个方法将有一个返回类型,所以var也可以使用它


至于类型分配切换副作用的东西强制使用null总是有效的,所以泛型处理得很好也就不足为奇了:

在我看来,你的
类型化
比你给出的
解码类型化
更重要。我看不出有什么问题,你不能从null推断类型,但你可以使用null。字符串b=null;var c=b;这是有效的,c是一个字符串。我执行的
字节x=decodeTypify(typeify(null))
的位呢?该方法返回
null
,因为该方法的返回签名是
T
,并且我将其分配给
Byte
类型的对象,所以Java创建了
null Byte
对象?是这样吗?“Java创建了一个
null字节
对象”是的。为什么这么奇怪?不奇怪,只是想知道编译器是如何确定的