【面试题】java装箱拆箱引发的思考

    xiaoxiao2021-12-14  22

    问题一:装箱拆箱举例

    装箱拆箱的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。

    转载请注明原文地址: https://ju.6miu.com/read-964226.html

    最新回复(0)