Java提高篇 —— String緩沖池

一、String緩沖池

?

? ? ? ?首先我們要明確,String并不是基本數據類型,而是一個對象,并且是不可變的對象。查看源碼就會發現String類為final型的(當然也不可被繼承),而且通過查看JDK文檔會發現幾乎每一個修改String對象的操作,實際上都是創建了一個全新的String對象。

? ? ? ?字符串為對象,那么在初始化之前,它的值為null,到這里就有必要提下””、null、new String()三者的區別。null 表示string還沒有new ,也就是說對象的引用還沒有創建,也沒有分配內存空間給他,而””、new String()則說明了已經new了,只不過內部為空,但是它創建了對象的引用,是需要分配內存空間的。

? ? ? ?java的虛擬機在內存中開辟出一塊單獨的區域,用來存儲字符串對象,這塊內存區域被稱為字符串緩沖池。那個java的字符串緩沖池是如何工作的呢?

String a = "abc";
String b = "abc";
String c = new String("xyz");

例如上邊的代碼:?

String a = "abc";

? ? ? ?創建字符串的時候先查找字符串緩沖池中有沒有相同的對象,如果有相同的對象就直接返回該對象的引用,如果沒有相同的對象就在字符串緩沖池中創建該對象,然后將該對象的應用返回。對于這一步而言,緩沖池中沒有abc這個字符串對象,所以首先創建一個字符串對象,然后將對象引用返回給a。

String b = "abc";

? ? ? ?這一句也是想要創建一個對象引用變量b使其指向abc這一對象。這時,首先查找字符串緩沖池,發現abc這個對象已經有了,這是就直接將這個對象的引用返回給b,此時a和b就共用了一個對象abc,不過不用擔心,a改變了字符串而影響了b,因為字符串都是常量,一旦創建就沒辦法修改了,除非創建一個新的對象。

String c = new String("xyz");

? ? ? ?查找字符串緩沖池發現沒有xyz這個字符串對象,于是就在字符串緩沖池中創建了一個xyz對象然后再將引用返回。

? ? ? ?從上邊的分析可以看出,當new一個字符串時并不一定是創建了一個新的對象,有可能是與別的引用變量共同使用了同一個對象。下面看幾個常見的有關字符串緩沖池的問題。

?

二、創建了幾個對象

?

String a = "abc";
String b = "abc";
String c = new String("xyz");
String d = new String("xyz");
String e = "ab" + "cd";

? ? ? ?這個程序與上邊的程序比較相似,我們分比來看一下:

? ? ? ?1、String a = “abc”;這一句由于緩沖池中沒有abc這個字符串對象,所以會創建一個對象

? ? ? ?2、String b = “abc”;由于緩沖池中已經有了abc這個對象,所以不會再創建新的對象

? ? ? ?3、String c = new String(“xyz”);由于沒有xyz這個字符串對象,所以會首先創建一個xyz的對象,然后這個字符串對象由作為String的構造方法,在內存中(不是緩沖池中)又創建了一個新的字符串對象,所以一共創建了兩個對象

? ? ? ?4、String d = new String(“xyz”);緩沖池中已有該字符串對象,則緩沖池中不再創建該對象,然后會在內存中創建一個新的字符串對象,所以只創建了一個對象

? ? ? ?5、String e = ”ab” + ”cd”;由于常量的值在編譯的時候就被確定了。所以這一句等價于String e = ”abcd”;所以創建了一個對象

? ? ? ?所以創建的對象的個數分別是:1,0,2,1,1。

?

三、到底相等不相等

?

? ? ? ?我們在學習java時就知道兩個字符串對象相等的判斷要用equal而不能使用==,但是學習了字符串緩沖池以后,應該知道為什么不能用==,什么情況下==和equal是等價的,首先,必須知道的是,equal比較的是兩個字符串的值是否相等,而==比較的是兩個對象的內存地址是否相等,下面我們就通過幾個程序來看一下。

?

實例一:

public static void main(String[] args) { String s1 = "Monday"; String s2 = "Monday"; if (s1 == s2) System.out.println("s1 == s2"); else System.out.println("s1 != s2"); 
}

輸出結果:

s1 == s2

? ? ? ?分析:通過上邊的介紹字符串緩沖池,我們知道s1和s2都是指向字符串緩沖池中的同一個對象,所以內存地址是一樣的,所以用==可以判斷兩個字符串是否相等。

?

實例二:

public static void main(String[] args) { String s1 = "Monday"; String s2 = new String("Monday"); if (s1 == s2) System.out.println("s1 == s2"); else System.out.println("s1 != s2"); if (s1.equals(s2)) System.out.println("s1 equals s2"); else System.out.println("s1 not equals s2"); 
} 

輸出結果:

s1 != s2 
s1 equals s2 

? ? ? ?分析:由上邊的分析我們知道,String s2 = new String(“Monday”);這一句話沒有在字符串緩沖池中創建新的對象,但是會在內存的其他位置創建一個新的對象,所以s1是指向字符串緩沖池的,s2是指向內存的其他位置,兩者的內存地址不同的。

?

實例三:

public static void main(String[] args) { String s1 = "Monday"; String s2 = new String("Monday"); s2 = s2.intern(); if (s1 == s2) System.out.println("s1 == s2"); else System.out.println("s1 != s2"); if (s1.equals(s2)) System.out.println("s1 equals s2"); else System.out.println("s1 not equals s2"); 
}

輸出結果:

s1 == s2 
s1 equals s2 

? ? ? ?分析:先來說說intern()這個方法的作用吧,這個方法的作用是返回在字符串緩沖池中的對象的引用,所以s2指向的也是字符串緩沖池中的地址,和s1是相等的。

?

實例四:

public static void main(String[] args) { String Monday = "Monday";  String Mon = "Mon";  String  day = "day";  System.out.println(Monday == "Mon" + "day");  System.out.println(Monday == "Mon" + day);  }

輸出結果:

true
false

? ? ? ?分析:第一個為什么等于true我們已經說過了,因為兩者都是常量所以在編譯階段就已經能確定了,在第二個中,day是一個變量,所以不能提前確定他的值,所以兩者不相等,從這個例子我們可以看出,只有+連接的兩邊都是字符串常量時,引用才會指向字符串緩沖池,都則都是指向內存中的其他地址。

?

實例五:

public static void main(String[] args) { String Monday = "Monday";  String Mon = "Mon";  final String  day = "day";  System.out.println(Monday == "Mon" + "day");  System.out.println(Monday == "Mon" + day);  }

輸出結果:

true
true

? ? ? ?分析:加上final后day也變成了常量,所以第二句的引用也是指向的字符串緩沖池。

?

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446948.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446948.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446948.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C++最新使用開源openssl實現輸入是文件,輸出是文件的AES加解密的代碼

AES.h頭文件 #include <cstring> #include <fstream> #include <iostream> #include <openssl/aes.h>//AES文件加密函數 int aes_encrypt_file(const std::string &original_backup_file_path,const std::string &encrypted_file_path,const …

Java基礎 —— JVM內存模型與垃圾回收

目錄一、概述二、運行時數據區方法區運行時常量池堆棧本地方法棧程序計數器三、對象訪問四、垃圾回收如何定義垃圾1、引用計數法2、可達性分析垃圾回收方法1、Mark-Sweep標記-清除算法2、Copying復制算法3、Mark-Compact標記-整理算法4、Generational Collection 分代收集垃圾收…

Report Design

ERP_ENT_STD-CSDN博客

規范化流程化提交自己代碼到遠程gitlab服務器

流程 進入到build目錄使用make命令進行編譯 make -j 6&#xff0c;前提是cmake命令已經執行../format.py rungit add .. 添加文件git checkout -b xxx 創建xxx分支&#xff0c;其中xxx是分支名字git branch 查看分支git commit -m "[chy/backup] modify parameters for…

Java提高篇 ——Java注解

目錄一、注解注解的定義注解的應用元注解RetentionDocumentedTargetInheritedRepeatable注解的屬性Java 預置的注解DeprecatedOverrideSuppressWarningsSafeVarargsFunctionalInterface二、注解的提取三、注解與反射四、注解的使用場景五、親手自定義注解完成某個目的六、注解應…

linux使用openssl查看文件的md5數值

代碼 #include <stdio.h> #include <openssl/md5.h>std::string get_file_md5(const char *path){unsigned char digest [MD5_DIGEST_LENGTH];std::ifstream file(path, std::ios::in | std::ios::binary); //打開文件MD5_CTX md5_ctx;MD5_Init(&md5_ctx);cha…

Android 性能優化四個方面總結

目錄一、四個方面二、卡頓優化1、Android系統顯示原理2、卡頓根本原因3、性能分析工具&#xff08;1&#xff09;Profile GPU Rendering&#xff08;2&#xff09;TraceView&#xff08;3&#xff09;Systrace UI 性能分析4、優化建議&#xff08;1&#xff09;布局優化&#x…

pycharm/clion/idea等產品多含代碼左移右移操作

左移 選中多行代碼后&#xff0c;按下Tab鍵&#xff0c;一次縮進四個字符 右移 鼠標選中多行代碼后&#xff0c;同時按住shiftTab鍵&#xff0c;一次左移四個字符

Android 開源框架選擇

目錄一、前言二、APP的整體架構三、技術選型的考量點四、日志記錄能力五、JSON解析能力1、gson2、jackson3、Fastjson4、LoganSquare六、數據庫操作能力1、ActiveAndroid2、ormlite3、greenDAO4、Realm七、網絡通信能力1、android-async-http2、OkHttp3、Volley4、Retrofit八、…

使用opensll的md5對于string進行加密

代碼 #include <openssl/md5.h>#include <sstream> #include <iomanip> #include <iostream>void get_string_md5(const std::string& await_md5_string) {unsigned char md5[MD5_DIGEST_LENGTH];MD5(reinterpret_cast<unsigned const char*&g…

Android Studio 自定義Gradle Plugin

一、簡介 之前公司的一個項目需要用到Gradle插件來修改編譯后的class文件&#xff0c;今天有時間就拿出來整理一下&#xff0c;學習一下Gradle插件的編寫還是一件十分有意義的事。 二、Gradle插件類型 一種是直接在項目中的gradle文件里編寫&#xff0c;這種方式的缺點是無法復…

C++創建臨時文件

命令 std::string original_backup_file std::tmpnam(nullptr);

Android Studio Gradle兩種更新方式

第一種、Android Studio自動更新 第一步&#xff1a;修改gradle版本 修改項目根目錄/gradle/wrapper/gradle-wrapper.properties最后一行的地址&#xff1a; distributionUrlhttps://services.gradle.org/distributions/gradle-3.3-all.zip新gradle地址從官方下載的地方有。…

C++使用openssl實現aes加解密,其中加密是string到文件,解密是文件到string,切合項目背景

代碼 使用md5對于用戶輸入的密碼進行保護,也使得密碼的長度固定crypto_util.h#pragma once#include <string>namespace hsm{ namespace mgmt{void get_md5_digest(const std::string &data,uint8_t result[16]);void aes_encrypt_to_file(const std::string &fi…

Android Canvas的drawText()和文字居中方案

自定義View是繪制文本有三類方法&#xff1a; // 第一類 public void drawText (String text, float x, float y, Paint paint) public void drawText (String text, int start, int end, float x, float y, Paint paint) public void drawText (CharSequence text, int start…

IntelliJ IDEA配置Tomcat

查找該問題的童鞋我相信IntelliJ IDEA&#xff0c;Tomcat的下載&#xff0c;JDK等其他的配置都應該完成了&#xff0c;那我直接進入正題了。 1、新建一個項目 2、由于這里我們僅僅為了展示如何成功部署Tomcat&#xff0c;以及配置完成后成功運行一個jsp文件&#xff0c;我僅勾…

C++對于文件的相關操作 創建、讀寫、刪除代碼

創建 /*** brief 創建文件:在密碼設備內部創建用于存儲用戶數據的文件* param pucFileName 緩沖區指針&#xff0c;用于存放輸入的文件名&#xff0c;最大長度128字節* param uiNameLen 文件名長度* param uiFileSize 文件所占存儲空間的長度*/void CreateFile(sdf_uint8_t…

Android開發之Path詳解

目錄一、xxxTo方法1、lineTo(float x, float y)2、moveTo(float x, float y)3、arcTo3.1、arcTo(RectF oval, float startAngle, float sweepAngle)3.2、arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)3.3、arcTo(float left, float top, float r…

git大文件拷貝代碼命令

git clone 鏈接 --recursive

Android APK打包流程

目錄一、概述二、打包流程1、打包資源文件&#xff0c;生成R.java文件2、處理aidl文件&#xff0c;生成相應的Java文件3、編譯項目源代碼&#xff0c;生成class文件4、轉換所有的class文件&#xff0c;生成classes.dex文件5、打包生成APK文件6、對APK文件進行簽名7、對簽名后的…