面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

介绍

享元模式

享元模式可以减少创建对象的数量,从而减少内存占用。享元模式本质上就是一个对象池,利用享元模式创建对象的逻辑也很简单,创建之前,首先去对象池里看看是不是存在;如果已经存在,就利用对象池李的对象,如果不存在,就会新创建一个对象,并且把这个新创建出来的对象放进线程池里。

为什么要有常量池?

常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。

例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。

(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。

(2)节省运行时间:比较字符串时,== 比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

基本数据类型的包装类和常量池

Java有8种基本数据类型

整数类型:byte,short,int,long。包装类型为Byte,Short,Integer,Long

浮点类型:float、double。包装类型为Float,Double

字符类型:char。包装类型为Character

布尔类型:boolean。包装类型为Boolean

8种包装类型中除了Float,Double没有实现常量池,剩下的都实现了

为了更方便理解后面的内容,这里先解释一下自动装箱和拆箱

自动装箱和拆箱

自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。因为这里的装箱和拆箱是自动进行的非人为转换,所以就称作为自动装箱和拆箱

自动装箱时编译器调用valueOf将原始类型值转换成对象,同时自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成原始类型值

<code>// jdk1.5 之前的写法
Integer tempNum1 = Integer.valueOf(5);
int num1 = tempNum1.intValue();
// jdk1.5之后的写法
Integer tempNum2 = 5;
int num2 = tempNum2;/<code>

Integer类常量池

这个是我原来面试问到的一个问题,让我判断如下代码的输出,并解释原因

<code>Integer a1 = 40;
Integer a2 = 40;
// true
System.out.println(a1 == a2);
Integer a3 = 200;
Integer a4 = 200;
// false
System.out.println(a3 == a4);/<code>

由自动装箱和拆箱可以知道这2种写法是等价的

<code>Integer a1 = 40;
Integer a1 = Integer.valueOf(40);/<code>

看一下Integer的valueOf方法

<code>public static Integer valueOf(int i) {
// i的取值范围为[-128,127]
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}/<code>

IntegerCache是Ingeter的静态内部类,默认创建了[-128,127]的对象,并放到IntegerCache内部的一个cache数组中,在[-128,127]这个范围内的整数对象,不用创建。直接从IntegerCache中的cache数组中根据下标拿就可以,超出这个范围的每次去创建新的对象。其他几种包装类型的常量池和Integer思路都差不多,源码都很相似。

因此a1和a2指向的是同一个对象,a3和a4指向的是不同的对象

<code>Integer i1 = 40;
Integer i2 = 40;
Integer i3 = 0;
Integer i4 = new Integer(40);
Integer i5 = new Integer(40);
Integer i6 = new Integer(0);
// true
System.out.println(i1 == i2);
// true
System.out.println(i1 == i2 + i3);
// false
System.out.println(i1 == i4);
// false
System.out.println(i4 == i5);
// true
System.out.println(i4 == i5 + i6);
// true
System.out.println(40 == i5 + i6);/<code>

解释:语句i4 == i5 + i6,因为+这个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较

String类和常量池

字符串常量池放在哪?

jdk1.7之前的不讨论,从jdk1.7开始,字符串常量池就开始放在堆中

下面这个代码初学者还是经常被问到的

<code>String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
String str4 = new String("abc");
// true
System.out.println(str1 == str2);
// false
System.out.println(str1 == str3);
// false
System.out.println(str3 == str4);/<code>

内存中的结构如下

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

其中常量池中存的是引用,引用一下R大在知乎上的解释

如果您说的确实是runtime constant pool(而不是interned string pool / StringTable之类的其他东西)的话,其中的引用类型常量(例如CONSTANT_String、CONSTANT_Class、CONSTANT_MethodHandle、CONSTANT_MethodType之类)都存的是引用,实际的对象还是存在Java heap上的。

解释一下上面代码的输出,Java中有2种创建字符串对象的方式

<code>String str1 = "abc";
String str2 = "abc";
// true
System.out.println(str1 == str2);/<code>


采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"abc"这个对象

如果不存在,则在字符串池中创建"abc"这个对象,然后将池中"abc"这个对象的地址赋给str1,这样str1会指向池中"abc"这个字符串对象

如果存在,则不创建任何对象,直接将池中"abc"这个对象的地址返回,赋给str2。因为str1、str2指向同一个字符串池中的"abc"对象,所以结果为true。

<code>String str3 = new String("abc");
String str4 = new String("abc");
// false
System.out.println(str3 == str4);/<code>


采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"abc"这个字符串对象,

如果没有,则首先在字符串池中创建一个"abc"字符串对象,然后再在堆中创建一个"abc"字符串对象,然后将堆中这个"abc"字符串对象的地址赋给str3

如果有,则不在池中再去创建"abc"这个对象了,直接在堆中创建一个"abc"字符串对象,然后将堆中的这个"abc"对象的地址赋给str4。这样,str4就指向了堆中创建的这个"abc"字符串对象;

因为str3和str4指向的是不同的字符串对象,结果为false。

Java面试手册

目录

一、性能优化面试专栏

1.1、tomcat性能优化整理

1.2、JVM性能优化整理

1.3、Mysql性能优化整理

二、微服务架构面试专栏

2.1、SpringCloud面试整理

2.2、SpringBoot面试整理

2.3、Dubbo面试整理

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

三、并发编程高级面试专栏

四、开源框架面试题专栏

4.1、Spring面试整理

4.2、SpringMVC面试整理

4.3、MyBatis面试整理

五、分布式面试专栏

5.1、分布式限流面试整理

5.2、分布式通讯面试整理

5.3、分布式数据库面试整理

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

面试官:Integer a1 = 40;Integer a2 = 40;a1 == a2吗?

有需要获取面试体系文档的朋友可以转发文章并关注作者,然后私信回复“Java面试”即可获得以上所有面试PDF文档资料的领取方式!以前没获取到的粉丝或者小伙伴们都可以获取参考哦

如何获取?

转发这篇文章,关注我,私信回复“java面试”即可获取高清大纲,以上 spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构

如何私信?

关注我后,在手机,点进头像进我的主页,主页上方右上角有个私信,点击私信,如何回复关键字“java面试”即可



分享到:


相關文章: