String类型的不可变

众所周知,String类型是不可变的,一旦String对象被创建好了则这个字符串中的序列就不可改变。

为什么String类型是不可变?

根据阅读源码可知,String类是一个final类,但是String不可变并不是因为它是一个final类,final修饰的类只是不能被继承,因为有字符串常量池这个东西,如果String类能被继承就会出现安全问题。关于String不可变的原因是因为下面这句代码:

private final char value[];

value负责存储String的值,因为value是用final修饰的,所以value的地址不能被改变(但是数组的值可以被改变),又因为在String类中并没有任何方法能够修改value的元素,所以String是不可变的。但是在有的时候我们认为字符串改变了啊,例如String s="hi"; s+=" world";s输出就会变成"hi world",这是因为重新给了s一个字符串对象,相加后的对象和以前的对象不一样,后面将会有代码演示。

String类型真的不可变吗?

因为value是一个char数组,他只是地址不可变,其中的值是可变的,String不可变是因为它没有提供给我们可以修改value的方法,但是我们可以通过反射获取到value数组,然后修改它的值,这样可以实现“String的可变”。如下代码所示:

String s1= "hello world";

String s2 ="hello world";

System.out.println(s1==s2);

System.out.println(s1);

System.out.println(s2);

Field field = String.class.getDeclaredField("value");

field.setAccessible(true);

char[] value = (char[])field.get(s1);

value[1]='i';

value[2]='i';

value[3]='i';

value[4]='i';

System.out.println(s1==s2);

System.out.println(s1);

System.out.println(s2);

输出结果

true

hello world

hello world

true

hiiii world

hiiii world

通过上面可以看出当我们改变s1的值时s2被改变了。

关于String的一些常识

如下代码

String s1 = "hello world";

String s2 = "hello world";

String s3 = "hello "+"world";

String s4 = new String("hello world");

String s5 = "hello" + new String("world");

String s6 = new String("hello ");

String s7="world";

String s8 ="hello ";

String s9=s6+s7;

String s10=s8+s7;

System.out.println(s1==s2);

System.out.println(s1==s3);

System.out.println(s1==s4);

System.out.println(s1==s5);

System.out.println(s4==s5);

System.out.println(s1==s9);

System.out.println(s1==s10);

System.out.println(s9==s10);

s1 = s1+"!";

System.out.println(s1);

System.out.println(s2);

System.out.println(s1==s2);

输出结果

true

true

false

false

false

false

false

false

hello world!

hello world

false

在String中使用new就新创建一个对象,不论字符串常量池是否有它,而s3和s10的区别在于,在编译阶段就能确定s3,因为s3指定了是"hello "和"world"相结合,而s10在编译阶段程序并不能确定s8和s7的值。

String一些方法可能产生新的对象

subString

当subString截取的字符串就是本身的时候,返回本身,否则返回一个新声明的字符串。

replace

如果新字符和要替换的一样的话,返回本身,否则返回一个新声明的字符串。

toCharArray

返回一个新的字符数组,对改数组进行修改不会对String产生任何影响。

toString

返回的是字符串本身

trim

trim方法是返回String对象的一个副本,该副本去除了原来字符串中的首部和尾部空白。但如果String对象首部和尾部没有空白的话,则返回自身。否则调用subString方法返回一个崭新的String对象(真子串,subString方法中说过)。

关于String传参

在开始String传参的时候先看看参数传递的两大类型:

值传递:在我们进行参数传递的时候将实参拷贝一份传递过去,所以在方法里面对其更改不会对原本的造成影响。

引用传递:在java中引用传递是拷贝该对象的地址传递过去,如果在传递过去的地址对应的对象上进行修改就会影响原本的值。

具体例子如下:

//自己声明的一个类

class Ref {

private String name;

public void setName(String name) {

this.name = name;

}

public String getName(){

return name;

}

@Override

public String toString() {

return "Ref{" +

"name='" + name + '\'' +

'}';

}

}

public static void main(String[] args) {

Ref ref = new Ref();

ref.setName("张三");

int a=5;

String name = "张三";

change(ref);

change(a);

change(name);

System.out.println(ref);

System.out.println(a);

System.out.println(name);

}

public static void change(Ref ref) {

ref.setName("李四");

}

public static void change(int num) {

num = 18;

}

public static void change(String name) {

name = "李四";

}

//上面输出

/*

Ref{name='李四'}

5

张三

*/

//将ref 的change函数改变如下

public static void change(Ref ref) {

Ref ref1 = new Ref();

ref = ref1;

ref.setName("李四");

}

/*运行

Ref{name='张三'}

5

张三

*/

通过上面的例子我们发现对象的传递如果在方法里面进行了修改将会改变原本的值。但是!!!要注意我们传递过去的只是地址,如下图所示,我们进行传递的时候将ref对象的地址拷贝一份传递过去(注意是拷贝一份),当我们没有对传递过去的形参地址进行修改的情况下,对该形参进行修改都会影响原本的实参,例如上面前面的change方法,如果进行对形参的地址进行修改了的话将会和原本的实参断绝关系,例如上面修改后的change方法。而上面的String的change就不用说了 name= "李四"相当于将name的地址修改为了字符串常量池中的"李四"对象。

ref的存储结构.png

通过上面的我们明白了什么是引用传递和值传递。关于String传参可能大家也有了答案。

String传参的时候传递String对象所指向的地址,但是由于String中没有方法能够对value数组进行修改,所以我们在对String参数进行操作的时候都不会改变他的值,很多情况下我们认为String的值变化了都是一种错觉。比如下面的replace方法

public static void change(String name) {

name.replace('张','李');

}

上面的代码很容易让我们产生name中的"张"换成了"李"的错觉,但是其实并没有改变,我们可以看一看replace的具体是怎么实现的

replace.png

我们可以看出repalce中并没有对原本value数组进行更改,而是将value中的数组拷贝到buf中(需要替换的替换),然后返回一个new String。具体其他你认为String内容改变了的地方你可以阅读源码进行观察,你就会发现其实都没有更改。

关于String的其他内容可以点击查看

java有string这个类型吗_关于java的String类型相关推荐

  1. java string改变的影响_为什么Java的string类要设成immutable(不可变的)

    最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类 ...

  2. java注解字段类型相同_《java基础学习之——重复注解》

    在某些情况下,您要将相同的注释应用于声明或类型使用.从JavaSE 8版本开始,重复注释使您能够做到这一点. 例如,您正在编写代码以使用定时服务,使您能够在给定时间或某个时间表运行方法,类似于UNIX ...

  3. java关于泛型的实验代码_[改善Java代码]强制声明泛型的实际类型

    Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. importjava.util.Arr ...

  4. Java返回int型的空值_使用MyBatis查询int类型字段,返回NULL值时报异常的解决方法...

    当配置mybatis返回int类型时 select id="getUserIdByName" parameterType="string" resultType ...

  5. java负数用什么类型定义_(转) Java中的负数及基本类型的转型详解

    (转) https://my.oschina.net/joymufeng/blog/139952 面这行代码的输出是什么? 下面两行代码的输出相同吗? 请尝试在Eclipse中运行上面的两个代码片段, ...

  6. java将一个整数按字节输出_在java中的整数类型有四种,分别是 byte  short int long 其中byte只有一个字节 0或1,在此不详细讲解。其他的三种类型如下:1、...

    在java中的整数类型有四种,分别是 byte  short int long 其中byte只有一个字节 0或1,在此不详细讲解. 其他的三种类型如下: 1. 基本类型:short 二进制位数:16 ...

  7. java中拼接和 的区别_浅析Java中String与StringBuffer拼接的区别

    学习笔记: 1.String拼接会创建一个新的String对象,存储拼接后的字符串: StringBuffer拼接是直接在本身拼接,会即时刷新. 2.String只能拼接String类型的字符串: S ...

  8. string substring的用法_夯实Java基础系列3:一文搞懂String常见面试题,从基础到实战...

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  9. 保存数组类型数据_「Java」基础12:什么叫数组?

    所谓数组,就是有序的元素序列 ,在数学里面都有讲到这个概念. 那么程序中的数组和数学里的数组又有哪些不同呢? 一.数组的定义与访问 举一个现实生活中的例子: 一个500毫升的杯子,既可以拿来装水,也可 ...

最新文章

  1. hashmap储存有向图_如何在Rust中构建向量的HashMap?
  2. 并行算法设计与性能优化_CME 323: 分布式算法与优化(1)
  3. python如何关闭multiprocess_python 开启进程两种方法 multiprocessing模块 介绍
  4. python 复制列表内容_Python复制列表列表
  5. 谁说Dota2赢了人类的AI太水?连比尔·盖茨都啧啧称赞了
  6. 亚马逊无人超市Amazon Go这次是真的真的开业了
  7. Python中被双下划线包围的魔法方法
  8. virtualenvwrapper安装及使用
  9. OneNote 安装代码高亮插件 NoteHightlight的安装及使用基础教程
  10. 关于MyEclipse的servers和WTPservers
  11. 手机浏览器java_三款最热java手机浏览器横评(组图)
  12. arcgis for js 画圆圈(会跟地图一起缩小),而不是打点然后加半径的圆点(不会缩小),制作打卡功能选点。可以点击地图自动画圆圈
  13. scrapy抓斗鱼主播的图片
  14. Ubuntu下安装NS3
  15. teradata是MySQL吗_Teradata 数据库介绍
  16. 业财一体化系统建设思路
  17. Zlib库的使用实现对zip文件的解压缩
  18. [渝粤教育] 西南交通大学 体育健康课程Ⅰ—奥运裁判带你学规则 参考 资料
  19. Zookeeper报错:Unable to read additional data from server sessionid 0x
  20. python移动均线SMA及双均线策略

热门文章

  1. html 中 标签里面的id 和 name 有什么区别?
  2. 还是畅通工程(思想+代码)
  3. 【指标需求思考】如何做好指标类需求建设
  4. 阿里CTO张建锋:明年双11将大规模应用含光AI芯片
  5. 阿里云MaxCompute印度开服,加速大数据产业升级
  6. Ampere Altra Max 对比测试数据公布,性能能效双领先
  7. AI深入应用,生态越加开放,开发者的机会在哪里?
  8. 低代码发展专访系列之六:低代码平台能解决业务重构的问题么?
  9. 看穿这些套路,你的kubernetes会更香
  10. 为什么嫁人就选程序员!