Java : 多态,包装类的面试题:
每博一文案
有人说:小孩子才会仰天大哭,成年人的世界早就调成了静音模式,连崩溃也很懂事。
一路走来,我们一边受伤,也一边变得更坚强,慢慢的不再逢人就笑了,也不再期待谁的拥抱了。
我们习惯了一边打伞一边奔跑,在没人帮的时候,学会了独立,也在没人疼的时候,学会了自愈,明白了
想要去的地方,要自己走过去。想要的安全感也只能自己给,没有人生来坚强,只是后来学会了隐藏。
听过这样的一句话,时间顺流而下,生活逆水行舟,人生不可能一帆风顺,经历过磨难在所难免。
很多时候,我们都是逼自己穿起了戎装,硬着头皮去面对,不愿在人面前露出一丝一毫的脆弱。
仿佛一旦示弱,就会被生活生吞活剥,其实这个世界上没有那么多的感同身受,有的,只是冷暖自知,你的眼泪
只有关心你的人心疼,你的笑容,也只有在乎你的人中重视,所以不要把硬抗伪装成坚强,把困难修饰成笑脸,
只为了让自己看起来还算体面。
你的眼睛很漂亮,看错人没关系,爱流眼泪也没关系,一定会有人时如珍宝。
愿你往后的每一次坚强都不是硬抗。
—————— 一禅心灵庙语
文章目录
- Java : 多态,包装类的面试题:
- 每博一文案
- 1. 多态面试题
- 2. 三目运算符
- 3. 包装类中的 Integer 缓存问题
- 4. 总结:
- 5. 最后:
1. 多态面试题
如下代码,其中的 atest.add(1,2,3);
语句执行的是 其中的 add()的哪个方法 ,执行结果又是什么???
package blogs.blog1;
public class Topic {
public static void main(String[] args) {
Test test = new Test2(); // 多态
test.add(1,2,3);
}
}
class Test{
public void add(int a,int...arr) {
System.out.println("Test:add");
}
}
class Test2 extends Test{
public void add(int a,int[]arr) {
System.out.println("Test2:add");
}
public void add(int a,int b,int c) {
System.out.println("Test: a, b, c");
}
}
解析:
执行的是
Test2 子类中重写的 add()
的方法。因为: 对于
public void add(int a,int...arr)
与public void add(int a,int[]arr)
是一样的参数列表,最后的可变参数 int…arr ,本身就是旧的数组 int[]arr ,继承关系:方法名一样,参数列表一样,符合继承重写条件,在加上继承的多态所以调用的是子类重写的 public void add(int a,int[] arr) 方法
修改一下:
如下 其中的 test2.add(1,2,3);
调用的又是哪个类中的哪个方法,执行的结果又是什么???
package blogs.blog1;
public class Topic {
public static void main(String[] args) {
Test test = new Test2(); // 多态
Test2 test2 = (Test2)test;
test2.add(1,2,3);
}
}
class Test{
public void add(int a,int...arr) {
System.out.println("Test:add");
}
}
class Test2 extends Test{
public void add(int a,int[]arr) {
System.out.println("Test2:add");
}
public void add(int a,int b,int c) {
System.out.println("Test: a, b, c");
}
}
解析:
test2.add(1,2,3);
是通过 这行代码 : Test2 test2 = (Test2)test;强制向下转型得到的,一个子类 Test2 对象的所以这里 add(1,2,3) 调用的是 Test2 子特有的 public void add(int a,int b,int c) 三个形参从方法。
2. 三目运算符
观察如下代码,思考运行结果是:什么 ???
public class Topic {
public static void main(String[] args) {
Object object = true ? new Integer(1) : new Double(2.0);
System.out.println(object);
}
}
解析:
因为对于运算: +,-,*,/ 都是需要保证两者之间是同一个数据类型才行的,如果不是的话,其中一个不符合的变量会自动提升到类型一致的情况后,再进行运算的。
同理 ? 三目运算符也是运算符,同样需要保证两者变量的一致性,所以 Integer 会自动提升至 Double 类型后,再进行运算。
结果就是 Double 类型的了,为 1.0 。
3. 包装类中的 Integer 缓存问题
请仔细阅读如下代码,查看执行的结果是 : ???
public class Topic {
public static void main(String[] args) {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println("i == j: "+(i == j));
Integer m = 1;
Integer n = 1;
System.out.println("m == n: "+(m == n));
Integer x = 128;
Integer y = 128;
System.out.println("x == y: "+(x == y));
}
}
解析:
- 第一个
i == j
的结果是 : false。因为我们使用的是 == 操作符,再加上使用的是 new 创建的实例对象,对于引用类型(除了String ) 比较的是 两个变量的地址是否相等 ,很显然地址是不同的。结果是 false
- 第二个
m == n
的结果是:true 。因为不是 new 创建的实例对象,而是通过自动装箱到包装类当中的,使用 == 比较的是两个变量的数值内容是否相等,很显然都是 1,相等,结果是 true;
- 第三个
x == y
的结果是: false。因为什么呢:这里我们使用和上面第二个自动装箱的方式,并没有 new ,按道理来说,应该也是比较的是两个变量的数值内容,返回的也应该是 true 才对,为什么返回的却是 false;
原因是:
Integer 内部定义了 IntegerCache 结构,IntegerCache 中定义了 Integer[] 保存了 从
-128~127
范围的整数,如果我们使用自动装箱的方式,给Integer赋值的范围在 -128~127范围内时,可以直接使用数组中的元素,就不用 new 了,从而提高效率。而这里的 128 自动装箱不在该[-128~127]的范围内,数组中没有该元素,就会 new 一个对象,存储该数值 128 ,new 一个实例对象,再 == 操作符,引用类型的比较的就不再是变量的数值内容了,而是变量的地址了,显然地址是不相同的。返回 false
我们在从源码上分析
private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; static { // high value may be configured by property int h = 127; String integerCacheHighPropValue = sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high"); if (integerCacheHighPropValue != null) { try { int i = parseInt(integerCacheHighPropValue); i = Math.max(i, 127); // Maximum array size is Integer.MAX_VALUE h = Math.min(i, Integer.MAX_VALUE - (-low) -1); } catch( NumberFormatException nfe) { // If the property cannot be parsed into an int, ignore it. } } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); // range [-128, 127] must be interned (JLS7 5.1.7) assert IntegerCache.high >= 127; } private IntegerCache() {} }
从源码上我们可以到 low 是为 -128 ,high 是为 127 ,我们在通过获取到的信息阅读如下代码
public static Integer valueOf(int i) { // low = -128 , high = 127 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
以发现, 当 i >= -128 && i <= 127 的时候,在该范围内时,取值是在IntegerCache.cache[] 数组中取的数值的,并不是 new 来的,在该范围内取的数值的来源是相同的,自然也就是会相等的,但是当需要取的值是超出该范围[-128~127]的时候,是return new Integer(i); 创建一个新的实例对象来的。
而在引用类型中的 == 等号,比较的就并不是数值了,而是其引用对象的地址,所以超过该范围的取值,比较时是地址,不是数值,结果就可能不相等了。
我们再比较 127 自动装箱看看,如下代码
public class Topic {
public static void main(String[] args) {
Integer x = 127;
Integer y = 127;
System.out.println("x == y: "+(x == y));
}
}
在该 [-128~127]的数组范围内,从IntegerCache.cache[] 数组中取数值,不是 new 出来的引用类型,== 操作符比较的就是两个变量的值了。
4. 总结:
- 对于
public void add(int a,int...arr)
与public void add(int a,int[]arr)
是一样的参数列表, - 对于运算: +,-,*,/ 都是需要保证两者之间是同一个数据类型才行的,如果不是的话,其中一个不符合的变量会自动提升到类型一致的情况后,再进行运算的。**?**三目运算符也是一样的
- 注意对于 Integer 包装类,自动装箱的数值如果是在 [-128~127] 范围内的话,是从 IntegerCache.cache[] 数组中取值,超过该范围的数值就是 new 创建一个实例对象,保存了。
5. 最后:
限于自身水平,其中存在的错误,希望大家给予指教,韩信点兵——多多益善,谢谢大家,后会有期,江湖再见 !!!