整理一下java中关于String的内容。Spring应该是java中使用最频繁的类了,那么今天我们仔细研究下关于Spring的内容。

定义:

  String类是一个字符串类型的类,使用"   "定义的内容都是字符串。

实例化:

  (1)直接赋值实例化:String str ="Hello World!";

  (2)使用构造方法实例化:String str = new String("Hello World!");

注意:

1)单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;

2)使用new String("")创建的对象会存储到堆中,是运行期创建的;

new创建字符串时首先查看String Pool中是否有相同的字符串,如果有,则拷贝一份到堆中,然后返回堆中的地址;如果池中没有,则在堆中创建一份,然后返回堆中的地址(注意,此时不需要从堆中复制一份到池中,否则,将使得堆中的字符串永远是池中的子集,浪费池的空间);

3)使用只包含常量的字符串连接符如"aa"+"bb"创建的也是常量,编译期就能确定,存储在String Pool中;

4)使用包含变量的字符串连接符如s1+"aa"创建的对象是运行期才创建的,存储在heap中。

字符串的比较:

  如果我们想知道两个int类型变量是否相等,可以使用 == 进行验证,那么String中使用 == 是否可以验证呢,来看一个栗子:

  

package javaEE;
/**
* @author 047493
* @version 2018年8月31日
* 类说明
*/
public class Test12 {
public static void main(String[] args) { String str1 = "Hello";
String str2 = new String("Hello");
String str3 = str2; System.out.println(str1 == str2);
System.out.println(str2 == str3);
System.out.println(str1 == str3); }
}

运行结果:

false
true
false

造成此原因的内存关系图如下:

通过上图分析可知,== 比较的不是字符串对象包含的内容,而是两个对象所在的内存对象的数值。即 == 属于数值比较,比较的是内存地址。

如果想比较字符串的内容,可以使用equals()。栗子如下:

package javaEE;
/**
* @author 047493
* @version 2018年8月31日
* 类说明
*/
public class Test12 {
public static void main(String[] args) { String str1 = "Hello";
String str2 = new String("Hello");
String str3 = str2; System.out.println(str1.equals(str2));
System.out.println(str2.equals(str3));
System.out.println(str1.equals(str3)); }
}

运行结果如下:

true
true
true

字符串常量是匿名对象:
一个栗子,验证如下:

package javaEE;
/**
* @author 047493
* @version 2018年8月31日
* 类说明
*/
public class Test12 {
public static void main(String[] args) { String str1 = "Hello";
System.out.println("Hello".equals(str1));
}
}

运行结果如下:

true

匿名对象可以调用类中的方法和属性,而以上字符串调用了String类的equals(),所以它一定是一个对象。

String类对象两种实例化方式的区别:

(1)直接赋值的实例化方式:String str ="Hello";

内存关系图如下:

举个栗子:

package javaEE;
/**
* @author 047493
* @version 2018年8月31日
* 类说明
*/
public class Test12 {
public static void main(String[] args) { String str1 = "Hello";
String str2 = "Hello";
String str3 = "Hello"; System.out.println(str1 == str2);
System.out.println(str2 == str3);
System.out.println(str3 == str1); }
}

运行结果如下:

true
true
true

我们发现以上所有直接赋值的String类对象的内存地址完全相同,内存分配图如下:

在设计String类的时候采用了一种共享设计模式的概念。在运行的JVM底层存在一个字符串的对象池(object pool),如果用户才用了直接赋值的方式,会将字符串的内容放入池保存,如果以后其他字符串对象继续使用直接赋值方式实例化,且设置了同样的内容,那么将不会分配新的堆内存空间,而是使用已有对象的引用进行分配继续使用。如果新声明的字符串内容不在对象池中,则会分配一个新的,然后继续放到池中以供下次使用。由于String对象的不可变性,我们可以十分肯定字符串常量池中一定不存在两个相同的字符串。

(2)构造方法实例化方式:String str = new String("Hello");

构造方法实例化使用new关键字,而一旦使用new关键字就表示要分配新的内存空间。

内存分配图如下:

首先产生匿名对象"Hello",然后new关键字再次产生"Hello",并且str指向该字符串,原来的匿名对象变成垃圾,由GC回收。

可以发现,分配了两块内存空间,其中一块是垃圾。这样除了内存的浪费外,使用构造方法定义的String对象,其内容不会保存在对象中(因为重新分配了一块堆内存)。

现在希望使用构造方法定义的String类对象,其内容要保存在对象中,改怎么办?我们可以使用intern(),手工入池。

举个栗子:

package javaEE;
/**
* @author 047493
* @version 2018年8月31日
* 类说明
*/
public class Test12 {
public static void main(String[] args) { String str1 = new String("Hello").intern();
String str2 = "Hello";
String str3 = "Hello"; System.out.println(str1 == str2);
System.out.println(str2 == str3);
System.out.println(str3 == str1);
}
}

运行结果如下:

true
true
true

注意:在实际开发中我们不会采用构造方法进行字符串的实例化。

两种实例化方式的区别:

  (1)直接赋值方式:只会分配一块堆内存空间,并且对象内容自动入池,以供重复使用;

  (2)构造方法方式:会分配两块堆内存空间,其中有一块是垃圾,并且不会自动入池,可以调用intern()自动入池。

字符串的内容一旦定义则不可改变:

一个栗子:

package javaEE;
/**
* @author 047493
* @version 2018年8月31日
* 类说明
*/
public class Test12 {
public static void main(String[] args) { String str = "Hello ";
str +="World ";
str +="!!!";
System.out.println(str);
}
}

运行结果如下:

Hello World !!!

内存分析图如下:

通过内存分析图得知,字符串内容的改变,实际上改变的是字符串对象的引用过程,并且会伴随着大量的内存垃圾出现,在实际开发中应该避免。

那,如果我们要改变字符串的长度,应该怎么做呢?

可以使用可变字符串StringBuilder或StringBuffer。

StringBuilder和StringBuffer构建可变字符串对象都是通过new操作符调用构造方法,两者的区别在于StringBuilder应用于单线程环境,而StringBuffer应用于多线程环境。

StringBuilder的主要方法:

package javaEE;
/**
* @author 047493
* @version 2018年8月31日
* 类说明
*/
public class Test12 {
public static void main(String[] args) { StringBuilder sb = new StringBuilder();
sb.append("String is changed");
System.out.println(sb);
sb.insert(0, 123); //在字符串下标0处插入123
System.out.println(sb);
sb.delete(0, 3); //删除前3位字符串
//sb.delete(sb.length()-3, sb.length()); //删除sb字符串后面的3位字符
System.out.println(sb);
sb.replace(0, 3, "!!!"); //替换前3位字符串
System.out.println(sb);
sb.reverse(); //字符串翻转
System.out.println(sb);
sb.setCharAt(0, 'A'); //设置某个小标的字符内容
System.out.println(sb);
}
}

运行结果如下:

String is changed
123String is changed
String is changed
!!!ing is changed
degnahc si gni!!!
Aegnahc si gni!!!

即,凡是需要大量拼接字符串的地方都应该尽量使用可变字符串来完成,效率高且不占内存空间。

关于String类,面试中所常遇到的问题?

1)String str = new String("Hello"); "Hello"在内存中是怎么分配的?程序创建了几个对象?

这个题考察的是java中字符串常量池和JVM运行时数据区的相关概念。

内存分布可以参考下图:

那么创建了几个对象呢?答案是2个。

首先,出现了字面量“Hello”,那么先要在String Pool中查找是否存在相同的字符串,因为程序就这一行代码所以肯定没有,那么就在堆内存中用字面量“Hello”首先创建一个Hello对象;

接着,new String("Hello"),关键字new又在堆中创建了一个对象,然后调用接收String参数的构造器进行了初始化,最后str引用这个String对象。

2)String,StringBuffer,StringBuilder区别?

首先我们知道String是不可变的,当我们对操作String时,总会创建新的字符串,很耗费资源,所以java提供了两个工具类来操作String,StringBuffer,StringBuilder。

StringBuffer与StringBuilder都是可变类,功能相似。唯一不同的是StringBuffer是线程安全的,而StringBuilder是线程不安全的。所以在多线程对同一个字符串进行操作的时候,我们应该选择StringBuffer。但如果是单线程的情况下,StringBuilder的效率要高于StringBuffer。

关于字符串在各种情况下的比较,可以参考博主平凡希的文章,写的很详细:https://www.cnblogs.com/xiaoxi/p/6036701.html

参考资料:

https://blog.csdn.net/wei_zhi/article/details/52761081

https://www.cnblogs.com/fwnboke/p/8529453.html

Java_String的更多相关文章

  1. java_String和StringBuffer区别分析

    JAVA平台提供了两个类:String和StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据.这个String类提供了数值不可改变的字符串.而这个StringBuffer类提供 ...

  2. JAVA_String、StringBuilder、StringBuffer区别

    String.StringBuilder.StringBuffer均为字符串 类 需要注意的一些问题 String StringBuilder StringBuffer 一旦创建,不能对其内容进行更改 ...

  3. Java_String&StringBuilder&StringBuffer类

    目录 一.String类 二."==" 和 "equals"的区别 三.StringBuffer和StringBuilder 一.String类 String为 ...

  4. java_String、StringBuilder

    在介绍String和StringBuilder前先学习一下equals方法和toString方法.API java1.6提取码:04b6 equals方法 equals方法,用于比较两个对象是否相同, ...

  5. java_String类练习

    public class StringTest { //1.模拟trim方法,去除字符串两端的空格 public static void main(String[] args) { String st ...

  6. java_String类的功能

    String类使用了final修饰不能被继承 实现类Serializable接口,字符串支持序列化 实现了Comparable接口,字符串可以比较大小 内部定义final char[] value用于 ...

  7. java_String类、StringBuilder类、Arrays类、Math类的使用

    String类 java.lang.String 类代表字符串.Java程序中所有的字符串文字(例如 “abc” )都可以被看作是实现此类的实例 构造方法 java.lang.String :此类不需 ...

  8. Myeclipse黑色主题配置

    Myeclipse自己打造黑色主题: 一.UI Theme(设置黑色主题模式): 如果是自己下载在的.jar主题,则首先将该jar包放在Myeclipse安装目录下的\dropins\plugins\ ...

  9. eclipse 更改背景颜色字体

    原文 切一个自己的图: 废话不说,直接入题. 方式一:替换Eclipse的配置文件 其实Eclipse的各种配置都是在文件设置里的,因此只要用一个配置好的模版来替换默认的配置文件,即可将所有配置克隆到 ...

随机推荐

  1. MS SQL Server 数据库连接字符串详解

    MS SQL Server 数据库连接字符串详解 原地址:http://blog.csdn.net/jhhja/article/details/6096565 问题 : 超时时间已到.在从池中获取连接 ...

  2. Vim使用技巧汇总

    一 写在开头 1.1 本文内容 Vim使用技巧与学习资源汇总. 二 Vim学习资源 1. Vimtutor 2. Vim中文帮助(http://vimcdoc.sourceforge.net/doc/ ...

  3. 【转】Reflector、reflexil、De4Dot、IL相关操作指令合集

    PS:CTRL+F 输入你需要的内容,可以快速查找页面上的内容. 名称 说明 Add 将两个值相加并将结果推送到计算堆栈上. Add.Ovf 将两个整数相加,执行溢出检查,并且将结果推送到计算堆栈上. ...

  4. django - 总结 - 跨域请求

    script ->jsonp跨域 浏览器的同源策略:不能跨越网站请求信息: XMLHttpRequests遵循这个规定. 因此ajax等基于XML的都不能进行跨站请求 而我们知道img,ifra ...

  5. SHELL希尔排序

    /****************************************************************************** * Compilation: javac ...

  6. mysql数据库truncate表时间长处理

    [环境介绍] 系统环境:Linux + mysql 5.7.18 + 主从复制架构 [背景描述] 客户反映用在mysql数据库上truncate一个innode引擎的list分区100G左右表时,耗时 ...

  7. pycharm实用快捷键集锦

    以下是本人需要记录的快捷键,并不针对大众,所以是断断续续补充的,大家看看图个乐呵就成! 生成代码块(Surround with):Ctrl + Alt + t . 历史浏览页面跳转:很多时候,我们需要 ...

  8. from中buttone 和 input type="button" 区别

    在做一个表单提交时碰到的问题, 1.js判断阻止表单提交,如果是form 里面的button的话,恭喜你,你要再换个写法了.<button type="submit" ... ...

  9. 题解 P4692 【[Ynoi2016]谁的梦】

    Ynoi 中少见的不卡常题呢....虽说有 50 个数据点... 果然还是道好题 noteskey 总之就是补集转化的思想,算出每种颜色选点的总方案减去不可行方案(就是不包含 该种颜色的点的区间选取方 ...

  10. Laravel -- 邮箱功能配置问题

    ```` 今天碰到了这块的问题,还是记一下 ```` 关于邮箱: 品牌:腾讯qq.网易163 等 种类:个人.企业 邮箱服务器种类 配置教程 https://jingyan.baidu.com/art ...