7.4.4 String对象问题

String是Java中使用频率第一的类,以前在CSDN论坛上,至少每个月都有相关的贴子,讨论==和equals()。

本节介绍这一部分的内容,也有一个重要更正



String文字在程序中被大量地使用。String文字作为引用,指向一个String对象。例如"baby"指向的一个String对象,该对象保存的数据主要有一个char[]引用和3个int值

字符串拘留

为了有效地利用堆,加快字符串处理效率(以==比较替代equals(Object)比较),多种语言如Java、C#和Python等,都支持字符串拘留/集中营(string interning)技术,即对每一个不同的字符串值仅保存一个拷贝(前提是它必须是不变对象)。

Java中两种拘留方式:

编译器将一个类中所有的String文字和常量表达式(如"ba"+"by"、"ba"+3+2等)加以分析,求出常量表达式的结果——String文字,然后仅仅将不同的String文字表示为class文件的各个CONSTANT_String_info项(相同的这时就统一了)。在类载入时,按照它的符号引用CONSTANT_Utf8_info,提取二进制表示的各字符并在“堆”中创建String对象,并将该对象的引用在一个HashMap中注册。

在HashMap中注册过的所有String对象的集合,有时候称为字符串池(string interning pool)。该HashMap驻留在方法区,而字符串池在堆中(注意,如同Java不在栈中分配对象空间一样,仅仅具有逻辑上的含义)。

package jvm.internedStrings;
public class OnlyOneCopy{
    static String str1 = "abc";
    String str2 = "a"+"bc";
    public void foo(){
        String str3 = "a"+"b"+'c'; // 'c'不是"c"
        System.out.println(str1==str3);
    }
}

载入OnlyOneCopy 时,JVM按照class文件的常量池中CONSTANT_String_info项创建一个String对象。因为编译器自动支持字符串拘留技术,因而将刚才创建的String对象的引用"abc"在HashMap中注册并交给不知名变量(假定为#2)保存。类的初始化阶段,静态变量str1被初始化,即取出#2的引用赋值"abc"给str1;当在某处创建OnlyOneCopy对象时,将初始化其实例域str2,即将#2的值赋值给str2;当某个程序调用方法foo()时,将#2的值赋值给str3。

最后的结果是:通过==可以判断str1、str2和str3三者指向同一个对象

但要注意,如果字符串的连接操作符中包含变量,则编译器无法足够聪明地确定该表达式的值。例如String str1 = "abc";String
str2 =str1+ "";

str1和 str2 指向不同的对象。

如果要减少多个字符串拷贝,有两个手段达到该目的:以final修饰str1;使用String的intern()方法,如str2= (str1+""). intern()。

xxx.intern()意味着将xxx的内容通过equals(Object)方法,判断HashMap中是否存在一个可用的引用。如果存在则将该引用作为xxx自己的引用;如果不存在,则将xxx的值在HashMap中注册,本String对象入池。字符串池中的String对象能否被垃圾回收?在现代的JVM实现中,一个被拘String对象,如果它不是编译时常量而且它不再被引用,则可以被垃圾回收。

字符子串

String 类的substring(int begin,intend)返回消息接受对象的范围为[begin.. end)的子字符串对象,而且该String对象是没有被拘留的。

我们知道,String对象保存的数据主要有一个char[]引用和几个int值。JVM创建子字符串对象本身的代价极小,代价主要在char[]变量v指向的char[]。

String str =  "abc……十万个为什么".substring(0,1);

创建的子字符串对象时,并不需要复制任何字符,子字符串和原字符串对象共享一个底层char[]对象,子字符串不过对原String对象的几个int成员变量(偏移量、长度等)加以更改。

这句话在Java 7u6之前是对的,但是之后已经被修改。原因是str只需要一个字符但是整个char[]-10W长度的空间得不到释放。

//JDK 6
String(int offset, int count, char value[]) {
	this.value = value;
	this.offset = offset;
	this.count = count;
}

public String substring(int beginIndex, int endIndex) {
	//check boundary
	return  new String(offset + beginIndex, endIndex - beginIndex, value);
}

//JDK 7
public String(char value[], int offset, int count) {
	//check boundary
	this.value = Arrays.copyOfRange(value, offset, offset + count);
}

public String substring(int beginIndex, int endIndex) {
	//check boundary
	int subLen = endIndex - beginIndex;
	return new String(value, beginIndex, subLen);
}

【图 7-10 子字符串对象】从上图更正为下图。

时间: 2024-10-09 10:42:12

7.4.4 String对象问题的相关文章

String s=new String("xyz");创建几个String对象的问题

首先让我们了解几个概念: 栈 :由JVM分配区域,用于保存线程执行的动作和数据引用. 堆 :由JVM分配的,用于存储对象等数据的区域. 常量池constant pool :在堆中分配出来的一块存储区域,用于存储显式 的String,float或者integer.这是一个特殊的共享区域,可以在内存中共享的不经常改变的东西,都可以放在这里. 进入正题: String a = "abc";①String b = "abc";② 使用String a = "abc

实习第二天-String对象的不可变性-未解决

public class Reverse { public static void main(String[] args) { String c1=new String("abc"); String c2=new String("abc"); String c3=c1; System.out.println("c1==c2:"+ (c1==c2)); //c1==c2:false 第一个输出语句c1==c2很好理解,因为c1和c2都是用new 创

C风格字符串和C++ string 对象赋值操作的性能比较

<<C++ Primer>> 第四版 Exercise Section 4.3.1 部分Exercise 4.2.9 习题如下: 在自己本机执行如下程序,记录程序执行时间: 1 #include "stdafx.h" 2 #include <iostream> 3 #include <string> 4 #include <vector> 5 #include <ctime> 6 7 using namespace

&lt;JavaScript&gt; 一. string对象的属性和方法

1 <!DOCTYPE html> 2 <html> 3 <head> 4 <title></title> 5 <script type="text/javascript"> 6 /* 7 string 对象 8 */ 9 10 // ------------- 属性 ------------- 11 // 1. length属性: 获取字符串的长度 12 var str = "Hello, world!

string 对象及其操作

标准库类型string 标准库类型string表示可变长的字符序列,使用string类型必须首先包含string头文件.作为标准库的一部分,string定义在命名空间std中.接下来的示例都假定了已包含了下述代码: #include <string> using std::string; 本节描述最常用的string操作. 定义和初始化string对象 如何初始化类的对象是由类本身决定的.一个类可以定义很多种初始化对象的方式,只不过这些方式之间必须有所区别:或者是初始值的数量有所区别,或者是初

JavaScript中的String对象

String对象提供的方法用于处理字符串及字符. 常用的一些方法: charAt(index):返回字符串中index处的字符. indexOf(searchValue,[fromIndex]):该方法在字符串中寻找第一次出现的searchValue.如果给定了fromIndex,则从字符串内该位置开始搜索,当searchValue找到后,返回该串第一个字符的位置. lastIndexOf(searchValue,[fromIndex]):从字符串的尾部向前搜索searchValue,并报告找到

java 创建string对象机制 字符串缓冲池 字符串拼接机制

1.String str = new String("hello"); 创建了2个对象,1.检查常量池中有没有hello,没有的话,创建对象放到常量池中,再创建对象放到堆中.如果常量池有hello对象,则只创建一个对象并放到堆中. 2.字符串常量池在方法区 3.String str = "hello";检查常量池有无hello,如果有,则把指向该对象,如果没有,创建对象放在常量池里. 4.intern()方法.把字符串变成常量池里的字符串:如果常量池中已经包含了等于

String对象的属性和方法

创建字符串的两种方法: 1.直接量:var str = ""; 2.字符串对象创建: new String(""); String对象的属性 1.constrcutor 2.prototype 3.length:   str.length可以获取字符串长度 String对象的方法 1.匹配相关:与正则表达式配合使用 (1)str.match(RegExp):匹配指定字符串 (2)str.replace(RegExp):替换指定字符 (3)str.search(Reg

数组对象元素的添加,String对象,BOM对象以及文档对象的获取

数组对象的删除有三种方法: pop();        //移除最后一个元素并返回该元素值shift();      //移除最前一个元素并返回该元素值,数组中元素自动前移splice(0,2); //删除从指定位置deletePos开始的指定数量deleteCount的元素,数组形式返回所移除的元素通过这三种方法我们可以将数组中的元素按进行删除 var del = ["aa",23,345,56,34,"bb"]; var del_last = del.pop()

string对象

string对象用于处理文本(字符串).在js中可以用单引号或者双引号括起来的一个字符串当做一个字符串对象的实例.所以可以在某个字符串后面加上 . 去调用string对象的属性和方法. 创建string对象的语法: new String(str); String(str); 参数: str 是要存储在String对象中或转换成原始字符串的值. 返回值: 当string()和运算符 new 一起作为构造函数使用时,它返回一个新创建的String 对象,存放的是字符串str或str的字符串表示. 当