挑战4道Java试题
来源:互联网 发布:婚纱照排版台词 知乎 编辑:程序博客网 时间:2024/05/23 13:15
本文概要
这两天网上看了几道有意思的Java试题,都是新鲜的知识, 之前可能没有注意过的问题。
- 本文概要
- 一符的使用
- 二String
- 三final关键字
- 四Integer与int那些事
- 参考资料
一、==
符的使用
首先看一段比较有意思的代码
public class Main { public static void main(String[] args){ Integer a=1000, b=1000; Integer c=100, d=100; System.out.println(a==b); System.out.println(c==d); }}
运行结果:
falsetrue
我们知道==比较的是两个对象的引用,这里的abcd都是新建出来的对象,按理说都应该输入false才对。这就是这道题的有趣之处,无论是面试题还是论坛讨论区,这道题的出场率都很高。原理其实很简单,我们去看下Integer.java这个类就了然了。
JDK1.7.0_79
/**as this method is likely to yield significantly better space and time performance by* caching frequently requested values.** This method will always cache values in the range -128 to 127,* inclusive, and may cache other values outside of this range.*/ public static Integer valueOf(int i) { assert IntegerCache.high >= 127; if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }
IntegerCache 为 Integer.java 中的内部静态私有类。
/** * Cache to support the object identity semantics of autoboxing for values between * -128 and 127 (inclusive) as required by JLS. * * The cache is initialized on first usage. The size of the cache * may be controlled by the -XX:AutoBoxCacheMax=<size> option. * During VM initialization, java.lang.Integer.IntegerCache.high property * may be set and saved in the private system properties in the * sun.misc.VM class. */ 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) { 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); } high = h; cache = new Integer[(high - low) + 1]; int j = low; for(int k = 0; k < cache.length; k++) cache[k] = new Integer(j++); } private IntegerCache() {} }
当我们声明一个 Integer c = 100;
的时候。此时会进行自动装箱操作,简单点说,也就是把基本数据类型转换成Integer对象,而转换成Integer对象正是调用的valueOf
方法,可以看到,Integer中把 -128到127 之间的所有数字 一共256个Integer对象 缓存了下来。
官方解释是小的数字使用的频率比较高,所以为了优化性能,把这之间的数缓存了下来。
这就是为什么这道题的答案回事false和ture了。当声明的Integer对象的值在-128到127之间的时候,引用的是同一个对象,所以结果是true。
二、String
接着看代码
String s1 = "abc"; String s2 = "abc"; String s3 = new String("abc"); System.out.println(s1 == s2); System.out.println(s1 == s3);
大家又来猜一猜这道题的答案是什么?
按照==的语法来看, 首先s1、s2、s3是三个不同的对象,常理来说,输出都会是false。然而程序的运行结果确实true、false。
第二个输出false可以理解,第一个输出true就又让人费解了。我们知道一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,而堆内存中则存放new 出来的对象和数组。
然而除此之外还有一块区域叫做常量池。像我们通常想String s1 = “abc”; 这样申明的字符串对象,其值就是存储在常量池中。
当我们创建String s1 = “abc”这样一个对象之后,”abc”就存储到了常量池(也可叫做字符串池)中,当我们创建引用String s2 = “abc” 的时候,Java底层会优先在常量池中查找是否存在”abc”,如果存在则让s2指向这个值,不会重新创建,如果常量池中没有则创建并添加的池中。这就是为什么答案是true 和false的原因。
三、final关键字
还是来看一段代码
public void mRun(final String name){ //Runnable内部类 new Runnable() { public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 内部类访问局部变量 name System.out.println(name); } }.start(); }
当内部类访问局部变量的时候,需要在局部变量前加final修饰符,不然编译器就会报错。
通常我们也是这么干的。好的,第二个问题来了,为什么要加final修饰符?
现在我们来分析一下,为什么要加final关键字。首先内部类的生命周期是成员级别的,而局部变量的生命周期实在方法体之内。
也就是说会出现这样一种情况,当mRun方法执行,new 的线程运行,新线程里面会睡一秒。主线程会继续执行,mRun执行完毕,name属性生命周期结束。1秒之后,Syetem.out.printh(name)执行。然而此时name已经寿终正寝,不在内存中了。
Java就是为了杜绝这种错误,严格要求内部类中局部变量,必须使用final关键字修饰。局部变量被final修饰之后,此时会在内存中保有一份局部变量的复制品,当内部类访问的时候其实访问的是这个复制品。这就好像是把局部变量的生命周期变长了。
四、Integer与int那些事
看下面代码
Integer a = new Integer(1000); int b = 1000; Integer c = new Integer(10); Integer d = new Integer(10); System.out.println(a == b); System.out.println(c == d);
运行结果:
truefalse
先来说下第二个,按第一题来说Integer不是把-128到127缓存起来了吗?
这不是应该是true嘛,但是你仔细看,这里的Integer是我们自己new出来的,并不是用的缓存,所以结果是false。
现在来看第一个为啥又是true了呢?
首先这里的值为1000,肯定和我们所知的Integer缓存没有关系。既然和缓存没有关系,a是新new出来的对象,按理说输入应该是false才对。但是注意b这里是int类型。当int和Integer进行==比较的时候,Java会把Integer进行自动拆箱,也就是把Integer转成int类型,所以这里进行比较的是int类型的值,所以结果即为true。
参考资料
https://yq.aliyun.com/ziliao/158464?spm=5176.8246799.blogcont.31.j0yF8r
- 挑战4道Java试题
- 170道Java工程师面试题,你敢挑战吗?
- 100.第 4 组微软面试题,挑战思维极限
- 20个高级Java面试题汇总,你要来挑战吗?
- 微软面试题公开 “挑战”就是秘密武器
- [绝对挑战]IBM公司的面试题
- 微软面试题公开 “挑战”就是秘密武器
- 挑战:数据提取(2016tabfun面试题)
- 4强挑战虽然建立分布式Java应用程序
- java百道试题
- Java面试题(4)
- java面试题4
- JAVA面试题4
- 黑马Ruby能否挑战Java
- Java IOC框架 挑战Spring
- 编程挑战(4)
- 4-1编程挑战
- 挑战
- 基于ODPS的SQL语句
- 设计模式之原型模式
- Lorg/apache/ws/commons/schema/XmlSchema;
- Dubbo-Admin管理平台和Zookeeper注册中心的搭建
- exe4j生成的exe反编译成java代码
- 挑战4道Java试题
- WebView 如何自定义自己的右键菜单?
- 使用setInterval对ajax请求做轮询
- 同步与异步、阻塞与非阻塞
- CSDN--字体颜色--markdown
- C
- ABAP报表事件说明
- Android Studio 如何打JAR包
- UGUI 圆角矩形控件实现