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).综合示例
分享到:
相关推荐
otherClass.java 从类的外部访问对象的成员 showInstVar.java 演示不同的对象拥有不同的成员变量 showMain.java 演示main方法访问本类成员 showMethod.java 演示如何定义一个方法体 showReturn_1.java return...
1、内存中的堆(stack)与... 包装类数据的存储 String类型数据的存储 数组的内存分配 内存空间的释放 3、Java内存分配中的栈 Java内存分配中的堆 4、String.intern() 5、关于equasl()与== 6、关于String是不可变的
020612_【第6章:面向对象(高级)】_包装类笔记.pdf 020613_【第6章:面向对象(高级)】_匿名内部类笔记.pdf 020701_【第7章:异常的基本概念】_异常的基本概念笔记.pdf 020702_【第7章:异常的基本概念】_异常的...
内存分析 59 属性(field,或者叫成员变量) 59 引用类型 60 类的方法 60 对象的创建和使用 60 构造器(或者叫做构造方法,constructor) 60 垃圾回收机制(Garbage Collection) 63 方法的重载(overload),构造方法的...
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平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变...
能够使用String,StringBuffer,StringBuilder类创建字符串对象和使用其方法,分辨不同类之间的区别。 能够使用Date, Calendar, Locale, DateFormat,NumberFormat类创建、改变和显示日期、数字和货币...
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 再...
public 说明类为公共类,该类可以被当前包以外的类和对象使用。 private 说明类为私有类。 (4) extends 子句用于说明类的直接超类。 (5) implements 子句用于说明类中将实现哪些接口,接口是 Java 的一种...
JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要...
•如果希望获得包装类对象中包装的基本类型变量,则可以使用包装类提供的XxxValue()实例方法。 自动装箱与自动拆箱 •JDk还提供了自动装箱和自动拆箱。自动装箱就是把一个基本类型的变量直接赋给对应的...
展示了如何提升Java应用性能,并且给出了优化前与优化后的Java应用程序的性能差别,以实际的实例与数字告诉你,为什么不可以这么做,应该怎么做,深入分析了影响Java应用程序性能的根本原因。本书不是教你怎样使用...
DiskFileItemFactory 是创建 FileItem 对象的工厂,这个工厂类常用方法: public void setSizeThreshold(int sizeThreshold) 设置内存缓冲区的大小,默认值为10K。当上传文件大于缓冲区大小时, fileupload组件将...
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异常的...
包装类 String 泛型 内部类 集合类 ArrayList & LinkedList 详解 HashMap HashTable ConcurrentHashMap 详解 异常相关 代理机制 JDBC BIO NIO AIO 创建类的方法 final finally finalize 反射 序列化与反序列化 ...
} } 运⾏结果: 基本类型:byte ⼆进制位数:8 包装类:java.lang.Byte 最⼩值:Byte.MIN_VALUE = -128 最⼤值: Byte.MAX_VALUE = 127 基本类型:char ⼆进制位数:16 包装类:java.lang.Character 最⼩值:...
进行高精度运算可以用java.math包中BigDecimal类中的方法。 自动类型提升又称作隐式类型转换。 强制类型转换:int ti; (byte) ti ; 强制转换,丢弃高位 宣告变量名称的同时,加上“final”关键词来限定,这个...
5.3 包装类的使用 114 实例093 将字符串转换成整数 114 实例094 整数进制转换器 115 实例095 查看数字的取值范围 116 实例096 ASCII编码查看器 117 实例097 Double类型的比较 118 5.4 面向对象的特征 119 实例098 ...