`

String深入理解

    博客分类:
  • java
阅读更多

String对象是不可变的,每个看起来会修改String对象的方法,实际上都是创建了一个新建的String对象,最初的String对象则丝毫未动。

public class Immutable {
	public static String upcase(String s) {
		return s.toUpperCase();
	}
	
	public static void main(String[] args) {
		String q = "howdy";
		String qq = upcase(q);
		System.out.println(qq);
		System.out.println(q);
	}
}

 

Output:

howdy

HOWDY

howdy

 

当把q传递给upcase方法时,实际上传递的是q引用的一个拷贝。

 

下面通过一些例子来说明String类型的一些特性,以及不同方式创建String对象的区别:

例1:

private static void test1() {
	String a = "a" + "b" + 1;
	String b = "ab1";
	System.out.println(a == b);
}

 

这个例子返回true;很多人会感到很奇怪,==操作符不是判断两个引用(如果对象不是基本数据类型)是否相等的嘛,怎么会是true呢?

那是因为,当编译器在编译代码:String a = "a" + "b" + 1;时,会将其编译为:String a = "ab1";。为何?因为都是“常量”,编译器认为这3个常量叠加会得到固定的值,无须运行时再进行计算,所以就会这样优化。

例如,就拿上面叠加字符串的例子来说,如果几个字符串叠加中出现了“变量”,即在编译时,还不确定具体的值是多少,那么JVM 是不会去做这样的编译时合并的。

 

例2:

private static String getA() {
	return "a";
}
public static void test2() {
	String a = "a";
	final String c = "a";
	String b = a + "b";
	String d = c + "b";
	String e = getA() + "b";
	String compare = "ab";
	System.out.println(b == compare);
	System.out.println(d == compare);
	System.out.println(e == compare);
}

 

结果:

false

true

false

第 1 个输出false。

“b”与“compare”对比,compare 是一个常量,那么b为什么不是呢?因为b = a +"b",a并不是一个常量,虽然a作为一个局部变量,它也指向一个常量,但是其引用上并未“强制约束”是不可以被改变的。虽然知道它在这段代码中是不会改变的,但运行时任何事情都会发生,尤其是在“字节码增强”技术面前,当代码发生切入后,就可能发生改变。所以编译器是不会做这样优化的,所以此时在进行“+”运算时会被编译为下面类似的结果:

StringBuilder temp = new StringBuilder();

temp.append(a).append("b");

String b = temp.toString();

 

第二个输出true。

因为c被声明为一个final变量,也就是不可变的,所以编译器会进行优化

 

第三个输出false。

虽然getA()返回一个常量的引用,但是编译器并不会去看方法内部做了什么。另外,即使返回的是一个常量,但是它是对常量的引用实现一份拷贝返回的,这份拷贝并不是final 的。

 

编译器优化一定是在编译阶段能确定优化后不会影响整体功能,类似于final引用,这个引用只能被赋值一次,但是它无法确定赋值的内容是什么。只有在编译阶段能确定这个final引用赋值的内容,编译器才有可能进行编译时优化(请不要和运行时的操作扯到一起,那样你可能理解不清楚),而在编译阶段能确定的内容只能来自于常量池中,例如int、long、String 等常量,也就是不包含new String()、new Integer()这样的操作,因为这

是运行时决定的,也不包含方法的返回值。因为运行时它可能返回不同的值,带着这个基本思想,对于编译时的优化理解就基本不会出错了。

 

例3:

public static void test3() {
	String a = "a";
	String b = a + "b";
	String c = "ab";
	String d = new String(b);
	String str1 = "java";// 指向字符串池
	String str2 = "blog";// 指向字符串池
	String s = str1 + str2;
	System.out.println(b == c);
	System.out.println(c == d);
	System.out.println(c == d.intern());
	System.out.println(b.intern() == d.intern());
	System.out.println(s == "javablog");
}

结果:

false

false

true

true

false

第一个和第二个false上面的例子已经解释过了。

 

第三个和第四个true。

当调用 intern()方法时,JVM 会在这个常量池中通过equals()方法查找是否存在等值的String,如果存在,则直接返回常量池中这个String对象的地址;若没有找到,则会创建等值的字符串(即等值的char[]数组字符串,但是char[]是新开辟的一

份拷贝空间),然后再返回这个新创建空间的地址。只要是同样的字符串,当调用intern()方法时,都会得到常量池中对应String 的引用,所以两个字符串通过intern()操作后用等号是可以匹配的。

 

第五个false。

String str1="java";//指向字符串池

String str2="blog";//指向字符串池

String   s = str1+str2; 

+运算符会在堆中建立起两个String对象,这两个对象的值分别是“java”,"blog",也就是说从字符串常量池中复制这两个值,然后再堆中创建两个对象。然后再建立对象s,然后将“javablog”的堆地址赋给s。这句话共创建了3个String对象。这时s指向的是堆内存中地址。

 

总之,创建字符串有两种方式:两种内存区域(pool,heap)

1.""创建的字符串在字符串池中。

2.new 创建字符串时,首先查看池中是否有相同的字符串,如果有则拷贝一份放到堆中,然后返回堆中的地址;如果池中没有则在堆中创建一分,然后返回堆中的地址,

3.在对字符串赋值时,如果右操作数含有一个或一个以上的字符串引用时,则在堆中再建立一个字符串对象,返回引用如:String s= str1+"blog";

 

String内建对正则表达式的支持

matches(String regex);

split(String regex);

split(String regex, int limit);   limit限制字符串分割的次数;

replaceFirst(String regex, String replacement);

replaceAll(String regex, String replacement);

 

参考:

java特种兵

分享到:
评论

相关推荐

    C++ string深入详解(最新版)

    ### C++ `string` 类深入详解 #### 一、C++ 的 `string` 使用 ##### 1.1 C++ `string` 简介 在 C++ 中,`string` 类是一个非常重要的类,它提供了丰富的接口来处理字符串。与 C 语言中的字符数组不同,`string` ...

    对String的深入理解

    【对String的深入理解】 String类在Java编程中扮演着至关重要的角色,它不仅涉及到基本的字符串操作,还涉及到内存管理、性能优化等多个方面。在深入理解String时,我们需要掌握以下几个关键知识点: 1. 引用变量...

    深入了解java 中的String

    深入了解Java中的String类是至关重要的,因为String在Java编程中占据着极其重要的位置。下面将对给定的信息进行深入分析: ### 1. String 类是 final 的,不可被继承 在Java中,`String` 类被声明为 `final` 类型...

    java String的深入理解

    Java String 深入理解 Java String 是 Java 语言中最基本的数据类型之一,然而,许多开发者对 String 的理解仅停留在表面,今天我们将深入了解 Java String 的内部机理和使用方法。 Java 字符串池 Java 字符串池...

    深入学习C++_String2.1版

    本教程"深入学习C++_String2.1版"旨在帮助开发者更全面、深入地理解`std::string`类及其在实际编程中的应用。以下是对这个主题的详细探讨: 一、`std::string`类的基本概念 `std::string`是一个容器类,用于存储可...

    小心String的陷阱——深入剖析Java中String的处理机制

    深入理解Java中`String`的处理机制对于避免陷阱至关重要。`String`的不可变性和`String Pool`的存在是为了提升性能和安全性,但同时也要求开发者在创建和使用`String`对象时采取正确的方法,以避免不必要的性能损耗...

    Ruby语言中的String深入理解

    Ruby语言中的String是mutable的,不像java、C#中的String是immutable的。比如 代码如下: str1=”abc” str2=”abc” 在java中,对于字面量的字符串,jvm内部维持一张表,因此如果在java中,str1和str2是同一个String...

    C string深入详解2.0版_C++_string_

    理解并熟练使用`std::string`对于C++程序员来说至关重要,无论是日常开发还是面试中,这都是考察C++基础能力的重要部分。通过深入学习`std::string`,开发者可以更高效地处理文本数据,提高代码质量。

    String和string区别以及string详解.doc

    标题与描述中提到的知识点是关于C#编程语言中`String`与`string`的区别,以及`string`类型的...通过以上分析,我们可以深入了解C#中`String`与`string`的区别及其使用细节,这对于提高代码质量和程序性能具有重要意义。

    C++笔试面试宝典2009版与C++ String深入详解2.0版

    “C++ String深入详解2.0版”深入探讨了C++标准库中的std::string类,不仅包括了构造、赋值、比较、查找、插入、删除等操作的详细用法,还可能讨论了如何在C++字符串与传统C风格字符数组之间进行有效交互,帮助...

    深入了解C#的String类.zip

    在深入探讨`String`类之前,先要理解C#与SQL Server数据库技术的结合,因为这两个领域的知识是现代软件开发中的基础。`String`类在处理SQL查询时经常扮演关键角色,例如构建SQL语句、存储和检索数据库中的文本数据。...

    《深入学习c++string》2.1版

    《深入学习C++ string》2.1版详细解读 C++中的`std::string`是C++标准库中一个非常重要的容器,它用于存储和操作文本...通过深入理解这些知识点,可以更好地在C++项目中利用`std::string`进行高效、安全的文本处理。

    深入学习C++ string 2.1

    通过深入学习`std::string`,你可以更好地理解和利用C++中的字符串处理能力,提高代码质量,减少因字符操作引起的错误。无论是编写简单的命令行工具还是复杂的系统应用,掌握`string`的用法都是必不可少的。

    深入理解JVM实战篇-String类1

    《深入理解JVM实战篇-String类》 在Java编程中,String类是使用最频繁的类之一,它涉及到许多底层机制,特别是与JVM(Java虚拟机)的交互。本文将探讨String类的一些关键特性,包括字面量与运行时常量池、String的...

    深入学习C++_String

    ### 深入学习C++ String #### 一、C++的string的使用 ##### 1.1 C++ string简介 在C++中,`std::string`是用于处理文本数据的标准库的一部分,它提供了丰富的功能来管理和操作字符串。与传统的C风格字符串不同,`...

    String对象创建问题

    这里我们将深入探讨`String`对象在编译期和执行期的创建方式以及它们之间的差异。 首先,我们来了解一下编译期的`String`对象创建,这通常与字符串字面量有关。在Java源代码中,当使用双引号定义一个字符串,例如`...

    深入理解 Java String#intern() 内存模型.docx

    "深入理解 Java String#intern() 内存模型" Java String#intern() 内存模型是 Java 语言中一个重要的概念,.string#intern() 方法是 Java 字符串常量池中一个重要的组件。字符串常量池是一个固定大小的 HashMap,桶...

    深入理解JavaString#intern()内存模型Ja

    深入理解`String#intern()`方法对于优化内存使用和理解Java的内存模型至关重要。`intern()`方法是一个非常特殊的函数,它将字符串常量池(String Constant Pool)的概念引入到我们的讨论中。 字符串常量池是Java...

    String和string区别以及string详解

    本文将深入探讨`String`和`string`的区别,并对`string`类型进行详尽的解释。 首先,`String`和`string`在C#中实际上是指同一个东西,都是System.String类的别名。C#设计者为了提高代码的可读性,推荐在编写代码时...

    C#_String与string的区别

    本文将深入探讨C#中`String`与`string`之间的区别,帮助开发者更好地理解和使用这两种类型。 #### 1. 基本定义 首先,`string`是C#中的一个关键字,它实际上是`System.String`类型的别名。这意味着`string`并非C#...

Global site tag (gtag.js) - Google Analytics