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.mzph.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、对签名后的…