var 省掉了类型声明,但推断出的类型有时出人意料:钻石、通配符、条件表达式、匿名类。这篇用 javac 报错信息反推每一个例子的推断类型,再验证 var 在哪些位置不能用、字节码里有没有 var。
var x = 1; → int
var x = 1L; → long
var x = 1.5f; → float
var x = 'c'; → char
var x = "s"; → String
var x = new ArrayList<String>(); → ArrayList<String>
var x = new ArrayList<>(); → ArrayList<Object>
var x = List.of(1, 2, 3); → List<Integer>
var x = List.of(1, "a"); → List<INT#1> ;INT#1 extends Object,Serializable,Comparable<? extends INT#2>,Constable,ConstantDesc ;INT#2 extends Object,Serializable,Comparable<?>,Constable,ConstantDesc
var x = Arrays.asList(1, 2.5); → List<INT#1> ;INT#1 extends Number,Comparable<? extends INT#2>,Constable,ConstantDesc ;INT#2 extends Number,Comparable<?>,Constable,ConstantDesc
var x = wl.get(0); → Number
var x = wl; → List<CAP#1> ;CAP#1 extends Number from capture of ? extends Number
var x = m.get("k"); → List<Integer>
var x = m.entrySet().iterator().next(); → Entry<String,List<Integer>>
var x = true ? 1 : "s"; → INT#1 ;INT#1 extends Object,Serializable,Comparable<? extends INT#2>,Constable,ConstantDesc ;INT#2 extends Object,Serializable,Comparable<?>,Constable,ConstantDesc
var x = true ? new A() : new B(); → INT#1 ;INT#1 extends Object,I,Serializable
var x = new Object() { int n = 1; }; → <anonymous Object>
var x = (Runnable & Serializable) () -> {}; → INT#1 ;INT#1 extends Object,Runnable,Serializable
var x = Optional.empty(); → Optional<Object>
var x = new int[]{1, 2}; → int[]
var x = (byte) 1; → byte
byte b0 = 1; var x = b0 + b0; → int
var x = 1 / 2.0; → double
var x = Collections.emptyList(); → List<Object>
var x = (Comparable<String>) "s"; → Comparable<String> var x = null; (局部变量初始化为 null)→ cannot infer type for local variable x
var x; (没有初始化器)→ cannot infer type for local variable x
var x = {1, 2}; (数组初始化器)→ cannot infer type for local variable x
var x = () -> {}; (lambda)→ cannot infer type for local variable x
var x = String::length; (方法引用)→ cannot infer type for local variable x
var x = 1, y = 2; (同一条语句声明多个)→ 'var' is not allowed in a compound declaration
var x[] = new int[1]; (var 与数组括号)→ 'var' is not allowed as an element type of an array
var x = x + 1; (自引用)→ cannot infer type for local variable x
var[] x = new int[1]; (var[])→ 'var' is not allowed as an element type of an array
class T { var f = 1; } (字段)→ 'var' is not allowed here
class T { var m() { return 1; } } (方法返回类型)→ 'var' is not allowed here
class T { void m(var p) {} } (方法参数)→ 'var' is not allowed here
class var {} (类型名 var)→ 'var' not allowed here
class T { void f() { int var = 1; var var = 2; } } (变量名叫 var)→ variable var is already defined in method f()
class T { void f() { try (var r = new java.io.StringReader("x")) { } } } (try-with-resources)→ 通过
class T { void f() { for (var i = 0; i < 1; i++) {} for (var s : java.util.Lis (for 循环)→ 通过
class T { void f() { java.util.function.BiFunction<Integer,Integer,Integer> g (lambda 参数用 var)→ 通过
class T { void f() { java.util.function.BiFunction<Integer,Integer,Integer> g (lambda 参数部分用 var)→ invalid lambda parameter declaration
class T { void f() { Object o = 1; if (o instanceof var x) {} } } (instanceof var)→ 'var' is not allowed here使用 var 与显式类型的两份源码编译出的 T.class:字节数 611 / 611;完全相同 = True 加 -g(保留局部变量表)后:相同 = True(var 的类型被写成它推断出的具体类型,局部变量表里没有 var 这个词) var 版本 -g 后的 LocalVariableTable: 0 5 0 this LT; | 43 7 3 v Ljava/lang/Integer; | 8 47 0 l Ljava/util/ArrayList; | 19 36 1 s I
var l1 = new ArrayList<>() 的元素类型是 Object:可以同时加入 Integer 与 String → [1, s]
对照 List<String> l2 = new ArrayList<>():元素类型 String
who(cs)(声明类型 CharSequence)→ CharSequence;var cs2 = cs;who(cs2) → CharSequence(var 保留的是右边表达式的静态类型)
var d = make()(返回 Animal)→ d 的静态类型是 Animal,不是 Dog:d.getClass() 是 Dog,但编译期只能调用 Animal 的方法
var anon = new Object() { int hits = 3; … } 可以访问匿名类的成员:anon.hits = 4
var lst = List.of(1, 2.5, 3L) 的元素静态类型是 Number & Comparable<…>;第一个元素的运行时类型 Integer
var cond = true ? 1 : 2.0 的类型是 double(数值提升):值 = 1.0,类型 = Double
var half = i / 4 → 2(int);var halfD = i / 4.0 → 2.5(double)
var chars → char[];var bytes → byte[]
var x = 100_000_000; var y = x * 100 → 1410065408(int 溢出,var 没有帮你换成 long)