string类
一、String类介绍:
String是一个引用数据类型默认为null;
String 为final类型不可更改,不能被继承;
基本类型与String结合都会转换为String类型;
二、String两种赋值方式:
1)直接赋值:String str = " ";
String str = "" 原理:
在 JVM(虚拟机)中有一个字符串池,专门用来存储字符串。如果遇到 String a=”hello”时(注意没有 NEW,不是创建新串),系统在字符串池中寻找是否有 ”hello”,
此时字符串池中没有”hello”,那么系统将此字符串存到字符串池中,然后将 ”hello”在字符串池中的地址返回 a。
如果系统再遇到String b=”hello”,此时系统可以在字符串池中找到 “hello”。则会把地址返回b,此时 a与b 为相同。
2)使用new进行赋值:String str = new String (" ");
3) 两种赋值方式的区别:
1、直接定义的String "a"是储存在常量存储区中的字符串常量池中;new String(“a”)是存储在堆中;
2、常量池中相同的字符串只有一个,但是new String(),每new一个对象就会在堆中新建一个对象;
3、String a = “a”在编译阶段就会在内存中创建;String a = new String(“a”);是在运行时才会在堆中创建对象;
String a = "hello";
String b = "hello";
System.out.println(a == b );//true a b 指向同一个值,地址相同
System.out.println(a.equals(b));//true a b 是同一个值,当然相等
String a1 = new String ("hello");
String b1 = new String ("hello");
System.out.println(a1 == b1 );//false 每次new都会创建一个新对象,a1 b1 地址不同
System.out.println(a1 .equals(b1) );//true
由此可以得出两种实例化方式的区别
1)直接赋值(String str = "hello"):只开辟一块堆内存空间,并且会自动入池,不会产生垃圾。
2)构造方法(String str= new String("hello");):会开辟两块堆内存空间,其中一块堆内存会变成垃圾被系统回收
在开发的过程中不会采用构造方法进行字符串的实例化。
4)常量池
字符串常量池在jdk1.6及之前在方法区中,但是在jdk1.7及以后就放在了堆中
编译阶段确定的字符串才会被放到字符串常量池中
分析下面创建几个对象:
String s1 = "java";
String s2 = "从0到1";
String s3 = "java从0到1";
String s4 = s1+s2;
System.out.println(s3==s4);
s1和s2还有s4都会在字符串常量池中,这已经有三个对象了 。关键在于这行代码上String s3 = s1 + s2;
对于s3无法在编译阶段确定下来,所以无论最后的字符串是什么都不会存在字符串常量池中,那么存在哪呢?因为对象创建在堆中,而字符串常量池也在堆中,既然不在字符串常量池中那就是在字符串常量池之外的堆中了,而s3最终的字符串对象是“Java从0到1”,那么也就是说这个字符串在常量池之外的堆中,这是一个对象了,加上之前的三个,这里一共四个了,但是我们还要分析这个s3是怎么来的,是通过s1和s2相加得到的,因为这个s3最终是在常量池之外的堆中形成的,而s1和s2都是在常量池中,因此会将s1和s2拷贝一份到字符串常量池之外的堆中来形成s3,我们看下面的一张图来加深理解
堆内存复制s1,s2,这样的话要再加上两个对象,那一共就是创建6个对象了!
三、String源码解析:
Jdk1.7 的String源码如下:
public final class String
implements java.io.serializable, Comparable<String>, Charsequence {
/** The value is used for character storage. */
private final char value[];
/** cache the hash code for the string */
private int hash; // Default to 0
由以上的代码可以看出, 在Java中String类其实就是对字符数组的封装,除此之外还有一个hash成员变量,是该String对象的哈希值的缓存。
value这个变量是final的, 也就是说在String类内部,一旦这个值初始化了, 也不能被改变。所以可以认为String对象是不可变的了。
String s = new ("ABCabc"); 对应的内存模型为:
当我们调用a.replace('A', 'a')时, 方法内部创建了一个新的String对象,并把这个新的对象重新赋给了引用a;
因此结果为 aBCabc
Spring是否真的是不可变?
我们知道被final修饰的引用类型变量是引用的地址不可变,而不是引用的值不可变,因此我们能否改变value数组的值而使String改变???答案当然是可以的,反射可以搞定。
反射可以访问私有成员,因此我们可以反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。
public static void testReflection() throws Exception {
//创建字符串"hello world", 并赋给引用s
String s = "Hello World";
System.out.println("s = " + s); //Hello World
//获取String类中的value字段
field valueFieldOfString = String.class.getDeclaredField("value");
//改变value属性的访问权限
valueFieldOfString.setaccessible(true);
//获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s);
//改变value所引用的数组中的第5个字符
value[5] = '_';
System.out.println("s = " + s); //Hello_World
}
在这个过程中,s始终引用的同一个String对象,但是再反射前后,这个String对象发生了变化, 也就是说,通过反射是可以修改所谓的“不可变”对象的。但是一般我们不这么做。这个反射的实例还可以说明一个问题:如果一个对象,他组合的其他对象的状态是可以改变的,那么这个对象很可能不是不可变对象。例如一个Car对象,它组合了一个Wheel对象,虽然这个Wheel对象声明成了private final 的,但是这个Wheel对象内部的状态可以改变, 那么就不能很好的保证Car对象不可变。
四、String进行字符串拼接:
拼接原理:String是字符串常量的引用,String += String的本质是new了新的临时对象Stringbuild,拼接后再把StringBuild.toString赋给原String。
String s="a"+"b"+"c"+"d"; 实际只创建了一个对象 ,过程是new 了 一个临时的StringBuild,然后把"a"+"b"+"c"+"d"进行拼接,结果"abcd".toString 返回gei s;
所有大量字符串拼接不要直接使用String,否则会生成大量临时对象,严重影响性能。
五、String,StringBuffer, stringbuilder比较:
1、String是字符串常量,StringBuffer和StringBuilder都是字符串变量。后两者的字符内容可变,而前者创建后内容不可变(String进行字符串拼接时创建新对象)。
2、StringBuffer是线程安全的,而StringBuilder是非线程安全的。
3.线程安全会带来额外的系统开销,所以StringBuilder的效率比StringBuffer高。如果对系统中的线程是否安全很掌握,
可用StringBuffer,在线程不安全处加上关键字Synchronize。
4. StringBuffer 和 StringBuilder 要调用.toString方法在进行比较
相关阅读
七、输入/输出流--基于字符串的流---basic_ostringstr
3 basic_ostringstream模板 basic_ostringstream模板支持写入basic_string对象,使用basic_stringbuf控制相关存储区域; 定义: tem
转自:http://blog.sina.com.cn/s/blog_9d85c1900102v1rm.html区别:主要是两者的参数不同功能:相似 substr :返回一个从
在使用C++编程的时候,有时会输入一段英文句子,如果使用Python原因的话,那么直接使用 split() 函数就好了。那么使用C++有没有方便的
java.lang.NumberFormatException: For input string:
我遇到的这个错误是在执行查询的时候遇到的错误,所以就不说因为类型转换引起的原因了 先贴上相关的sql 其实报这个错误的原因就是
package java.lang; import java.util.Arrays; /** * A thread-safe, mutable sequence of characters. * A string buffer i