您的位置:首页 > 职场人生

[置顶] 【面试题】java装箱拆箱引发的思考

2016-12-04 15:55 796 查看

问题一:装箱拆箱举例

装箱拆箱的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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: