问题一:装箱拆箱举例
装箱拆箱的demo.java
public class Demo{
public static void main(String[] args) {
Integer i = 10;
int n =i;
}
}
看看装箱拆箱分别通过什么方法实现的?
反编译Demo.class即可知
public class Demo
{
public static void main(String[] paramArrayOfString)
{
Integer localInteger = Integer.valueOf(10);
int i = localInteger.intValue();
}
}
装箱通过:
Integer localInteger = Integer.valueOf(10);
拆箱通过:
int i = localInteger.intValue();
如果到这就结束了,也太小瞧面试官了。新的面试题是这样的。
问题二、八种基本类型的包装类中的常量池与否
进阶的demo.java
public class Main {
public static void main(String[] args) {
Integer i1 = 100;
Integer i2 = 100;
Integer i3 = 200;
Integer i4 = 200;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
答案是:true,false。原因:
看看valueOf的源码:-128到128之外,则新建对象。(注释:java1.7源码)
public static Integer valueOf(int i) {
return i >= 128 || i < -128 ? new Integer(i) : SMALL_VALUES[i + 128];
}
否则,用已经存在的对象cache的引用。常量数组SMALL_VALUES(也称常量池)引用源码如下
/**
* A cache of instances used by {@link Integer#valueOf(int)} and auto-boxing
*/
private static final Integer[] SMALL_VALUES = new Integer[256];
static {
for (int i = -128; i < 128; i++) {
SMALL_VALUES[i + 128] = new Integer(i);
}
}
可能这么看还不直观,继续看反编译进阶demo的class的代码:看到全部都用的是valueOf方法,也就是上面的源代码。
import java.io.PrintStream;
public class Demo
{
public static void main(String[] paramArrayOfString)
{
Integer localInteger1 = Integer.valueOf(100);
Integer localInteger2 = Integer.valueOf(100);
Integer localInteger3 = Integer.valueOf(200);
Integer localInteger4 = Integer.valueOf(200);
System.out.println(localInteger1 == localInteger2);
System.out.println(localInteger3 == localInteger4);
}
}
假如面试官只是为了考点是否深入其实到这儿就结束了。碰到一个较真的面试官,可能会一并问这个问题。
进阶的demo.java混淆视听代码:
public class Demo{
public static void main(String[] args) {
Double i1 = 100.0;
Double i2 = 100.0;
Double i3 = 200.0;
Double i4 = 200.0;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
答案:false,false。
长得几乎一摸一样,只是类型由Integer变成了Double。
原因:value的valueOf方法源码如下:
public static Double valueOf(double d) {
return new Double(d);
}
是不是想问为什么设计者这么变态?因为常量数量有限,可以通过常量数组去处理加快速度,而类似double,float也用-127到128范围枚举的话就太多了。
总结记住以下:(记少不记多,记住第二句!)
Integer、Short、Byte、Character、Long、Boolean有常量池。
double,float没有常量池。
问题三、boolean和Boolean的区别
遇到这么变态的面试官,赶快喊爸爸。
public class Main {
public static void main(String[] args) {
Boolean i1 = false;
Boolean i2 = false;
Boolean i3 = true;
Boolean i4 = true;
System.out.println(i1==i2);
System.out.println(i3==i4);
}
}
答案,一眼看出答案,true,true,只要不是被上面3题弄晕了。
//然而这一题不是问答案,问的是Boolean和boolean的区别。什么时候用到Boolean
反编译后的class
import java.io.PrintStream;
public class Demo
{
public static void main(String[] paramArrayOfString)
{
Boolean localBoolean1 = Boolean.valueOf(false);
Boolean localBoolean2 = Boolean.valueOf(false);
Boolean localBoolean3 = Boolean.valueOf(true);
Boolean localBoolean4 = Boolean.valueOf(true);
System.out.println(localBoolean1 == localBoolean2);
System.out.println(localBoolean3 == localBoolean4);
}
}
答案:唯一只能使用Boolean上的就是从列表或者哈希表获取值时。
比如
boolean t = false;
Map map = new HashMap();
map.put("t", t);
那么获取值时只能用Boolean t1 = (Boolean) map.get(t); //前面只能用Boolean强制转换,不能使用boolean。
简而言之:
也就是需要强制类型转换的时候。
问题四、衍生的String的问题:
如果以上都问了,问到这题,面试官,请收下我的膝盖。你肯定是因为我长得太帅,而针对我!
public class Demo{
public static void main(String[] args) {
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);//输出false
System.out.println(s1.equals(s2));//输出true
String s3 = "hello";
String s4 = "hello";
System.out.println(s3 == s4);//输出true
System.out.println(s3.equals(s4));//输出true
}
}
这题,作为一个资深面试官,我会问
答案是什么?
1. equals和==的区别?
2. String的equals方法和hashcode方法的源码是否阅读过?
如果还没晕的话,首先需要知道String是一个基本数据类型。那么这题不再是考包装类了。而是考基本数据类型和引用数据类型。了解这点,已经赢了一大半。
==比较:比较值是否相等。
equals的定义比较复杂:
单看String的equals方法源码如下:
@Override public boolean equals(Object other) {
if (other == this) {
return true;
}
if (other instanceof String) {
String s = (String)other;
int count = this.count;
if (s.count != count) {
return false;
}
if (hashCode() != s.hashCode()) {
return false;
}
for (int i = 0; i < count; ++i) {
if (charAt(i) != s.charAt(i)) {
return false;
}
}
return true;
} else {
return false;
}
}
第2行,比较是否同一个对象。如果是则返回true。
第5行,先比较字符串的长度,然后比较字符串的hashcode(如果hashcode不相等,则字符串一定不相等。反过来则需要继续判断)。最后比较每个位置的字符的值。
看看String的hashCode方法:
初始是0,每次(原累计数hash)*31 加上当前位置字符的ASCII码,比如h字符的ASCII码是104。循环累加。得到hash值。
@Override public int hashCode() {
int hash = hashCode;
if (hash == 0) {
if (count == 0) {
return 0;
}
for (int i = 0; i < count; ++i) {
hash = 31 * hash + charAt(i);
}
hashCode = hash;
}
return hash;
}
结论来了,如果
两个一模一样的字符串,它的hashcode必然是一样的。而hashcode一样,却不一定是同一个字符串。
为什么呢?
第一句的原因,原因是因为如果字符串相同,同一个算法,那么累积和必然是一个一摸一样的数值。比如“hello”,和“hello”。所以在比较字符串值是否相等的时候先比较hashcde是否一样,能加快比较速度。(因为比较一个数值肯定比挨个比较字符串要快)
第二句的原因,举个栗子“hello” 和 “hlleo”按照上面的算法,hashcode值是一样的,而事实不是同一个字符串。所以仍然需要继续比较下去。
先码到这,下波继续java。