1.字符串常量STring
特点:
1)类被final修饰,不能被继承
2)数据存储在一个final修饰的char类型的数组中
3)字符串常量池,可以理解为一个String的数据集,它是在堆内存中开辟的一块特殊内存
4)传递一个String常量给方法,原来的String常量不会被改变。
2.字符串变量 StringBuffer 和Stringbuilder都是字符串数据
1)修改String对象的值,内存地址会发生改变(相当于创建了一个新的STring对象,回收原来的String对象);
StringBuffer和Stringbuilder类的对象能被多次修改,且不产生新的对象,即内存地址不会被改变
2)StringBuffer和Stringbuilder默认容量长度是16
3) 如果在声明StringBuffer对象的同时,通过构造方法进行value[]初始化(即给变量赋值),则容量长度是 value[]的长度+16
4) 如果调用append()方法拼接字符串,字符串的长度超出容量长度,则对容量长度进行扩容,扩容大小为原长度<<1+2( 原长度左移一位+2)。扩容后仍小于字符串长度,则设置容量为字符串长度
5) StringBuilder线程不安全,执行速度快
6) StringBuffer线程安全
7)注意,String和StringBuffer都是通过字符数组实现的。
String的字符数组是final修饰的,而StringBuffer的字符数组没有final修饰。所以String的字符数组不能修改,StringBuffer的字符数组可以修改。而地址所指的内容可不可以修改,要看字符数组可不可以修改。所以String不能修改,StringBuffer可以修改。
String和StringBuffer都是final修饰的,这个final只是限制他们的引用地址不可修改。
final修饰字符数组,显示内容不可修改
final修饰对象,限制引用地址。不可修改
3.
1)基本数据类型存储在栈中
2)引用型指向对象,对象本身存储在堆中,对象实例存储在栈中
4.值传递与引用传递
1)基本数据类型遵循值传递(不变),将原来的值复制一份,传给方法
2)引用类型遵循引用传递(内存地址传递),将原来的引用(内存地址),复制一份,传给方法
public static void main(String[] args) {
int i= 12;
StringBuffer sf = new StringBuffer("abc");
String str = "123";
up(i,sf,str);
System.out.println(i);//12
System.out.println(sf);//abca
System.out.println(str);//123
}
private static void up(int a,StringBuffer b,String c) {
a = 20;
//修改StringBuffer变量,内存地址不变
b.append("a");
//传过来c的地址,修改字符串常量c,在另一个内存地址存储”1234“
//原内存地址的值没有被改变
c += "4";
}
5.相等性规则
1)==比较基本数据类型,比较的是值是否相等; = =引用类型,比较的是内存地址是否相等
2)Object类equals方法,比较的是内存地址是否相等
String类的equals方法,比较的是值是否相等
6 toString()方法是object类的公用方法,默认返回”类名+@hash值“。
如果object类使用,需要对toString()方法进行重写。
但是String类本身就对toString方法进行了重写
public static void main(String[] args) {
String a = "abc";//先去字符串常量池中检索,如果存在,则返回常量池中该值的引用
// String c = "abc";//a和c是一个地址
String b = new String("abc");
// String d = new String("abc");//a和c是两个不同的对象,内存不同
// 1.获取字符串长度
int len = a.length();
// 2.根据下表获取字符
char e = a.charAt(0);//e = a[0]
// 3.根据字符,获取该字符在字符串中出现的第一个位置的下标
int pos = a.indexOf('a');//pos=0
// 4.判断指定字符串是否被包含在变量中(判断字符串,不是字符‘’)
boolean tar = a.contains("ab");//true
boolean tar2 = a.contains("ac");//false
// 5.比较两个字符串的值是否相等
// 注意equals的原理
tar = a.equals(b);//true
a = null;
tar = a.equals("abc");//空指针异常
tar = "123".equals("a");//flase; 要把可能出现空指针异常的变量放在equals方法里面去
// 6.valueOf类型转换,将其他类型转换成String类型
int i = 12;
String.valueOf(i);
// 7.去除字符串两端的空格(中间的空格不能去除)
a = " 12 3 ";
a = a.trim();
System.out.println(a);
// 8.转大写,不改变原字符串,生成新的字符串
String str = "abc".toUpperCase();//ABC
// 9.转小写,不改变原字符串,生成新的字符串
str = "ABC".toLowerCase();
// 10.截取字符串subString(a,b),从下标a开始,到下标b结束,但不包括下标b
str = "0123".substring(0,2);//012
// 截取字符串,从指定下标开始,到字符串末尾结束
str = "0123".substring(2);//23
// 11.替换指定字符,返回一个新的字符串,不影响原来字符串
a = "abcdaaa";
str = a.replace('a', 'x');
// !!! 12.分割字符串,把字符串切割成String数组
a = "a,b,c,d,e";
String[] strr = a.split(",");
// 13.判断字符串是否为空
String c = "";//有c,但是c为空字符串
boolean bo = c.isEmpty();//bo为true
c = null;//没有c
bo = c.isEmpty();//空指针异常
// 13.String类的拼接concat,不改变原字符串,生成新的字符串
String str1 = new String("abc");
String str2 = str1.concat("xyz");
System.out.println(str1);//abc
System.out.println(str1);//abcxyz
// 14.StringBuffer的reservse,改变原字符串
StringBuffer str = new StringBuffer("abc");
str.reverse();
System.out.println(str);//cba
// 15.StringBuffer的append方法,改变原字符串
StringBuffer str = new StringBuffer("abc");
str.append("xyz");
System.out.println(str);//abcxyz
// 16.StringBuffer的capcity方法,返回字符串所在地址内存的容量,而不是字符串长度
StringBuffer sf = new StringBuffer();
int cap = sf.capacity();
// 几种不同类型对象的capcity
//1.通过构造函数定义容量长度
StringBuffer s1 = new StringBuffer(3);//初始化容量长度为3
System.out.println(s1.capacity());
//2.通过构造函数初始化对象,capcity等于对象length+16
StringBuffer s2 = new StringBuffer("good");
System.out.println(s2.capacity());//用构造函数初始化,容量是16+初始值的长度
//3.通过构造函数,默认capcity 16
StringBuffer s3 = new StringBuffer();
System.out.println(s3.capacity());//初始默认容量16
//4.使用append方法时,容量不足,扩容
StringBuffer s4 = new StringBuffer(3);
s4.append("你好呀小");//扩容,原容量3<<1+2 = 8
System.out.println(s4.capacity());
//5. 扩容后,容量仍不满足
StringBuffer s5 = new StringBuffer(3);
s5.append("你好呀小兰见到你很高兴");//扩容后仍s5.capcity()<s5.length,则把容量设置为length
System.out.println(s5.capacity());
}
7 String创建对象的两种方式:
String str1 = “aaa”;// ''aaa"是字面量,str1会创建在字符串常量池中
String str2 = new String(“aaa”);// 一共会创建两个字符串对象。一个在堆中,一个在常量池中(如果常量池中没有aaa)。
str1 == str2; // false,地址不同
8 字符串常量池的使用:
1)直接用双引号声明的String对象会存储在字符串常量池中
2)用String提供的intern()方法。intern方法:如果常量池中存在一个值为该String对象的字符串,则返回该字符串的引用。如果没有,在常量池中创建一个值为该String对象的字符串,并返回该字符串的引用。
例:
String s1 = new String("AAA");
String s2 = s1.intern();
String s3 = "AAA";
System.out.println(s2);//AAA
System.out.println(s1 == s2);//false。地址一个在堆中,一个在常量池中
System.out.println(s2 == s3);//true。s3创建在常量池中
9.字符串拼接:
String a = "a";
String b = "b";
String str1 = "a" + "b";//常量池中的对象
String str2 = a + b; //堆中的对象
String str3 = "ab"; //常量池中的对象
System.out.println(str1 == str2);//false
System.out.println(str1 == str3);//true
System.out.println(str2 == str3);//false
10.把String[] str的前ans个元素穿给String b[]—System.arraycopy(str, 0, b,0, ans);
String[] str = new String[4]; //这样一定义,str的长度就只能是4
int ans = 0;
String[] b = new String[ans];//字符串数组的长度是ans
System.arraycopy(str, 0, b,0, ans);//把str的前ans个元素传给b数组