這篇文章給大家分享的是有關(guān)Java中String如何創(chuàng)建對(duì)象的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。
目前成都創(chuàng)新互聯(lián)公司已為1000多家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站改版維護(hù)、企業(yè)網(wǎng)站設(shè)計(jì)、江川網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
本文研究的主要是Java String創(chuàng)建對(duì)象的問題,具體介紹如下。
首先我們要明白兩個(gè)概念,引用變量和對(duì)象,對(duì)象一般通過new在堆中創(chuàng)建,String只是一個(gè)引用變量。
所有的字符串都是String對(duì)象,由于字符串常量的大量使用,java中為了節(jié)省時(shí)間,在編譯階段,會(huì)把所有字符串常量放在字符串常量池中,字符串常量池的一個(gè)好處就是可以把相同的字符串合并,占用一個(gè)空間。
雖然在Java中無法直接獲取變量的地址,但是可以用==判斷一下兩個(gè)引用變量是否指向了一個(gè)地址即一個(gè)對(duì)象。
棧內(nèi)存 | 堆內(nèi)存 |
---|---|
基礎(chǔ)類型,對(duì)象引用( 堆內(nèi)存地址 ) | 由new 創(chuàng)建的對(duì)象和數(shù)組 |
存取速度快 | 相對(duì)于棧內(nèi)存較慢 |
數(shù)據(jù)大小在聲明周期必須確定 | 分配的內(nèi)存由java 虛擬機(jī)自動(dòng)垃圾回收器管理。動(dòng)態(tài)分配內(nèi)存大小 |
共享特性,棧中如果有字符串,則直接引用;如果沒有,開辟新的空間存入值 | 每new一次都在堆內(nèi)存中生成一個(gè)新的對(duì)象。不存在任何復(fù)用 |
package com.demo.test; import java.lang.reflect.Field; public class StringDemo { public static void main(String[] args) { //先在內(nèi)存中查找有沒有這個(gè)字符串對(duì)象存在,如果存在就指向這個(gè)字符串對(duì)象; String str1 = "abc"; String str2 = "abc"; /* public String toString() { return this; } */ String str3 = "abc".toString(); //不論內(nèi)存中是否已經(jīng)存在這個(gè)字符串對(duì)象,都會(huì)新建一個(gè)對(duì)象。 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是不可變字符串對(duì)象,StringBuilder和StringBuffer是可變字符串對(duì)象(其內(nèi)部的字符數(shù)組長度可變),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計(jì)算公式: s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1] 因此hashCode都是一樣的,而且是每次運(yùn)行都一樣 */ 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只是指向堆內(nèi)存中的引用,存儲(chǔ)的是對(duì)象在堆中的地址,而非對(duì)象本身,給string賦值只是改變其引用對(duì)象而非對(duì)象本身 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, 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 } }
總結(jié)
如果String指向的是一個(gè)字符串常量,那么會(huì)先在字符串常量池(棧)中查找,如果有就直接指向它;沒有則在字符串常量池中創(chuàng)建該常量,然后String指向該常量。
如果String使用關(guān)鍵字new初始化,則會(huì)在堆中開辟固定的空間存放該字符串的值,然后String指向該常量。
使用字符串常量拼接,由于表達(dá)式先計(jì)算右值,因此相當(dāng)于將String指向一個(gè)新拼接好的字符串常量。同樣會(huì)在字符串常量池中查找,如果有就直接指向它;沒有則在字符串常量池中創(chuàng)建該常量,然后String指向該常量。但是如果拼接中存在使用new生成的字符串,則新的字符串就等價(jià)于使用new在堆中創(chuàng)建的一樣。
修改String的值,只能改變String的指向,不會(huì)改變String指向的對(duì)象本身。如果非要改變指向的對(duì)象本身,可以使用反射。
如果是數(shù)組,由于它是對(duì)象,那么equals只比較其數(shù)組指針地址,并不會(huì)去比較其中的元素是否相等。
感謝各位的閱讀!關(guān)于“Java中String如何創(chuàng)建對(duì)象”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!