Java String创建对象实例解析
程序员文章站
2023-11-04 20:55:34
本文研究的主要是java string创建对象的问题,具体介绍如下。
首先我们要明白两个概念,引用变量和对象,对象一般通过new在堆中创建,string只是一个引用变量。...
本文研究的主要是java string创建对象的问题,具体介绍如下。
首先我们要明白两个概念,引用变量和对象,对象一般通过new在堆中创建,string只是一个引用变量。
所有的字符串都是string对象,由于字符串常量的大量使用,java中为了节省时间,在编译阶段,会把所有字符串常量放在字符串常量池中,字符串常量池的一个好处就是可以把相同的字符串合并,占用一个空间。
虽然在java中无法直接获取变量的地址,但是可以用==判断一下两个引用变量是否指向了一个地址即一个对象。
栈内存 | 堆内存 |
---|---|
基础类型,对象引用( 堆内存地址 ) | 由new 创建的对象和数组 |
存取速度快 | 相对于栈内存较慢 |
数据大小在声明周期必须确定 | 分配的内存由java 虚拟机自动垃圾回收器管理。动态分配内存大小 |
共享特性,栈中如果有字符串,则直接引用;如果没有,开辟新的空间存入值 | 每new一次都在堆内存中生成一个新的对象。不存在任何复用 |
package com.demo.test; import java.lang.reflect.field; public class stringdemo { public static void main(string[] args) { //先在内存中查找有没有这个字符串对象存在,如果存在就指向这个字符串对象; string str1 = "abc"; string str2 = "abc"; /* public string tostring() { return this; } */ string str3 = "abc".tostring(); //不论内存中是否已经存在这个字符串对象,都会新建一个对象。 string str4 = new string("abc"); string str5 = new string("abc"); string str6 = str5; string str7 = "a" + "b" + "c"; string str8 = "a" + "b" + new string("c"); //string是不可变字符串对象,stringbuilder和stringbuffer是可变字符串对象(其内部的字符数组长度可变),stringbuffer线程安全,stringbuilder非线程安全 string str9 = new stringbuilder().append("a").append("b").append("c").tostring(); string str10 = new stringbuffer().append("a").append("b").append("c").tostring(); system.out.println("--------> =="); system.out.println("---> 1"); system.out.println(str1==str2);//true system.out.println("---> 3"); system.out.println(str3==str1);//true system.out.println("---> 4"); system.out.println(str4==str1);//false system.out.println(str4==str3);//false system.out.println(str4==str5);//false system.out.println(str4==str6);//false system.out.println("---> 7"); system.out.println(str7==str1);//true system.out.println(str7==str3);//true system.out.println(str7==str4);//false system.out.println("---> 8"); system.out.println(str8==str1);//false system.out.println(str8==str3);//false system.out.println(str8==str4);//false system.out.println(str8==str7);//false system.out.println("---> 9"); system.out.println(str9==str1);//false system.out.println(str9==str3);//false system.out.println(str9==str4);//false system.out.println(str9==str7);//false system.out.println(str9==str8);//false system.out.println("---> 10"); system.out.println(str10==str1);//false system.out.println(str10==str3);//false system.out.println(str10==str4);//false system.out.println(str10==str7);//false system.out.println(str10==str8);//false system.out.println(str10==str9);//false system.out.println("--------> equals"); system.out.println(str1.equals(str4));//true system.out.println(str1.equals(str7));//true system.out.println(str1.equals(str8));//true system.out.println("--------> hashcode"); /* hashcode计算公式: s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 因此hashcode都是一样的,而且是每次运行都一样 */ system.out.println(str1.hashcode());//96354 system.out.println(str2.hashcode()); system.out.println(str3.hashcode()); system.out.println(str4.hashcode()); system.out.println(str5.hashcode()); system.out.println(str6.hashcode()); system.out.println(str7.hashcode()); system.out.println("--------> normal change value"); //string是不可变类,string只是指向堆内存中的引用,存储的是对象在堆中的地址,而非对象本身,给string赋值只是改变其引用对象而非对象本身 str6 = "123"; system.out.println(str5);//abc system.out.println(str6);//123 system.out.println("--------> reflect change value"); /* 如果非要改变string的值,也不是不可行。只能使用反射了。 public final class string implements java.io.serializable, comparable<string>, charsequence { // the value is used for character storage. private final char value[]; …… } */ str6 = str5; try { field field = string.class.getdeclaredfield("value"); // field field = str6.getclass().getdeclaredfield("value"); if(!field.isaccessible()) { field.setaccessible(true); } char[] value = (char[])field.get(str6); value[0] = '0'; system.out.println(str5);//0bc system.out.println(str6);//0bc } catch (nosuchfieldexception | securityexception | illegalargumentexception | illegalaccessexception e) { e.printstacktrace(); } system.out.println("--------> obj.tostring()"); object obj = new object(); /* public string tostring() { return getclass().getname() + "@" + integer.tohexstring(hashcode()); } */ system.out.println(obj.tostring());//java.lang.object@15db9742 string[] arr1 = {"0"}; string[] arr2 = {"0"}; system.out.println(arr1.equals(arr2));//false } }
总结
- 如果string指向的是一个字符串常量,那么会先在字符串常量池(栈)中查找,如果有就直接指向它;没有则在字符串常量池中创建该常量,然后string指向该常量。
- 如果string使用关键字new初始化,则会在堆中开辟固定的空间存放该字符串的值,然后string指向该常量。
- 使用字符串常量拼接,由于表达式先计算右值,因此相当于将string指向一个新拼接好的字符串常量。同样会在字符串常量池中查找,如果有就直接指向它;没有则在字符串常量池中创建该常量,然后string指向该常量。但是如果拼接中存在使用new生成的字符串,则新的字符串就等价于使用new在堆中创建的一样。
- 修改string的值,只能改变string的指向,不会改变string指向的对象本身。如果非要改变指向的对象本身,可以使用反射。
- 如果是数组,由于它是对象,那么equals只比较其数组指针地址,并不会去比较其中的元素是否相等。
以上就是本文关于java string创建对象实例解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!