字符串String基础知识储备!

1. 创建字符串

1.1 常见的构造String的方法

方法一:

String str = "hello";

创建 str 这个引用,使之指向"hello"这个字符串常量的地址
方法二:

String str = new String("hello");

new String() 出一个新的对象,让"hello"这个字符串常量值赋进这个新对象,然后让 str 这个引用指向新对象
方法三:

char[] array = {a,b,c,d};
String str = new String(array);

Java中的字符串(String)和字符数组(char[ ])之间没有关联关系

1.2 其他构造String方法

官方文档Java Platform SE 8中还支持很多构造方法

1.3 了解String与栈、堆的关系

代码如下

String str1 = "Hello";
String str2 = str1;

内存布局如下

仅仅是两个引用指向了同一个对象
当修改代码为:

String str1 = "World";
String str2 = "Hello";

在这里插入图片描述
即修改了 str1 这个引用指向的地址为 0x200 ,不指向"Hello",而指向"World",并不是修改了之前的字符串

2. 字符串比较相等

2.1 “==” 比较

String 通过“ == ”来比较的只是两个引用是否指向同一个对象,即地址是否相同

  //局部变量---栈上
  String a = "hello";
  String b = "hello";
  //此时的比较是直接比较a和b引用里面存的地址是否相等
  System.out.println(a == b);
  输出:true
   //成员变量---堆上
   String c = new String("hello");
   String d = new String("hello");
   //手动创建出来的两个不同的对象,地址不同,所存内容相同
   //故通过“==”来比较是不相等的
   System.out.println( c == d);
   输出:false

局部变量在栈上,成员变量在堆上

2.2 .equals 比较

String 通过 a.equals(b) 来比较 a,b 内容是否相同

  String a = "hello";
  //方法一
  System.out.println(a.equals("hello"));
  //方法二
  System.out.println("hello".equals(a));

推荐使用方法二,因为方法一当 a 为 null 时(即为空引用)会抛出异常,而方法二不会

3. 字符串常量池

3.1 常量池

当我们需要大量使用相同的常量时,就只需要将其一次放入常量池中,以后每次使用就在其中调用即可,不必每次使用都去创建新的对象,常量池中的内容主要来自编译器的自动识别和intern方法的手动加入。
池的目的就是为了降低开销,提高效率,本质是把频繁使用的东西提前保存好,以备用到的时候可以随时使用

3.2 String 的两种实例化操作

3.2.1 直接赋值
  String str1 = "hello";
  String str2 = "hello";
  String str3 = "hello";
  System.out.println( str1 == str2 );//true
  System.out.println( str2 == str3 );//true

采用直接赋值来进行String类的对象实例化操作,该对象将直接保存在对象池中,如果下次再用直接赋值的方式声明String类对象,对象池中存在则直接引用,不存在则这次存入,下次直接引用,通过“==”比较的是两对象的地址是否相同

3.2.2 采用构造方法
  String str = new String("hello");

采用 String 的构造方法会开辟出两块内存,原先的"hello"已有内存,当 new String 出来新的对象,存入"hello"而原先的"hello"内存会被JVM垃圾回收器自动回收,所以这样的构造方法较浪费空间,解决方法如下:
用 String 的 intern 方法手动将 String 对象加入到字符串常量池中 :

   String a = new String("hello");
   System.out.println(a == "hello");//false

a 中存的是 new String() 出来的对象的地址

   String a = new String("hello").intern();
   System.out.println(a == "hello");//true

new String 出一个新的对象,根据这个对象的内容调用 intern()方法在常量池中找出该内容的地址再返回给 a,语句执行完毕后,并没有引用指向new出的新对象,其将会被JVM垃圾回收机制回收。
*intern方法
会拿着new String() 出的这个字符串在字符串常量池中去查找,看是否存在,若存在,则直接返回其地址,若不存在,则将该字符串存入常量池中并返回该地址
*注意事项
String 类中两种对象实例化的区别?
直接赋值:只会开辟一块空间,将该字符串对象自动保存在字符串常量池中,以供后续使用。
构造方法:会开辟出两块空间,造成空间浪费,并且不会自动保存字符串常量,可以使用intern()这个方法来将对象手动加入到字符串常量池中。

4. 理解字符串不可变

4.1 区别常量(final修饰)和不可变对象

final 修饰的是常量
若 final 修饰的是一个引用类型,则表示的是该引用的指向(引用中存的地址)不可变
若 final 修饰的是一个类,则表示该类不能被其他类继承

	//final修饰的是一个常量
	final A a = new A();
	//a 是一个常量,其引用指向无法改变
	//此操作是不合法的
	a = new A();
	//此时的 a 是一个"可变对象"
	a.num = 10;

不可变对象对象本身的内容不能改变
特点:

  1. 无法在类的外部访问
  2. 没有 public 的方法可以修改内容

4.2 Java为什么要把 String 设计成不可变对象

  1. 方便放到池中,如果是可变的对象,当池中内容改变,就会影响到所有引用这个池的对象的结果
  2. 对象内容不可变,则对象的hashCode也不可变,方便和hash表这样的结构配合使用
  3. 对象不可变,线程安全更有保障(String s =“hello”=>“hella”,在java中只能通过构造一个新的对象来完成)

4.3 特殊方法修改字符串内容

“反射”/自省的方法 :

    //通过非常规的手法来修改String里面的内容(反射)
	String str = "hello";
    // 1.获取String 的类对象
    // 2.根据"value"这个字段名字,在类对象中拿到对应的字段(仍然是一个图纸的一部分)
    Field valueField = String.class.getDeclaredField("value");//须处理抛出异常
    //让value 这个 private 的成员也能被访问到
    valueField.setAccessible(true);
    // 3.根据图纸,把 str 这个对象给拆开,取出里面的零件
    char[] value = (char[])valueField.get(str);
    // 4.修改零件的内容
    value[4] = 'a';
    System.out.println(str);
    输出:hella

反射和封装是背道而驰的

  • 使用反射往往可能打破封装
  • 反射的代码比较复杂,容易出错
  • 反射牺牲了编译器自身的一些检查校验机制,更需要程序员人工保证代码的正确性

5. 字符、字节、与字符串

5.1 字符与字符串

5.1.1字符数组转字符串
	char[] value= {'a','b','c','d'};
	String str = new String("value");
5.1.2 字符串转字符数组

运用charAt()方法输出字符串内容

	String s = "abcd";
	System.out.println(s.charAt(0));//a
	System.out.println(s.charAt(1));//b
    System.out.println(s.charAt(2));//c
    System.out.println(s.charAt(3));//d
    //输出字符串长度,用.length()这个方法
    //获取字符数组长度,用.length 这个属性
    System.out.println(s.length());//4

运用toCharArray()方法得到新的字符数组
toCharArray 方法相当于在内部创建了一个新的字符数组并返回

	//修改这个返回值不会影响到 s 本身的内容
    char[] value = s.toCharArray();
    for(char v : value){
        System.out.println(v);
      }//输出a b c d
    value[0] = 'x';
    System.out.println(value);//xbcd 修改的是新字符数组
    System.out.println(s);//abcd 不修改 s 本身

5.2 字节与字符串

运用getBytes()方法

	String str = "HelloWorld";
    //String 转 byte[]
    byte[] data = str.getBytes();
    for(int i = 0; i < data.length;i++){
         System.out.println(data[i]+" ");
     }
    //byte[] 转 String
    System.out.println(new String(data));

5.3 区别字节、字符

字节=>8 bit位
字符=>2 字节

6. 字符串常见操作

6.1 字符串比较

使用compareTo()方法比较两字符串大小

	String a = "hello";
    String b = "Hello";
    //1. compareTo()会返回一个整数
    //2. a 比 b 小,返回 <0 的值
    //3. a 比 b 大,返回 >0 的值
    //4. a 与 b 相等,返回 0
    int result = a.compareTo(b);
    System.out.println(result);//32
    //忽略大小写比较
    int result1 = a.compareToIgnoreCase(b);
    System.out.println(result1);//0

比较规则:根据unicode的值来比较大小,若第一个字符区分不开再向后挪一位比较,以此类推,即可比较出大小。

6.2字符串查找

查找对应的字符串下标起始位置

	//查找字符串
	String a = "hello world world";
    String b = "world";
    //从左至右第一次出现的下标
    int result = a.indexOf(b);
    System.out.println(result);//6
    //指定下标开始向后查找
    result = a.indexOf( b , result + 1);
    //result+1是从第一个world的下个位置开始,以便查找第二个world
    System.out.println(result);//12
    //从右向前向后查找
    System.out.println(a.lastIndexOf(b));//12

查找开头/结尾字符串

	String str = "@@**hello world^^";
    //判断开头字符
    System.out.println(str.startsWith("@@"));//true
    //判断第 2 个下标的字符是否与要求相同
    System.out.println(str.startsWith("*",2));//true
    System.out.println(str.startsWith("h",2));//false
    //判断结尾字符
    System.out.println(str.endsWith("^^"));//true

方法 startsWith()、endsWith() 的返回值是布尔类型,只有( true / false )

6.3 字符串替换

 	//字符串替换
	String a = "hello world world";
    String b = "world";
    //替换所有
    System.out.println(a.replaceAll( b , "java"));//hello java java
    //替换第一次出现的内容
    System.out.println(a.replaceFirst( b ,"java"));//hello java world

6.4 字符串拆分

普通拆分

	String str = "hello java java ";
	//将字符串以" "为分隔符划分开来
    String[] result = str.split(" ");
    System.out.println(Arrays.toString(result));//[hello, java, java]
    //将字符串以" "为分隔符,划分成2部分
    //limit是从头开始每一段划分一块,后面为一大部分
    //limit = 2   [hello, java java ]
    //limit = 3   [hello, java, java ]
    String[] result1 = str.split(" ",2);
    System.out.println(Arrays.toString(result1));

特殊拆分

	//正则表达式里的特殊字符无法直接使用来拆分,需要转义
    String str = "192.168.1.1";
    String[] result = str.split(".");
    System.out.println(Arrays.toString(result));//[]
    //正则表达式中将 . 当做特殊字符来看待,将 \. 才能当做 . 来对待
    //java又将 \ 当做转义字符,故为了表达原始的 \ 需再次转义
    String[] result1 = str.split("\\.") ;
    System.out.println(Arrays.toString(result1));//[192, 168, 1, 1]

6.5 字符串截取

	//字符串的截取
    String str = "hello beautiful world";
    //[begin,end)
    System.out.println(str.substring(6,15));//beautiful
    //从6开始一直输出到结束
    System.out.println(str.substring(6));//beautiful world

6.6其他操作方法

6.6.1 去掉字符串左右空白符,不去中间的
	String str = "   hello world   ";
	System.out.println(str);//   hello world   
	System.out.println(str.trim());//hello world

空白符:空格、换行、回车、制表符、翻页符、垂直制表符…

6.1.2 转换大小写
	String str = "HeLLo";
    //全部转换为大写
    System.out.println(str.toUpperCase());
    //全部转换为小写
    System.out.println(str.toLowerCase());
6.1.3 判断字符串是否为空字符串
	String str = "";
	//返回 boolean 类型
    System.out.println(str.isEmpty());//true

*区别空字符串和空引用

	//把字符串想象成是一个装字符的盒子
    //空字符串就是空盒子
    //空引用连空盒子都没有
    String a = "";//空字符串
    String b = null;//空引用

以上方法中能改变字符串内容的都是创建了一个新的字符串,改变的是新字符串的内容,原字符串没有改变

7. StringBuilder和StringBuffer

  • String 的常量一旦声明就无法更改,如果需要更改对象内容,改变的的只是其引用的指向而已,并未改变原字符串内容
  • 若需要改变字符串内容,则借用StringBuilder和StringBuffer类可方便字符串的修改
  • StringBuilder和StringBuffer类主要区别:
    StringBulider 线程不安全
    StringBuffer 线程安全

7.1 StringBuilder使用范例

7.1.1 append对字符串进行追加
	StringBuilder str = new StringBuilder("hello");
	for (int i = 0; i < 10; i++) {
       str.append(i);
        }
	System.out.println(str);//hello0123456789

区别:

  1. 使用 append 能够把字符串进行追加,相当于 String 里面的 +=
  2. String 的 += 会产生新的 String 对象,如果在循环中使用,是比较低效的
7.1.2 逆置
	StringBuilder str = new StringBuilder("hello");
    str.reverse();//修改字符串本身
    System.out.println(str.toString());//olleh
7.1.3 删除
	StringBuilder str = new StringBuilder("hello");
    //[begin,end)
    System.out.println(str.delete( 2 , 4 ));//heo
7.1.4 增加
str.insert(int offset,各种数据类型)
	StringBuilder str = new StringBuilder("hello");
	System.out.println(str.insert(5," world"));//hello world
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值