今天在百度上看到这么一个问题,大家来分析一下是什么原因public class Test {
public static void go(List list)
{
list.add(1.1);
}
public static void main(String args[])
{
List<String> list=new ArrayList<String>();
list.add("1");
go(list);
System.out.println(list.get(1));
}
}
以上代码编译通过,运行出错,很好理解但public class Test {
public static void go(List list)
{
list.add("1.1");
}
public static void main(String args[])
{
List<Integer> list=new ArrayList<Integer>();
list.add(1);
go(list);
System.out.println(list.get(1));
}
}
这段代码却可以通过编译也可以运行,何解?
public static void go(List list)
{
list.add(1.1);
}
public static void main(String args[])
{
List<String> list=new ArrayList<String>();
list.add("1");
go(list);
System.out.println(list.get(1));
}
}
以上代码编译通过,运行出错,很好理解但public class Test {
public static void go(List list)
{
list.add("1.1");
}
public static void main(String args[])
{
List<Integer> list=new ArrayList<Integer>();
list.add(1);
go(list);
System.out.println(list.get(1));
}
}
这段代码却可以通过编译也可以运行,何解?
{
list.add("1.1");
}
这个方法里也要用泛型.
public static void go(List<Integer> list)
{
list.add(1.1);
}
{
list.add("1.1");
}
这样没问题啊
System.out.println(i.toString());这样子就会报错。Exception in thread "main" java.lang.NumberFormatException: For input string: "1.1"
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.<init>(Unknown Source)
at test.Test.main(Test.java:29)
第一段代码掉用的是
void println(String x)
而list.get(1)返回的是一个Double对象,所以会报错。第二段代码掉用的是
void println(Object x)
list.get(1)返回的是一个String对象,而String类继承自Object,所以没问题。
我试过System.out.println(list.get(1)); 改成System.out.println(list.get(1).toString());或System.out.println((String)list.get(1));
还是不行,而且即使把list.get(1).toString()或(String)list.get(1)单独拿出来执行也是错的,除非:
Object o = list.get(1);
System.out.println(o);
这又搞不懂了。
无论何时,将一个对象强转成String类型,都是不可取的。因为 1) 如果该对象本来就是一个String对象,那么强转就是画蛇添足了。2)如果该对象不是String对象,则强转一定会失败,因为String是final类,不能被继承。再来看System.out.println(list.get(1).toString());
当编译器看到这行代码是,它要做的一项工作是确定list.get(1)的返回值类型,由于在前面有了形如 List <String> list=new ArrayList <String>() 的声明,编译器认为list.get(1)会返回一个String对象,因此这里调用的是String类中的toString()方法。而在运行时list.get(1)返回的实际上是一个Double对象,故而出错。
public E get(int index) {
RangeCheck(index);
return (E) elementData[index]; // 这里把Double直接转成String
}相当于:
Double d = 1.1;
String str = (String) d;
当然是要报错的
1、当范型参数为String时,也就是程序中的List<String>时,System.out实际调用的是System.out.println(String)这个方法
所以当list.add(1.1)后,取list.get(1)实际是一个Double,然后System.out.println(String)要把Double强制转换为String
类型自然会抛出类型转化异常。
2、那范型参数是Integer或者别的对象时,也就是List<Integer>时,为什么没有出现异常呢?
这是因为System.out现在实际调用的是System.out.println(object)。要明白System.out.println(object)实际执行的是
System.out.println(String.valueof(object));所以这个问题就是在println方法调用,跟范型实际没什么关系。
这位哥,为什么
String s="1.1";
Integer i=(Integer)s;
不报错呢????
public static void go(List list)
{
list.add(1.1); 是double类型的
}
下面的代码
public static void go(List list)
{
list.add("1.1"); 这个事string
}
你的list定义式String的泛型
第一种情况
public static void main(java.lang.String[] args);
0 new java.util.ArrayList [34]
3 dup
4 invokespecial java.util.ArrayList() [36]
7 astore_1 [list]
8 aload_1 [list]
9 ldc <String "1"> [37]
11 invokeinterface java.util.List.add(java.lang.Object) : boolean [24] [nargs: 2]
16 pop
17 aload_1 [list]
18 invokestatic reflect.Test.go(java.util.List) : void [39]
21 getstatic java.lang.System.out : java.io.PrintStream [41]
24 aload_1 [list]
25 iconst_1
26 invokeinterface java.util.List.get(int) : java.lang.Object [47] [nargs: 2]
31 checkcast java.lang.String [51]
34 invokevirtual java.io.PrintStream.println(java.lang.String) : void [53]
37 return
第二种情况
public static void main(java.lang.String[] args);
0 new java.util.ArrayList [28]
3 dup
4 invokespecial java.util.ArrayList() [30]
7 astore_1 [list]
8 aload_1 [list]
9 iconst_1
10 invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [31]
13 invokeinterface java.util.List.add(java.lang.Object) : boolean [18] [nargs: 2]
18 pop
19 aload_1 [list]
20 invokestatic reflect.Test1.go(java.util.List) : void [37]
23 getstatic java.lang.System.out : java.io.PrintStream [39]
26 aload_1 [list]
27 iconst_1
28 invokeinterface java.util.List.get(int) : java.lang.Object [45] [nargs: 2]
33 invokevirtual java.io.PrintStream.println(java.lang.Object) : void [49]
36 return第一种情况调用的是java.io.PrintStream.println(java.lang.String),而且在前面进行了一个String的类型检查checkcast java.lang.String [51]第二种情况调用的是 java.io.PrintStream.println(java.lang.Object),没做类型检查
下面是参数为string的时候
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
当为基本类型时,print的实现方式
public void print(int i) {
write(String.valueOf(i));
} public void print(long l) {
write(String.valueOf(l));
} public void print(float f) {
write(String.valueOf(f));
} ...... public void print(Object obj) {
write(String.valueOf(obj));
}
我想大家应该已经看明白了,当是string的时候要判断一下,因此第一种范型为string时要做类型检查,而第二种编绎器将自作主张地调用了能用的print(Object obj)这个方法了,这样作有啥好处呢,因为少了一步装箱拆箱的工作
和26楼看字节码达到同样的效果。前提是你要有jdk的原文件。
{
list.add("1.1");
}
这个方法里也要用泛型.
public static void go(List <Integer> list)
{
list.add(1.1);
}
如:
public static void go(List<String> list) //List<String>
{
list.add("1.1");
}
public static void main(String args[])
{
List <String> list=new ArrayList <String>();
list.add("1");
go(list);
System.out.println(list.get(1));
}
{
list.add("1.1");
} 这个有什么错????