java.lang.String
构造函数
String(byte[] bytes, Charset charset)
通过使用指定的 charset 解码指定的 byte 数组,构造一个新的 String。String(char[] value)
分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。该字符数组的内容已被复制,后续对字符数组的修改不会影响新创建的字符串。
方法
- public String replace(char oldChar, char newChar)
如果 oldChar 在此 String 对象表示的字符序列中没有出现,则返回对此 String 对象的引用。否则,创建一个新的 String 对象,它所表示的字符序列除了所有的 oldChar 都被替换为 newChar 之外,与此 String 对象表示的字符序列相同。
String s = "123";
s.replace("1", "2");
System.out.println(s);
输出:123 是新建了一个String 对原来的String没有影响
public String intern()
当调用 intern 方法时,如果字符串常量池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回此 String 对象的引用。public String[] split(String regex)
public String toLowerCase()
public String toUpperCase()
public String trim()
返回字符串的副本,忽略前导空白和尾部空白。重写了equal()方法 重写了hashcode方法
注意
三种新建方式
String s = “123”;
JVM通过字符串常量池查找不到内容为123的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量s。String s = new String(“123”);
当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。使用+串联,生成新的字符串
字符串常量池中存放的时引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。常量池在方法区中,道理是一样的,方法区中也是静态变量的引用,具体是在堆上分布内存参照这篇,注意perm的大小。
- 字符串的拼接+
String name = "Andy";
String age = "24";
String job = "Developer";
String info = name + age + job;
实际上编译器做了优化,内部是这样处理的:
new StringBuilder()
StringBuilder.init()
StringBuilder.append()
StringBuilder.toString()
- 当使用任何方式来创建一个字符串对象时,运行中JVM会在String池中找是否存在内容相同的字符串对象,如果不存在,则在池中创建一个字符串s,否则,不在池中添加。
- Java中,只要使用new关键字来创建对象,则一定会(在堆区或栈区)创建一个新的对象。
- 使用直接指定或者使用纯字符串串联来创建String对象,则仅仅会检查维护String池中的字符串,池中没有就在池中创建一个.
- 使用包含变量的表达式来创建String对象,则不仅会检查维护String池,而且还会在堆栈区创建一个String对象。
String a=”a”+”b”+”c”在内存中创建几个对象?
知乎上的回答:javac会进行常量折叠,全字面量字符串相加是可以折叠为一个字面常量,而且是进入常量池的。
String str=new String("abc");
这行代码究竟创建了几个String对象:
public String(String original)
初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。”abc”作为构造函数的参数先被初始化,然后是new过程。所以是两个对象。关于深入理解JVM书中的String.intern()的方法的理解
String a = "qwer";
String b = new String("qwer");
System.out.println(a==b);
System.out.println(b==b.intern());
String c = new String("计算机");
String ci = c.intern();
System.out.println(ci==c);
String stri1 = new StringBuilder("计算机er").append("qw").toString();
System.out.println(stri1.intern()==stri1);
false
false
false
true
我的理解:文中提到了字符串常量池中存放的时引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。我看了深入理解JVM,p57,在JDK1.6及之前的版本中,常量池分配在永久代,intern()方法会把首次遇到的字符串实例复制。记住是复制,到永久代,返回这个永久代中这个字符串实例的引用,所以在JVM这本书里面,他用了JDK1.6去实现永久代溢出。在JDK1.6之后,不再复制,只是在常量池中记录首次出现的示例引用,常量池中是引用,不再是对象,所以文章中的验证方式不会导致永久代溢出。
关于上述程序中,我这样理解String c = new String(“计算机”);
这句话编译的时候,遇到”计算机”的时候,编译器会把他放进常量池,运行的时候,堆中新建了一个String对象,此时内存中有两个地方可以找到”计算机”,c.intern()返回的引用是常量池中的引用(因为编译的时候,常量池中已经有”计算机了”),所以ci==c返回false.
但是String stri1 = new StringBuilder(“计算机er”).append(“qw”).toString();注意用了append(),编译器只能把”计算机er” “qw”放进常量池,运行的时候才有”计算机erqw”,编译后常量池里面的没有的,stri1.intern()==stri1返回的一个东西,(stri1.intern()这句话让常量池多了一个引用,指向我们的String对象)
java.lang.StringBuilder StringBuffer
构造函数
- 略
方法
- 增:append() insert()
- 删:delete()
- 改:replace() reverse() substring()
方法比较面向对象。
注意
StringBuffer和StringBuilder这两者的方法没有很大区别。但在线程安全性方面,StringBuffer允许多线程进行字符操作。这是因为在源代码中StringBuffer的很多方法都被关键字synchronized 修饰了,而StringBuilder没有。