1.String 类型不可改变

        String类型是public final class String,而其实现主要是private final char value[],

这里 final 修饰基本数据类型,不可被更改,

修饰引用数据类型不可指向其他对象,

修饰方法,该方法不可被重写,

修饰类,不可被继承。

public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "abc";
        s1 = "def";
        System.out.println(s1 == s2);
        System.out.println(s1);
        System.out.println(s2);

    }

第一个问题 为什么String不可变,s1却可以被重新赋值?

        主要原因还是String里的final修饰的数组不可指向其他对象,而String类只是不可被继承。仿照String自己实现OOO类。

import java.util.Arrays;
public final class OOO {
	private final char value[];
	public OOO(char[] value) {
		this.value = value;
	}
	@Override
	public String toString() {
		return "OOO{" +
			"value=" + Arrays.toString(value) +
			'}';
	}
}

 

string为什么不能memset_string为什么不能memset

 String代表不可变的字符序列

        当字符串重新赋值,需要重写指定内存区域赋值,不能使用原有的value进行赋值

        当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能对使用原有的value进行赋值

        当调用String的replace方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。

一道面试题

public class StringTest {
	String str = new String("good");
	char[] ch = {'t', 'e', 's', 't'};
	
	public void change(String str, char ch[]) {
		str = "test ok";
		ch[0] = 'b';
	}
	
	public static void main(String[] args) {
		StringTest ex = new StringTest();
		ex.change(ex.str, ex.ch);
		System.out.println(ex.str);//good
		System.out.println(ex.ch);//best
	}
}

这里char ch[]是一定会变化的,因为Java的值传递。

        对于基本类型 ,赋值运算符会直接改变变量的值,原来的值被覆盖。         对于引用类型,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变。

这里ch[]是引用数据类型,所以是一定会改变的,但如果是下面这样ch[]也是不会改变的。

string为什么不能memset_java-ee_02

也就是说 change 方法的参数拷贝的是 ch[](实参)的地址,因此,它和 ch 指向的是同一个数组对象。这也就说明了为什么方法内部对形参的修改会影响到实参。

今天在看Java设计模式时,在享元模式中,作者说了这样一段

JDK类库中的String类使用了享元模式

public static void main(String[] args) { String a = "abcd"; String b = "abcd"; String c = "ab" + "cd"; String d = "ab"; d += "cd"; System.out.println(a == b); //true System.out.println(a == c); //true System.out.println(a == d); //false b += "e"; d = d.intern(); System.out.println(a == d); //true System.out.println(a == b); //false }

Java String类这种在修改享元对象时先将原有对象复制一份,然后在新对象上实现修改操作的机制叫做“Copy On Write”。

 这也就对应了

  1. 常量与常量的拼接结果在常量池,原理是编译期优化(a==c)
  2. 常量池中不会存在相同内容的变量(a==b)
  3. 拼接前后,只要其中有一个是变量,结果就在堆中。变量拼接的原理是StringBuilder(第一个a==d)
  4. 如果拼接的结果调用intern()方法,根据该字符串是否在常量池中存在,分为:
  • 如果存在,则返回字符串在常量池中的地址(第二个a==d)
  • 如果字符串常量池中不存在该字符串,则在常量池中创建一份,并返回此对象的地址