String类

理解String的不可变性

只要对String字符串进行了修改,都需要在字符串常量池中找到修改后对应的字符串,若没有则重新new一块地址给当前字符串变量,若有则将该字符串地址给到当前字符串变量。不能在原来的字符串地址上进行修改。
这里的s1,s2是变量而不是对象,对象是new来的。
比如String s=new String(“abc”);这里的“abc”就是对象

public class Demo {
    public static void main(String[] args) {
        /*
        String:字符串,声明为final,不可被继承
        1.实现了Serializable接口:表示字符串是支持序列化的
        2.实现了Comparable接口:表示String可以比较大小
        3.内部定义了final cahr[] value用于存储字符串数据
        4.代表不可变的字符序列。不可变性。
        5.String比较特别,明明是个类,却不用new,直接字面量定义,但它不是基本数据类型
         */
        String s1="abc";//字面量的定义方式,只有String这个类可以
        String s2="abc";
        System.out.println(s1==s2);//比较s1和s2的地址值;
    }
}

输出:true
通过字面量的定义方式给字符串赋值时
字符串“abc”将被存储到字符串常量池中,字符串常量池不会存储两个相同的字符串,所以s1中的“abc”与s2中的“abc”是同一个。
整体过程是:先给s1一个地址比如0x1212,s1=“abc”,则“abc”地址也为0x1212,s2出现时,先在字符串常量池中找有没有“abc”,有则将“abc”的地址给到s2,所以s1和s2的地址是相同的。
在这里插入图片描述
当改变字符串s1的值时:
当对字符串重新赋值时,需要重新指定一个内存区域赋值,不能使用原有的value进行赋值。
字符串常量池中新造一个“hello”,将新地址给到s1,所以s1与s2的地址不相同了。且s2的值不会随s1的改变而改变。

public class Demo {
    public static void main(String[] args) {
        String s1="abc";//字面量的定义方式
        String s2="abc";
        s1="hello";
        System.out.println(s1==s2);//比较s1和s2的地址值;
    }
}

在这里插入图片描述

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

public class Demo {
    public static void main(String[] args) {
        String s1="abc";//字面量的定义方式
        String s2="abc";
        s1+="def";
        System.out.println(s1==s2);//false
    }
}

当调用String的replace()方法修改字符串时,也必须重新指定内存区域赋值

public class Demo {
    public static void main(String[] args) {
        String s1="abc";//字面量的定义方式
        String s2=s1.replace('a','m');
        System.out.println(s1==s2);//false
    }
}

String对象的创建

在这里插入图片描述
String str1=“abc”;与String str2=new String (“abc”);的区别?
在这里插入图片描述
str1的地址是“abc”的,value是个引用类型,指向的是“abc”的地址值,value本身也有地址,str2的地址是value的地址。修改str2的值时并不会修改str1的值,因为字符串的不可变性。也就是说value会重新指向一个常量池中的新地址。

public class Demo {
    public static void main(String[] args) {
        /*
        String 实例化的方式:
        方式一:通过字面量定义的方式
        方式二:通过new+构造器的方式
         */
        //此时s1和s2的数据"javaEE"声明在方法区中的字符串常量池中。
        String s1="javaEE";
        String s2="javaEE";
        //通过new+构造器的方式
        //此时的s3和s4保存的地址值,是数据在堆空间开辟空间以后对应的地址
        String s3=new String("javaEE");
        String s4=new String("javaEE");
        System.out.println(s1==s2);//true
        System.out.println(s3==s4);//false
        System.out.println(s1==s3);//false
        System.out.println(s1==s4);//false
    }
}

相关解释说明
s1和s2因为字符串值相同,在字符串常量池中指向的是同一个字符串地址。
s3和s4虽然字符串相同,但在堆空间中new了两块地址value3和value4,value3和value4存储的都是字符串常量池中的同一个字符串地址“javaEE”,但value3和value4的地址不同,则s3和s4的地址也不同。
在这里插入图片描述
面试题:
String s=new String(“abc”);方式创建对象,在内存中创建了几个对象?
答:两个:一个是堆空间中new结构,另一个是char[ ]对应的常量池中的数据"abc";

String不同拼接操作的对比

public class Demo {
    public static void main(String[] args) {
        String s1="javaEE";
        String s2="hadhoop";
        String s3="javaEEhadhoop";
        String s4="javaEE"+"hadhoop";
        String s5=s1+"hadhoop";
        String s6="javaEE"+s2;
        String s7=s1+s2;

        System.out.println(s3 == s4);//true
        System.out.println(s3 == s5);//false
        System.out.println(s3 == s6);//false
        System.out.println(s3 == s7);//false
        System.out.println(s5 == s6);//false
        System.out.println(s5 == s7);//false
        System.out.println(s6 == s7);//false

        String s8=s5.intern();
        //返回值得到的s是使用的常量池中已经存在的"javaEEhadoop"
        System.out.println(s3 == s8);//true
        
        String s9=s7.intern();
        System.out.println(s9 == s3);//true
    }
}

只有s3和s4初始化时右边都是字符串常量,其在字符串常量池中完成字符串拼接。其余的s5,s6,s7具有变量参与,相当于在堆空间中new了一块新地址,所以都不相等。如果将右边的变量改为常量,则是在字符串常量池中操作。
例:

        String str1="java";
        String str2="EE";
        String str="javaEE";
        String str3=str1+"EE";
        System.out.println(str==str3);//false

        final String str4="java";
        String str5=str4+"EE";
        System.out.println(str==str5);//true

在这里插入图片描述
面试题

public class Demo {
    public static void main(String[] args) {
        String str=new String("good");
        char[] ch={'t','e','s','t'};
        change(str,ch);
        System.out.println(str);
        System.out.println(ch);

    }
    public static void change(String str,char ch[]){
        str="test ok";
        ch[0]='b';
    }
}

因为String的不可变性,所以change方法内的str只能重新在堆内存中重新new一块地址,而main方法中的str仍在原来的地址,所以值不改变。

String常用方法

String s1="helloworld";
        System.out.println(s1.length());//10
        System.out.println(s1.charAt(0));//h 获取第n个字符 字符串没有数组下标形式
        System.out.println(s1.isEmpty());//false
        s1="";
        System.out.println(s1.isEmpty());//true
public class Demo {
    public static void main(String[] args) {
        String s1="helloworld";
        //将字符串全部小写
        System.out.println(s1.toLowerCase());//helloworld
        //将字符串全部大写
        System.out.println(s1.toUpperCase());//HELLOWORLD
        System.out.println(s1);//helloworld s1的内容仍不变

        String s2="hello  world  ";
        //trim()去除字符串首尾空格,中间的不去除
        String s3=s2.trim();
        System.out.println(s2+"-----");//hello  world  -----
        System.out.println(s3+"-----");//hello  world-----

        String s4="hello";
        String s5="world";
        String s6=s4+s5;
        System.out.println(s1.equals(s6));//true 比较字符串内容是否相同

        String s7=s6.toUpperCase();//HELLOWORLD
        //忽略字符串的大小写比较内容是否相同
        System.out.println(s7.equalsIgnoreCase(s1));//true

        //拼接字符串 等价于用“+”
        String s8=s4.concat("abc");
        System.out.println(s8);//helloabc

        //compareTo()比较字符串大小:按顺序挨个比较
        //因为w-a=-22,所以输出-22
        System.out.println(s8.compareTo(s1));//-22

        s8="北京我爱你";
        System.out.println(s8.substring(2));//我爱你
        //注意第2个数是最后一个字符对应下标+1
        System.out.println(s8.substring(2, 5));//我爱你
    }
}
public class Demo1 {
    public static void main(String[] args) {
        String str1="helloworld";
        //检测是否以指定后缀结尾
        boolean b=str1.endsWith("rld");
        System.out.println(b);//true

        //检测是否以指定前缀开头
        System.out.println(str1.startsWith("He"));//false

        //检测是否从指定索引开始的子字符以指定内容开头
        System.out.println(str1.startsWith("ll",2));//true

        //判断字符串是否包含子字符串
        System.out.println(str1.contains("hell"));//true

        //返回指定子字符串在此字符串中第一次出现处的索引
        System.out.println(str1.indexOf("lo"));//3
        System.out.println(str1.indexOf("ww"));//没有则返回-1
        //从指定索引处开始找子串是否存在于字符串中
        System.out.println(str1.indexOf("lo",5));//-1

        String str2="hellorporpp";
        //从后面开始找子串,返回第一个出现的子串索引
        System.out.println(str2.lastIndexOf("or"));//7
        //从指定索引处开始往左找第一个匹配的子串
        System.out.println(str2.lastIndexOf("or",6));//4
    }
}

什么情况下str.lastIndexOf(“str1”);和str.IndexOf(“str1”);返回值相同?
情况一:字符串中只有一组与子串相匹配
情况二:一个都没有(返回-1)

public class Demo1 {
    public static void main(String[] args) {
        String str1="北京尚硅谷教育北京";
        String str2=str1.replace('北','东');
        System.out.println(str1);//北京尚硅谷教育北京
        System.out.println(str2);//东京尚硅谷教育东京
        String str3=str1.replace("北京","上海");
        System.out.println(str3);//上海尚硅谷教育上海

        String str4="464dsvf8svd646fbdfba4a6va";
        //d表示数字(正则表达式),+表示可能有多个数字
        //将字符串中的数组替换为指定字符串
        String str5=str4.replaceAll("\\d+",",");
        System.out.println(str4);//464dsvf8svd646fbdfba4a6va
        System.out.println(str5);//,dsvf,svd,fbdfba,a,va
        //若字符串开头(^)或结尾($)有","则用“”代替,也就是去除“,”
        String str6=str4.replaceAll("\\d+",",").replaceAll("^,|,$","");
        System.out.println(str6);//dsvf,svd,fbdfba,a,va

        String str7="12345";
        //判断str是否全部由数字组成
        boolean matches=str7.matches("\\d+");
        System.out.println(matches);//true
        //判断是否是一个杭州的固定电话
        String tel="0571-453428999";
        matches=tel.matches("0571-\\d{7,8}");//表示后面还有7~8位数字
        System.out.println(matches);//false 有9位数字

        //切片 用“|”将字符串切割开,并用字符串数组接收
        str7="hello|world|java";
        String[] strs=str7.split("\\|");
        for(int i=0;i<strs.length;i++){
            System.out.print(strs[i]+" ");//hello world java 
        }
    }
}

String与基本数据类型转换

在这里插入图片描述

public class Demo1 {
    public static void main(String[] args) {
        //String--->基本数据类型、包装类
        // 调用包装类的静态方法:parseXxx(str)
        String str="123";
        int num=Integer.parseInt(str);

        //基本数据类型、包装类--->String
        //调用String重载的valueOf(xxx)
        String s=String.valueOf(num);//"123"
        //或者直接连接“”
        String s1=num+"";//"123"
    }
}

String与char[ ]

        /*
        String 与char[]之间的转换
         */
        //String--->char[] 调用String的toCharArray
        String str="abc123";
        char[] chars=str.toCharArray();
        for(int i=0;i<chars.length;i++){
            System.out.print(chars[i]+" ");
        }
        System.out.println();

        //char[]--->String 调用String的构造器
        char[] arr=new char[]{'h','l','o'};
        String str1=new String(arr);
        System.out.println(str1);

String与byte[ ]
说明:解码是,要求解码使用的字符集必须与编码时使用的字符集一致,否则出现乱码。

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class Demo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        /*
        String 与byte[](字节数组)之间的转换
         */
        //编码:String--->byte[] 调用String的getBytes()
        String str1="abc123";
        byte[] bytes=str1.getBytes();//使用默认的字符集进行转换
        System.out.println(Arrays.toString(bytes));//[97, 98, 99, 49, 50, 51]

        String str2="你好中a";
        byte[] gbks=str2.getBytes("gbk");//使用gbk字符集进行编码
        System.out.println(Arrays.toString(gbks));//[-60, -29, -70, -61, -42, -48, 97]

        //解码:byte[]--->String 调用
        String str3=new String(bytes);//使用默认的字符集进行解码
        System.out.println(str3);//abc123

        //String str4=new String(gbks);乱码 原因:编码集和解码即不一致
        String str4=new String(gbks,"gbk");
        System.out.println(str4);//你好中a
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值