存档

文章标签 ‘重载’

关于Java的一些编译机制

2009年10月26日 低调の华丽 没有评论

No.1 前几天在JavaEye上看到有人讨论Java对String常量优化的问题,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package test;
 
public class TestA {
	public static void main(String[] args) {
                String s="ab";
		String s1="a";
		String s2="b";
		String s3=s1+s2;
		String s4="a"+"b";
		System.out.println(s3==s4);
		System.out.println(s3=="ab");
		System.out.println(s4=="ab");
	}
}

结果:false
false
true

s3和s4虽然值相同,但是显然s3和s4并没有指向同一个String常量池中的String常量。String s4=”a”+”b”;,字符串连接的行为是在编译期间,编译器给优化了。而String s3=s1+s2;中的字符串连接是在代码运行期间进行的。这也间接的说明一个问题,就是String常量池在代码运行前就已经分配好了,代码运行时生成的String对象不会增加到String常量池中。因为s4指向的对象是在代码运行时新生成的对象,所以s3和s4没有指向同一个对象。

推荐这篇文章《Java编译器对于String常量表达式的优化

No.2 Java编译涉及到的基本变量的问题。下面的代码

1
2
3
4
5
6
7
8
9
10
11
package test;
 
public class TestA {
	public static void main(String[] args) {
		short s=10;//这行代码可以通过编译
		new TestA().go(11);//无法通过编译,需要进行类型转换
	}
	short go(short s){
		return 12;//可以通过编译
	}
}

之前我一直无法理解为什么第5行和第9行可以通过编译,第6行不能通过编译,需要进行强制类型转换。因为这三行同样都是基本变量赋值的问题。后来我发现,这里面涉及到一个重载的问题。比如下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package test;
 
public class TestA {
	public static void main(String[] args) {
		short s=10;
		new TestA().go(11);//go方法会取调用最匹配的重载方法
	}
 
	short go(short s){
		return 12;
	}
//	short go(int i){
//		return 12;
//	}
	short go(long l){
		return 12;
	}
}

在go(int i)的方法注释掉之前,自然会调用go(int i)方法,注释掉之后,g(11)会调用最匹配的重载方法,而11既可以赋值给short型(强制类型转换),也可以赋值给long型(隐式类型转换),这是不可能的,不存在两个重载方法都匹配的情况,那样的话编译器无法知道真正要调用的方法到底是哪个。所以编译器无法为你主动做强制类型转换,,只能调用go(long l)方法。所以java规定第6行那样的情况需要做强制类型转换。

分类: Java 标签: , , ,