`

Java之内存分析和String对象、包装类

 
阅读更多

Java中内存分析:

1.栈(Stack):存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new出来的对象)或者常量池中(字符串常量对象存放在常量池中)。

2.堆(heap):存放所有new出来的对象。

3.常量池(constant pool):在堆中分配出来的一块存储区域,存储显式的String常量和基本类型常量(float、int等)。另外,也可以存储不经常改变的东西(public static final)。常量池中的数据可以共享。

4.静态存储:存放静态成员(static定义的)。

示例分析

1).

String a = "abc";①

String b = "abc";②

分析:

①代码执行后在常量池(constant pool)中创建了一个值为abc的String对象

②执行时,因为常量池中存在"abc"所以就不再创建新的String对象了。

2).

String c = new String("xyz");①
String d = new String("xyz");②
分析:
①Class被加载时,"xyz"被作为常量读入,在常量池(constant pool)里创建了一个共享的值为"xyz"的String对象;然后当调用到new String("xyz")的时候,会先去常量池中查找是否有"xyz"对象,如果没有则在常量池中创建一个此字符串对象,然后再在堆中创建一个此常量池中"xyz"对象的拷贝,最后在堆(heap)里创建这个new String("xyz")对象;
②由于常量池(constant pool)中存在"xyz"对象,所以不用再在常量池中创建"xyz",直接在堆里创建新的new String("xyz")对象。
3).
String s1 = new String("xyz"); //创建二个对象(常量池中"xyz"常量对象和堆中new String("xyz")对象),一个引用(栈中s1引用堆中new String("xyz")对象)
String s2 = new String("xyz"); //创建一个对象(堆中),并且以后每执行一次同样赋值操作均创建一个对象,一个引用
String s3 = "xyz";//创建一个对象(常量池中"xyz"常量对象),一个引用
String s4 = "xyz";//不创建对象(共享上次常量池中的数据),只是创建一个新的引用
4). intern()
java.lang.String的intern()方法"abc".intern()方法的返回值还是字符串"abc",表面上看起来好像这个方法没什么用处。但实际上,它做了个小动作:检查字符串池里是否存在"abc"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会把"abc"添加到字符串池中,然后再返回它的引用。
String s1 = "Monday";//在常量池中创建"Monday"对象
String s2 = new String("Monday").intern();//在堆中创建new String("Monday")对象后,并未使用该对象,而是继续检查常量池中是否存在"Monday"对象,并返回常量池中的"Monday"对象给s2,此时s1,s2指向同一对象。
5). 而对于基础类型的变量和常量,变量和引用存储在栈中,常量存储在常量池中
int a1 = 1, a2 = 2, a3 = 3;
public static final int INT1 = 1;
public static final int INT2 = 1;
public static final int INT3 = 1;
6). Java中的装箱和拆箱。
在JDK1.5之前,我们要实现基本类型和包装类之间的转换,大多是通过包装类提供的方法,Integer i = Integer.valueOf(5)或者int j = i.intValue()来做互相转换的。JDK1.5之后,编译器会在我们做赋值操作(这里所说的赋值操作不包括构造函数)的时候帮我们自动完成基本类型和包装类之间的相互转换。包装类是类,是对象,而基本类型是有值的“变量”,包装类的实例(对象)创建在堆上,而基本类型创建在栈上。包装类作为类,可以容纳更多的信息。包装类都实现了Comparable接口,可以实现对象之间的比较,所以包装类之间的比较尽量用compareTo,而不是><=这些运算符。上面我们所说的赋值操作,基本上可以分为两种情况,一种是显式赋值,另一种是隐式赋值。

显式赋值,我们可以理解为有赋值符号出现的情况,比如,Integer i = 11;这里编译器会自动的帮你完成把11这个int的基本类型装箱成包装类实例的工作,这样就不用我们再手动的转换了。

隐式赋值,就是没有赋值符号出现的情况,比如方法调用时候的参数传递,比如我们有一个接受Integer类型参数的方法(void method(Integer i)),我们在调用的时候可以直接传递一个基本类型的实参进去(method(5)),这时候编译器会自动的将我们传递进去的实参装箱成包装类,从而完成对方法的调用。在方法调用的时候,在内存中的栈上,首先会为方法的形参创建内存区域,然后将我们传递进去的实参赋值给形参,就是在这时,发生了赋值操作,才会让编译器完成装箱操作。当然,方法执行完后,栈上有关形参的内存区域会被回收。

还有我们要记住一点,就是编译器的装箱/拆箱原则,就是基本类型可以先加宽(比如int转换为long),再转变成宽类型的包装类(Long),但是不能直接转变成宽类型的包装类型。比如我们有个方法 void method(longl),我们通过method(5)是可以调用该方法的,因为int类型的5被加宽成了long类型;但是如果这个方法变成void method(Long l),我们通过method(5)就不能调用它了,因为int类型的5是不能直接转换成Long包装类的,切记。

最后还有一个值得注意的地方,就是上面我们提到的显示赋值的情况下,比如Integer i = 11的情况,实际上在源码中是调用到了Integer的静态方法valueOf(),在这一块,java的设计者采用了cache pool的设计模式,在Integer这个类里面有一个长度为256的静态Integer数组,里面存储了从-128到127的Integer对象,当我们传递进去的参数在这个范围之内时,这个方法会返回该数组中实际保存的Integer对象实例,只有超过该范围时,才会返回new出来的Integer对象实例。

7).综合示例

    public static void main(String[] args) {  
        // 以下两条语句创建了1个对象。"凤山"存储在字符串常量池中  
        String str1 = "凤山";  
        String str2 = "凤山";  
        System.out.println(str1==str2);//true  
          
        //以下两条语句创建了3个对象。"天峨",存储在字符串常量池中,两个new String()对象存储在堆内存中  
        String str3 = new String("天峨");  
        String str4 = new String("天峨");  
        System.out.println(str3==str4);//false  
          
        //以下两条语句创建了1个对象。9是存储在栈内存中  
        int i = 9;  
        int j = 9;  
        System.out.println(i==j);//true  
          
        //由于调用构造函数,并非装箱,以下两条语句创建了2个对象,存储在堆内存中  
        Integer l1 = new Integer(1);  
        Integer k1 = new Integer(1);  
        System.out.println(l1==k1);//false  
        //以下两条语句引用了Interger类中Interger数组中同一对象,自动装箱时对于值从-128到127之间的值,使用同一个实例。  
        Integer l = 20;//装箱  
        Integer k = 20;//装箱  
        System.out.println(l==k);//true  
        //以下两条语句创建了2个对象。i1,i2变量存储在栈内存中,两个256对象存储在堆内存中  
        Integer i1 = 256;  
        Integer i2 = 256;  
        System.out.println(i1==i2);//false  
    }  




分享到:
评论

相关推荐

    Java开发技术大全(500个源代码).

    otherClass.java 从类的外部访问对象的成员 showInstVar.java 演示不同的对象拥有不同的成员变量 showMain.java 演示main方法访问本类成员 showMethod.java 演示如何定义一个方法体 showReturn_1.java return...

    Java开发详解.zip

    020612_【第6章:面向对象(高级)】_包装类笔记.pdf 020613_【第6章:面向对象(高级)】_匿名内部类笔记.pdf 020701_【第7章:异常的基本概念】_异常的基本概念笔记.pdf 020702_【第7章:异常的基本概念】_异常的...

    JAVA基础课程讲义

    内存分析 59 属性(field,或者叫成员变量) 59 引用类型 60 类的方法 60 对象的创建和使用 60 构造器(或者叫做构造方法,constructor) 60 垃圾回收机制(Garbage Collection) 63 方法的重载(overload),构造方法的...

    疯狂JAVA讲义

    6.1 基本数据类型的包装类 167 6.2 处理对象 170 6.2.1 打印对象和toString方法 170 6.2.2 ==和equals比较运算符 172 6.3 类成员 175 6.3.1 理解类成员 175 6.3.2 单例(Singleton)类 176 6.4 final修饰符 ...

    java 面试题 总结

    JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变...

    AIC的Java课程1-6章

     能够使用String,StringBuffer,StringBuilder类创建字符串对象和使用其方法,分辨不同类之间的区别。  能够使用Date, Calendar, Locale, DateFormat,NumberFormat类创建、改变和显示日期、数字和货币...

    Java入门教程(微学苑)-part1

    3.19 Java包装类、拆箱和装箱详解 54 3.20 包装类的应用 54 3.20.1.1 1) 实现 int 和 Integer 的相互转换 54 3.20.1.2 2) 将字符串转换为整数 55 3.20.1.3 3) 将整数转换为字符串 55 3.21 自动拆箱和装箱 56 3.22 再...

    Java 语言基础 —— 非常符合中国人习惯的Java基础教程手册

     public 说明类为公共类,该类可以被当前包以外的类和对象使用。  private 说明类为私有类。 (4) extends 子句用于说明类的直接超类。 (5) implements 子句用于说明类中将实现哪些接口,接口是 Java 的一种...

    超级有影响力霸气的Java面试题大全文档

     JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要...

    【05-面向对象(下)】

    •如果希望获得包装类对象中包装的基本类型变量,则可以使用包装类提供的XxxValue()实例方法。 自动装箱与自动拆箱 •JDk还提供了自动装箱和自动拆箱。自动装箱就是把一个基本类型的变量直接赋给对应的...

    Java优化编程(第2版)

    展示了如何提升Java应用性能,并且给出了优化前与优化后的Java应用程序的性能差别,以实际的实例与数字告诉你,为什么不可以这么做,应该怎么做,深入分析了影响Java应用程序性能的根本原因。本书不是教你怎样使用...

    file java 上传 下载

    DiskFileItemFactory 是创建 FileItem 对象的工厂,这个工厂类常用方法: public void setSizeThreshold(int sizeThreshold) 设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将...

    Java开发技术大全 电子版

    5.2.3String对象的使用214 5.2.4String类型的数组216 5.2.5StringBuffer对象的声明217 5.2.6StringBuffer对象的创建217 5.2.7StringBuffer对象的使用218 5.3本章小结219 第6章Java的异常处理220 6.1异常的...

    leetcode题库-java-interview:Java研发基础相关

    包装类 String 泛型 内部类 集合类 ArrayList & LinkedList 详解 HashMap HashTable ConcurrentHashMap 详解 异常相关 代理机制 JDBC BIO NIO AIO 创建类的方法 final finally finalize 反射 序列化与反序列化 ...

    Java的8大基本数据类型.pdf

    } } 运⾏结果: 基本类型:byte ⼆进制位数:8 包装类:java.lang.Byte 最⼩值:Byte.MIN_VALUE = -128 最⼤值: Byte.MAX_VALUE = 127 基本类型:char ⼆进制位数:16 包装类:java.lang.Character 最⼩值:...

    整理后java开发全套达内学习笔记(含练习)

    进行高精度运算可以用java.math包中BigDecimal类中的方法。 自动类型提升又称作隐式类型转换。 强制类型转换:int ti; (byte) ti ; 强制转换,丢弃高位 宣告变量名称的同时,加上“final”关键词来限定,这个...

    Java开发实战1200例(第1卷).(清华出版.李钟尉.陈丹丹).part3

    5.3 包装类的使用 114 实例093 将字符串转换成整数 114 实例094 整数进制转换器 115 实例095 查看数字的取值范围 116 实例096 ASCII编码查看器 117 实例097 Double类型的比较 118 5.4 面向对象的特征 119 实例098 ...

Global site tag (gtag.js) - Google Analytics