Java对象创建方式及JVM对字符串处理
来源:互联网 发布:小苍零食淘宝店 编辑:程序博客网 时间:2024/06/15 05:13
1.Java程序中创建对象的5种常见方式
在讲Jvm对字符串的处理之前,我们先来讲一下,在Java中,最常见的5种创建对象的方式:
1)通过关键字new调用构造器创建Java对象,eg :String str = new String("hello");
2)通过Class对象的newInstance()方法调用构造器创建Java对象,eg : Class.forName("com.mysql.jdbc.Driver").newInstance();
3)通过Java的反序列化机制从IO流中恢复Java对象,eg :
1 package test; 2 3 import java.io.Serializable; 4 5 public class Person implements Serializable { 6 7 static final long serialVersionUID = 1L; 8 9 String name; // 姓名10 11 public Person() {}12 13 public Person(String name) {14 super();15 this.name = name;16 }17 }
1 package test; 2 3 import java.io.FileInputStream; 4 import java.io.FileOutputStream; 5 import java.io.ObjectInputStream; 6 import java.io.ObjectOutputStream; 7 8 public class ObjectIo { 9 public static void main(String[] args) throws Exception {10 Person p = new Person("小明");11 FileOutputStream fos = new FileOutputStream("d:/objectIoTest.dat");12 ObjectOutputStream oos = new ObjectOutputStream(fos);13 oos.writeObject(p);14 oos.flush();15 oos.close(); //前面这几行都是为了下面几行通过Java的反序列化机制从IO流中恢复Java对象作准备16 17 //下面才是开始通过Java的反序列化机制从IO流中恢复Java对象18 FileInputStream fis = new FileInputStream("d:/objectIoTest.dat");19 ObjectInputStream ois = new ObjectInputStream(fis);20 Person person = (Person) ois.readObject();21 System.out.println("这个人是 : " + person.name);22 }23 }
运行结果:
4)通过Java对象提供的clone()方法复制一个新的Java对象,eg :
1 package test; 2 3 /** 4 * 必须实现Cloneable接口,并且重写clone()方法 5 * @ClassName: Base 6 * @author 小学徒 7 * @date 2013-3-28 8 */ 9 public class Base implements Cloneable{10 int i = 20;11 12 @Override13 protected Object clone() throws CloneNotSupportedException {14 return super.clone();15 }16 }
1 package test;2 3 public class CloneTest {4 public static void main(String[] args) throws Exception {5 Base b = new Base();6 Base c = (Base) b.clone();7 System.out.println("b和c是同一个对象? " + (c == b));8 }9 }
运行结果 :
5)除上述四点之外,对于字符串以及基本类型的包装类(Byte, Short, Integer, Long, Character, Float, Double 和 Double),Java允许他们以直接量来创建Java对象,eg:Integer in = 5;
2.JVM对字符串变量的处理
在Java中,我们经常会用到字符串类型,关于字符串类型,有这么三个类型:String , StringBuffer, StringBuilder,那么为什么一个简单的字符串类型要分为这三种呢?JVM对他们的处理有是怎样的呢?
1)String,不可变的字符串
①我们先来看一下最基本的笔试面试题:String javaStr = new String("小学徒的成长历程");这条语句创建了几个字符串对象?
答案是两个,一个是“小学徒的成长历程”这个直接量对应的字符串对象,一个是由new String()构造器返回的字符串对象。
那么究竟为什么是两个呢?为什么会有直接量对应的字符串对象呢?好啦,言归正传。其实这个就与JVM对字符串变量的处理有关了。
对于Java程序中的字符直接量(eg:String javaStr = "小学徒的成长历程"),JVM会使用一个字符串池来保存他们,当第一次使用某个字符串直接量时,JVM会将它放入字符串池进行缓存。当程序再次需要使用该字符串时,无须重新创建一个新的字符串,而是直接引用变量执行字符串中已有的字符串。但是对于使用构造器进行初始化的字符串(eg :String javaStr = new String("小学徒的成长历程")),因为凡是通过构造器创建的对象都会进行内存分配,所以他就不会指向缓存池中已有的对象而指向新的对象,这样就会造成缓存池中存在多个值相同的字符串对象,浪费了资源。
1 public class Test{ 2 3 public static void main(String[] args) { 4 //通过构造器进行初始化,如果是第一次,他同样会在缓存池中缓存该字符串 5 //但是他依旧另外创建一个对象并指向该对象 6 String newStr = new String("小学徒的成长历程"); 7 //javaStr的值是字符串直接量 8 //所以,javaStr指向字符串缓存池中的"小学徒的成长历程"字符串 9 String javaStr = "小学徒的成长历程";10 //由于缓存池中已经有了"小学徒的成长历程"字符串11 //所以,anotherStr也指向字符串缓存池中的"小学徒的成长历程"字符串12 String anotherStr = "小学徒的成长历程";13 14 System.out.println("javaStr == anotherStr : " + (javaStr == anotherStr)); //判断两个字符串是不是指向同一个对象15 System.out.println("newStr == anotherStr : " + (newStr == anotherStr));16 System.out.println("newStr == javaStr : " + (newStr == javaStr));17 } 18 }
运行结果:
上面的测试代码块执行后,他在内存中的分配情况是这样的:
②下面我们再看一题经典的笔试面试题:String javaStr = "小学徒" + "的" + "成长历程";总共创建了多少个字符串对象?
答案是一个,因为如果一个字符串连接表达式的值可以在编译时确定下来,那么JVM会在编译时计算该字符串变量的值,并让他指向字符串池中对应的字符串。但如果程序使用了变量,或者调用了方法,那么就只能等到运行时才可确定该字符串连接式的值,也就无法在编译时确定字符串变量的值,因此无法确定该字符串变量的值,所以无法利用JVM的字符串池。
下面我们写一段代码验证一下吧:
1 public class Test{ 2 3 public static void main(String[] args) { 4 String anotherStr = "小学徒的成长历程"; 5 6 //虽然javaStr的值不是直接量,但是因为javaStr的值可以在编译时确定 7 //所以javaStr也会直接引用字符串池中对应的字符串 8 String javaStr = "小学徒" + "的" + "成长历程"; 9 10 String a = "的";11 12 //使用了变量,只能等到运行时才可确定该字符串连接式的值13 //也就无法在编译时确定字符串变量的值,因此无法确定该字符串变量的值,所以无法利用JVM的字符串池14 String contactStr = "小学徒" + a + "成长历程";15 16 //调用了方法只能等到运行时才可确定该字符串连接式的值17 //也就无法在编译时确定字符串变量的值,因此无法确定该字符串变量的值,所以无法利用JVM的字符串池18 String methodStr = "小学徒的成长历程" + a.length();19 20 //判断各个字符串是否相等21 System.out.println("javaStr == anotherStr : " + (javaStr == anotherStr));22 System.out.println("contactStr == javaStr : " + (contactStr == javaStr));23 System.out.println(" methodStr == javaStr : " + (methodStr == javaStr));24 25 26 } 27 }
运行结果:
③呵呵,我们再用一题经典面试笔试题目来抛砖引玉吧,这样比较可以诱导大家的思考,同时增加大家的兴趣,不会太过闷,而且还能提醒大家在笔试面试的时候该注意什么地方,好啦,言归正传。String name = "小学徒"; name = name + "的成长空间";两条语句总共创建了多少个字符串对象?
答案是两个,因为当一个String对象创建完成后,该String类里包含的字符串序列就被固定下来了,以后永远都不能改变。(如果目前不懂这句的话,没关系,看下补充你就理解的了)
1 public class Test{2 3 public static void main(String[] args) {4 String name = "小学徒"; //定义一个字符串变量5 System.out.println(System.identityHashCode(name)); //输出该对象的hashCode值6 name = name + "的成长空间"; //拼接字符串变量7 System.out.println(System.identityHashCode(name));//输出该对象的hashCode值8 } 9 }
运行结果:
我们可以看到两个的值是不一样的,所以此处说明String是典型的不可变类,上述代码之后代码中的内存分配情况是
或许你看了之后会说,没关系啊,这个java会自动进行垃圾回收,到时候回收就行了,到这里,我就得补充一下前面没有说到的问题了:
java为了节省内存,提高资源的复用,才引入了字符串缓存池的概念,而且,在缓存池中的字符串是不会被垃圾回收机制回收的,基本都是常驻内存,所以过多使用String类,可能会出现内存溢出。
所以前面的代码中,对String对象进行操作后,其返回的是一个新的对象,之前那个对象是没有改变的,改变的是name这个引用所指的对象,这时候的对象已经是新的对象,然而之前那个对象被废弃了,但是他存在缓存池,因此不会被垃圾回收机制回收,所以这里会容易出现内存泄漏,所以如果要操作字符串,尽量不用String而改为使用StringBuffer或者StringBuilder。
2)StringBuilder和StringBuffer:可变的字符串
之所以说他们会改变的原因是:StringBuilder和StringBuffer在进行字符串操作的时候就不会去创建一个新出现的对象,引用的都是同一个对象,减少了String带来的弊端。
1 public class Test{2 3 public static void main(String[] args) {4 StringBuilder sb = new StringBuilder("小学徒");5 System.out.println(System.identityHashCode(sb));6 sb.append("的成长历程");7 System.out.println(System.identityHashCode(sb));8 }9 }
运行结果:
那么StringBuilder和StringBuffer这两个类有什么区别呢?
他们之间的唯一区别就在于StringBuffer是线程安全的,也就是说StringBuffer类里绝大部分方法都增加了synchronized修饰符,这样就降低了该方法的执行效率,所以在没有多线程的环境下,推荐使用StringBuilder。
StringBuffer的源代码:
StringBuilder的源代码:
转载请注明出处:http://www.cnblogs.com/xiaoxuetu/ ,谢谢合作
- Java对象创建方式及JVM对字符串处理
- Java对象创建方式及JVM对字符串处理
- Java对象创建方式及JVM对字符串处理
- Java对象创建方式及JVM对字符串处理
- 创建Java对象的五种方式以及JVM对字符串处理
- java对String字符串对象的创建及管理
- JVM 如何创建Java对象
- JVM 如何创建Java对象
- Java中JNI的使用详解第四篇:C/C++中创建Java对象和String字符串对象及对字符串的操作方法
- JVM对字符串变量的处理 .
- java对String字符串对象的创建以及管理
- java创建对象方式
- JAVA对象创建方式
- Java对象创建和初始化过程,处理字符串的机制
- 面试总结之Java中创建对象过程及方式
- JVM-内存管理及创建对象
- 详解Java String字符串对象的创建及管理(1)
- 详解Java String字符串对象的创建及管理(2)
- 省赛 双线程dp
- _com_util::ConvertBSTRToString 连接错误
- 下拉树~不断、持续完善中~
- 二叉树
- poj 3349 snowflake 哈希表
- Java对象创建方式及JVM对字符串处理
- 回文字符串
- Java学习笔记(AWT组件 之 按钮)
- Java数据类型与各数据库类型对应一览表
- android学习笔记---55_frame动画的实现,Java技术qq交流群:JavaDream:251572072
- 在日常工作中应用看板
- CSS 中的分离、抽象和层叠
- 并查集(Union-Find)算法介绍(转)
- [025] 微信公众帐号开发教程第1篇-引言