目录:

  1. 自动装箱与拆箱
  2. 常量池
  3. ==与equals()区别

  1. 自动装箱与拆箱

  Java是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java为每一个基本数据类型都引入了对应的包装类型(wrapper class),如int的包装类就是Integer,从Java 5开始引入了自动装箱/拆箱机制,使得二者可以相互转换。 
Java 为每个基本类型提供了包装类型: 

  • 原始类型: boolean,char,byte,short,int,long,float,double
  • 包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

  首先看一个简单例子:

 public class AutoUnboxingTest {
public static void main(String[] args) {
Integer a = new Integer(3);
Integer b = 3; // 将3自动装箱成Integer类型
int c = 3;
System.out.println(a == b); // false 两个引用没有引用同一对象
System.out.println(a == c); // true a自动拆箱成int类型再和c比较 Integer f1 = 3, f2 = 3, f3 = 150, f4 = 150;
System.out.println(f1 == f2);//true
System.out.println(f3 == f4);//false Integer p1 = new Integer(3);
Integer p2 = new Integer(3);
Integer p3 = new Integer(0);
System.out.println(p1 == p2);//false,两个不同的对象
System.out.println(p1 == p2+p3); //true p2和p3自动拆箱为int类型,p1也会自动拆箱,本质为基本数据类型比较
}
}

  用new关键字创建一个新对象,它们的内容可以相同,但其内存中存放的地址不同。而==对对象来说,是比较的内存地址,不同的对象自然不同,故(a、b)(p1、p2)比较为false。那么f1、f2、f3、f4四个变量都是Integer对象引用,为什么会出现一个false一个true呢?这就涉及装箱的本质,当我们给一个Integer对象赋一个int值的时候,会调用Integer类的静态方法valueOf,想知道发生了什么,直接上源码:

 /**
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, 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.
*
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
*/
public static Integer valueOf(int i) {
assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
19 return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

  其调用了Integer的内部类IntegerCache,源码如下:

 /**
* 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;
27 cache = new Integer[(high - low) + 1];
28 int j = low;
29 for(int k = 0; k < cache.length; k++)
30 cache[k] = new Integer(j++);
}
private IntegerCache() {}
}

  源码中标红的部分是重点,在第一次自动装箱时,程序即会创建[-128 ~ 127]区间的Integer,存在cache数组中,并且数组和256个Integer对象都在堆内存中。所有在该区间的比较对应结果为true,故(f1、f2)为true;超出该区间将重新创建对象,故(f3、f4)为false。其实这就涉及常量池的概念了。

   2. 常量池

  常量池是JVM的一种内存空间,用来存放编译后确定的数据文本形式的符号引用,其采用11种常量表进行存储(后续博客介绍),并且对6种基本数据类型(对一定范围内的数值)和String等都有常量池的应用,用来快速创建对应的对象。

  其中6种基本数据类型(原理与上边一致,另外两种浮点数类型的包装类则没有实现)常量范围如下:

类型 范围
Boolean true false
Character '\u0000' to '\u007F'(0-127)
Byte all byte values are cached
Short -128 ~ 127
Integer -128 ~ 127
Long -128 ~ 127

  百度百科对常量池的介绍:Java是一种动态链接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值外,还包含一些以文本形式出现的符号引用,比如:类和接口的全限定名;字段的名称和描述符;方法的名称和描述符。在源码编译成字节码时,存在一块叫做“Constant pool”的区域,用来存放常量和符号引用等。

  下一篇博客将介绍String与常量池的内容。

  3. ==与equals()区别

  Java中数据类型分为两类:
  基本数据类型,采用==比较的是它们的值;
  复合数据类型(类),采用==比较的是它们的内存地址。
  Java中多数的类都继承于Object基类,其中有定义equals()方法,该方法的初始行为是比较对象的内存地址。一些类库重写了该方法,如String、Integer、Date等,equals()直接对其值进行比较,而不是类在堆内存中的存放地址;对没有重写该方法的类,比较的仍然是内存地址,相当于==。上源码:

  Object中的equals()方法:

 public boolean equals(Object obj) {
return (this == obj);
}

  String重写后(对每个char进行比较):

 /**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

全文总结:

  • 自动装箱与拆箱,涉及基本数据类型的常量池(一定范围内);
  • 常量池的概念,后续会在介绍Java内存模型时详细介绍;
  • ==与equals()方法的区别,会在面试中问到,尤其涉及String,下一篇博客再详细阐述。

Java基础二:常量池的更多相关文章

  1. 【Java_基础】java中的常量池

    1.java常量池的介绍 java中的常量池,通常指的是运行时常量池,它是方法区的一部分,一个jvm实例只有一个运行常量池,各线程间共享该运行常量池. java常量池简介:java常量池中保存了一份在 ...

  2. Java基础-DBCP连接池(BasicDataSource类)详解

    Java基础-DBCP连接池(BasicDataSource类)详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程 ...

  3. Java入土--Java基础(二)

    Java基础(二) 接上一讲,我们接着来聊聊Java的一些基础知识,下一讲就会进行流程的控制. 类型转换 首先呢,是类型的转换,接上一个内容的数据类型,类型转换就是数据类型更进一步的应用. 由于Jav ...

  4. 第46节:Java当中的常量池

    Java当中的常量池 在Java虚拟机jvm中,内存分布为:虚拟机堆,程序计数器,本地方法栈,虚拟机栈,方法区. 程序计数器是jvm执行程序的流水线,是用来存放一些指令的,本地方法栈是jvm操作系统方 ...

  5. 19、java内存分配 常量池详解

    在class文件中,“常量池”是最复杂也最值得关注的内容. Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int.long等等)和对象型(如Stri ...

  6. Java面试题总结之Java基础(二)

    Java面试题总结之Java基础(二) 1.写clone()方法时,通常都有一行代码,是什么? 答:super.clone(),他负责产生正确大小的空间,并逐位复制. 2.GC 是什么? 为什么要有G ...

  7. Java中的常量池

    JVM中有: Class文件常量池.运行时常量池.全局字符串常量池.基本类型包装类对象 常量池 Class文件常量池: class文件是一组以字节为单位的二进制数据流,在java代码的编译期间,编写的 ...

  8. 讲一讲Java的字符串常量池,看完你的思路就清晰了

    前言 很多朋友Java的字符串常量池的概念困扰了很长一段时间,最近研究了一下jvm指令码,终于对它有了大概的了解. 在展示案例前,我们需要先搞清楚一个概念,众所周知,jvm的内存模型由程序计数器.虚拟 ...

  9. Java堆/栈/常量池以及String的详细详解(转)------经典易懂系统

    一:在JAVA中,有六个不同的地方可以存储数据: 1. 寄存器(register). 这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部.但是寄存器的数量极其有限,所以寄存器由编译器根据 ...

随机推荐

  1. centos 7安装es 及异常处理

    首先,我们从官网下载zip包:(官网:https://www.elastic.co/downloads/elasticsearch)   直接使用浏览器下载可能会很慢,我一般会copy下载链接,然后w ...

  2. QT编程环境搭建

    使用QT需要QT的库以及QT creator,在QT5以后的版本中,两者已经集成,不需要单独下载了,只需要下载一个文件即可.配置步骤如下: 1.下载qt-opensource-windows-x86- ...

  3. java初级开发程序员(第四单元)

    1.switch选择结构:     语法:        switch(表达式){              case    常量1:    //常量可以是整数或字符类型.              ...

  4. 【排序算法】直接选择排序算法 Java实现

    基本思想 直接选择排序是从无序区选一个最小的元素直接放到有序区的最后. 初始状态:无序区为a[1...n],有序区为空. 第一次排序:在无序区a[1...n]中选出最小的记录a[k],将它与有序区的第 ...

  5. Angular.js之指令学习笔记

    <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"& ...

  6. 性能测试工具 - Apache JMeter (安装)

    简介 Apache JMeter 是100%纯java语言开发的负载测试和性能测试开源工具. 功能 Apache JMeter可以对静态/动态资源进行性能测试,模拟多个用户并行请求资源端,以测试其强度 ...

  7. 每天一个linux命令(39)--ifconfig命令

    许多人非常熟悉Windows下的ipconfig 命令行工具,它被用来获取网络接口配置信息并对此进行修改.Linux系统拥有一个类似的工具,也就是ifconfig(interfaces  config ...

  8. Sleeping会话导致阻塞原理(下)

    背景 最近给客户做优化时,有几个客户都存在.SLEEPING 会话中开启了事务,导致的大量阻塞,从而产生严重的性能问题.虽然在之前的文章我分享了Sleeping会话导致阻塞原理(上) .说明了什么是S ...

  9. 为效率而生:开源Mac版Google Authenticator认证客户端GoldenPassport

    最近运维同学为了提高安全性,用Google Authenticator对服务器加了双重认证,此后登录服务器需要先输入动态密码,在输入服务器密码.Google Authenticator相当于软toke ...

  10. Python入门教程(2)

    人生苦短,我玩蛇0.0! Python(英语发音:/ˈpaɪθən/), 是一种面向对象.解释型计算机程序设计语言,由Guido van Rossum于1989年底发明,第一个公开发行版发行于1991 ...