String
- String类:代表字符串。java程序中字符串字面值(如 “abc”)都做为此类的实例实现。
- String是一个final类,代表不可变性。
- 字符串是常量,双引号引起来表示,他们的值创建之后不能改变。
- String的字符内容是存储在一个字符数组value[]中的。
/*
1.String实现了 Serializable接口 :表示支持序列化
Comparable 接口 : 表示String可以可以比较大小
2. String内部定义了 String final char value[] 用于存储字符串数据
3. 代表不可变性的字符序列。简称:不可变性。
体现:1.当字符串重新被赋值时,需要重新指定内存区域,,不能使用原有的value进行赋值
2.当对现有的字符串进行连接操作时,也是需要重新指定内存区域赋值,不能使用原有的value进行赋值
String s3 = "abc";
s3 += "def";
System.out.println(s3); // abcdef
System.out.println(s2); // abc
3. 用String方法的replace() 替换字符时,也是需要重新指定内存区域,原有的字符串不会发生改变
4.通过字面量赋值 区别于(new) 给一个字符串赋值,此时声明的字符串都在常量池中。
简单说就是 用= 弄出来的 字符串都在常量池中
5.常量池是不会存储相同的字符串的。
*/
@Test
public void test() {
String s1 = "abc"; //字面量的定义方式
String s2 = "abc";
//s1 = "hello";
System.out.println(s1); //hello
System.out.println(s2); //abc
System.out.println(s1 == s2); //比较s1 s2的地址值 true
System.out.println("****************");
String s3 = "abc";
s3 += "def";
System.out.println(s3); // abcdef
System.out.println(s2); // abc
System.out.println("***********");
String s4 = "abc";
String s5 =s4.replace('a','m');
System.out.println(s5); // mbc
System.out.println(s4); // abc
}
String的实例化方式
- String对象的创建
- String s= “abc”;
- String s1 = new String(); 本质上 this.value = new char[0];
- String s2= new String(“java”); this.value = original.value;
@Test
public void test1(){
/**
* String 的 实例化 方式
* 1. 通过字面量定义的方式
* 2. 通过new + 构造器的方式
*
* String s = new String("abc");方式创建对象,在内存中创建了几个对象?
* 两个:一个是在堆空间new 出来的 一个是对应在常量池当中
*/
// 通过字面量定义的方式
String s1 = "java";
String s2 = "java";
//通过new + 构造器的方式
String s3 = new String("java");
String s4 = new String("java");
System.out.println(s1==s2); //true
System.out.println(s3==s4); //false
System.out.println(s1==s3); //false
System.out.println(s2==s4);//false
}
String不同拼接的对比操作
@Test
public void test2() {
String s1 = "hello";
String s2 = "word";
String s3 = "hello" + "word";
String s4 = s1 + "word";
String s5 = s1 + s2;
String s6 = "helloword";
System.out.println(s3 == s6); //true
System.out.println(s3 == s4); //false
System.out.println(s3 == s5);//false
System.out.println(s5 == s6);//false
String s7 = s5.intern();
System.out.println(s6 == s7);//true
}
//结论:
1. 常量与常量之间的拼接结果都在常量池当中,且常量池当中不会存在相同的字符串
2. 只要有一个变量参与,结果会在堆当中,就相当于new了一个
3. 如果拼接有intern()方法,返回值会显示在常量池当中
练习 :下面输出结果是什么?
public static void main(String[] args) {
String str = new String("good");
char[] ch = {'t', 'e', 's', 't'};
StringTest1 ex = new StringTest1();
ex.change(str, ch);
System.out.println(str); //good
System.out.println(ch); //best
/*
1.这里把str传递给了下面的方法,因为String 是引用类型 所以是传递的是地址值,而又因为String特殊
是不可变的,所以输出的还是 good
2. char[] 数组是长度不可变,内容是可以变的
*/
}
public void change(String str, char[] ch) {
str = "test ok";
ch[0] = 'b';
}
String的常用方法
@Test
public void test() {
String s1 = "helloworld";
//int length():返回字符串的长度: return value.length
System.out.println(s1.length()); //10
//char charAt(int index): 返回某索引处的字符return value[index]
System.out.println(s1.charAt(0));//h
//boolean isEmpty():判断是否是空字符串:return value.length == 0
System.out.println(s1.isEmpty()); //false
//String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
System.out.println(s1.toLowerCase());//helloworld
// String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
System.out.println(s1.toUpperCase());//HELLOWORLD
String s2 = " yes ";
//String trim():返回字符串的副本,忽略前面空白和尾部空白, 中间空白保持不变
System.out.println(s2.trim().length()); //3
//boolean equals(Object obj):比较字符串的内容是否相同
System.out.println(s1.equals(s2)); //false
//boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
String s3 = "HELLOWORLD";
System.out.println(s3.equalsIgnoreCase(s1));//true
//int compareTo(String anotherString):比较两个字符串的大小
String s4 = "abc"; // 97 98 99 97 - 97 98 -98 99 -101 = -2
String s5 = "abe"; // 97 98 101
System.out.println(s4.compareTo(s5)); //涉及到字符串的排序 比如手机联系人的排序 这里前面的减去后面的是负数说明后面的大,
/*
beginIndex开始截取到最后的一个子字符串。String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字
符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
*/
String s6 = "我爱我的祖国";
System.out.println(s6.substring(2)); //我的祖国
System.out.println(s6.substring(1, 4)); //爱我的
}
@Test
public void test2() {
String s1 ="helloworld";
//boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
System.out.println(s1.endsWith("ld")); //true
//boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
System.out.println(s1.startsWith("HE")); //false
//boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始
System.out.println(s1.startsWith("he",0)); //true
//boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
System.out.println(s1.contains("world"));//true
//int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
System.out.println(s1.indexOf("l")); // 2
//int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
System.out.println(s1.indexOf("o", 3)); //4
//int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
System.out.println(s1.lastIndexOf("o")); //6
//int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
System.out.println(s1.lastIndexOf("w", 6)); //5
//注:indexOf和lastIndexOf方法如果未找到都是返回-1
//替换字符串方法
/*
1.String replace(char oldChar, char newChar):返回一个新的字符串,它是
通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
2.String replace(CharSequence target, CharSequence replacement):使
用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
3.String replaceAll(String regex, String replacement) : 使 用 给 定 的
replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
4.boolean matches(String regex):告知此字符串是否匹配给定的正则表达式
5.String[] split(String regex):根据给定正则表达式的匹配拆分此字符串
6. String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此
字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。
*/
}
String 与基本类型,包装类,char[],byte[]字节数组之间的转换
public void test4() {
/*
字符串 基本数据类型、包装类
Integer包装类的public static int parsexxxx(String s):可以将由“数字”字
符组成的字符串转换为整型。
类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应
的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
基本数据类型、包装类 字符串
调用String类的public String valueOf(int n)可将int型转换为字符串
相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double
d)、valueOf(boolean b)可由参数的相应类型到字符串的转换
*/
String s = "123";
System.out.println(Integer.parseInt(s));
System.out.println(Double.parseDouble(s));
System.out.println(s.valueOf(s));
}
public void test5() {
// String ----->char[]:调用 toCharArray()
String s = "hello";
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.println(chars[i]);
}
//char[] 转换 String 直接调用构造器
char[] arr = {'h', 'e', 'l', 'l', 'o'};
String s1 = new String(arr);
System.out.println(s1);
}
@Test
public void test6() throws UnsupportedEncodingException {
/*String 与 byte[]之间的转换
编码: String --->byte[] 调用String的 getBytes()
解码: byte[] ----String
编码: 把看得懂的变成 看不懂的
解码: 看得懂的 变成看不懂的
说明:解码时要求和编码时的要一样
*/
String str = "abc123中国";
byte[] bytes = str.getBytes(); //使用默认字符集进行转换
byte[] gbks = str.getBytes("gbk"); //使用gbk进行编码
System.out.println(Arrays.toString(bytes)); //[97, 98, 99, 49, 50, 51, -28, -72, -83, -27, -101, -67]
System.out.println(Arrays.toString(gbks)); //[97, 98, 99, 49, 50, 51, -42, -48, -71, -6]
System.out.println("*************");
String s = new String(bytes);ee
System.out.println(s);//abc123中国
System.out.println(new String(gbks));//abc123�й� 这里用的是gbk编码,而解码是utf-8所以乱码了
System.out.println(new String(gbks,"GBK")); //指定解码 字符集 abc123中国
}
StringBuffer
@Test
public void test(){
StringBuffer s1 = new StringBuffer("abc");
s1.append(1);
s1.append('1');
System.out.println(s1);
// s1.delete(2,4);
// s1.replace(2,4,"hello");
// s1.insert(2,false);
// s1.reverse();
String s2 = s1.substring(1, 3);
System.out.println(s1);
System.out.println(s1.length());
System.out.println(s2);
}
/*
String、StringBuffer、StringBuilder三者的异同?
String:不可变的字符序列;底层使用char[]存储
StringBuffer:可变的字符序列;线程安全的,效率低;底层使用char[]存储
StringBuilder:可变的字符序列;jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储
源码分析:
String str = new String();//char[] value = new char[0];
String str1 = new String("abc");//char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];底层创建了一个长度是16的数组。
System.out.println(sb1.length());//
sb1.append('a');//value[0] = 'a';
sb1.append('b');//value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc");//char[] value = new char["abc".length() + 16];
//问题1. System.out.println(sb2.length());//3
//问题2. 扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
默认情况下,扩容为原来容量的2倍 + 2,同时将原有数组中的元素复制到新的数组中。
指导意义:开发中建议大家使用:StringBuffer(int capacity) 或 StringBuilder(int capacity)
*/
String与StringBuffer的区别
- String的长度是不可变的,StringBuffer的长度是可变的。如果你对字符串中的内容经常进行操作,特别是内容要修改时,那么使用StringBuffer,如果最后需要String,那么使用StringBuffer的toString()方法
StringBuilder跟Buffer一样,buffer是线程安全的速度慢,builder不安全,速度快。