字 符 串

String类的特点

  • String 类代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。解释:凡是在代码中出现"",不管""中有没有字符,它都是String的对象。
  • 字符串是常量。字符串对象不可变。
  • 因为字符串对象不可变。所以字符串对象可以共享。只要是字符串常量对象就可以共享。这些共享(就是指使用同一个对象)的字符串存储在字符串常量池中。
  • 字符串常量池在哪呢?笼统的说在方法区

细说: JDK1.6以及之前:方法区 JDK1.7:挪到了堆中,即在堆中单开一块空间存储字符串常量,和其他的对象分开的
JDK1.8之后:元空间(类似于方法区的一个逻辑分区)

  • java.lang.String类本身是final修饰,不能被继承。String类没有子类,父类是Object。
  • String类的对象是如何设计为不可变的呢?

(1)首先,String中用一个private final char[] value,来存储字符串内容。
         因为这里value数组使用了final,所以value数组不能扩容,即value不能指向新数组了。
         因为这里value数组使用了private,所以外面不能直接操作String对象的value的
(2)其次,String类中提供了一些操作字符串对象的方法,但是只要涉及到修改字符串内容,都会返回新对象

  • JDK1.9之前,String内部时char[],JDK1.9之后把char[]数组换成了byte[]数组。
    为什么呢?

因为一个char字符,在JVM内存中使用Unicode编码值表示,需要栈2个字节。
无论什么范围的编码值,JVM都给你分配2个字节。

但是我们程序中大量使用ASCII表范围内的字符。这些字符的Unicode编码值是在[0,127]范围,按理说1个字节够了,所以会有点浪费。
JDK1.9就用byte[]数组,如果一个字节能搞定的,用1个字节,不能的,再用2个字节。

字符串举例

	@Test
    public void test(){
        //凡是在代码中出现"",不管""中有没有字符,它都是String的对象。
        String str1= "";//str1是一个空字符串
        String str2= "hello";//str2是hello字符串
        System.out.println("hello");//打印一个hello字符串
        System.out.println("");//打印一个空字符串

    }
	@Test
    public void test(){
        //字符串对象不可变。
        String s = "hello";
        change(s);
        System.out.println("s = " + s);//hello  但是s仍然执行hello字符串
    }

    public void change(String str){ //形参是String类型
        str += "atguigu";
        //对象形参做了修改,但是因为String类型的对象是不可变对象,只要修改,str就会指向新的新的字符串对象,就和原来实参对象无关了。
       //此时str指向了 helloatguigu字符串,不再指向hello字符串了
    }
	@Test
    public void test(){
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1 == s2);//地址相同,因为它们指向同一个字符串常量对象

        String s3 = new String("hello");
        String s4 = new String("hello");
        System.out.println(s3 == s4);//false  内存地址不一样,因为s3是新new的
        System.out.println(s3 == s1);//false
        /*
        虽然字符串常量对象是共享的,使用==比较也会返回true,
        但是实际开发中,无论字符串是否是常量对象,只要涉及到比较字符串内容是否相同,都用equals方法,不要用==
         */
    }

字符串不能修改

    @Test
    public void test(){
        String str = "hello";
//        str.value[0] = 'H';//无法操作,value是private的
        System.out.println(str);
    }
    @Test
    public void test(){
        String str = "hello";
        str.replace('h','H');//把h字符替换为H
        System.out.println(str);//hello
        //因为replace方法,如果修改了字符串的内容,就会返回一个新的字符串对象,不是在原来hello字符串基础上直接修改的
        //如果没有接收新字符串对象,那么str是不变的
    }

字符串修改后必须返回新对象

   @Test
    public void test6(){
        String str = "hello";
        str = str.replace('h','H');//把h字符替换为H
        System.out.println(str);//Hello
        //str变量重新指向新的字符串对象
    }

创建字符串对象

在Java程序中,如何得到一个字符串对象?
1、直接""把字符串内容引起来,就是一个字符串对象
2、任意对象调用toString都可以得到一个字符串对象
3、任意类型的数据 和 字符串拼接结果都是字符串
4、String类有静态方法valueOf可以把多种数据类型转换为字符串
5、String类有很多构造器

@Test
    public void test5(){
        String s1 = new String();
        String s2 = new String("hello");
        char[] arr = {'a','b','c'};
        String s3 = new String(arr);
        byte[] bytes = {97,98,99,100};
        String s4 = new String(bytes);

        System.out.println("s1 = " + s1);
        System.out.println("s2 = " + s2);
        System.out.println("s3 = " + s3);
        System.out.println("s4 = " + s4);
    }

    @Test
    public void test4(){
        String s1 = String.valueOf(12);
        System.out.println("s1 = " + s1);
        
        String s2 = String.valueOf(13);
        System.out.println("s2 = " + s2);

        System.out.println(s1 + s2);//1213
    }
    @Test
    public void test3(){
        System.out.println('a' + "," + 'b');//a,b
    }

    @Test
    public void test2(){
        Date d = new Date();
        String s = d.toString();
        System.out.println("s = " + s);
    }
    
    @Test
    public void test1(){
        String s = "hello";
        System.out.println(s.length());//求s字符串对象的长度
        System.out.println("Aa".length());//"Aa"一个字符串对象,length()求字符串对象的长度
        System.out.println("Aa".equals(s));//表示判断"Aa"字符串和s字符串对象是否相等
        System.out.println("".equals(s));//判断s字符串对象和空字符串对象是否相等
    }

字符串对象的个数

	@Test
    public void test3(){
        String s1 = "hello";
        String s = new String("hello");

        //上面的代码,也是2个字符对象
        //其中"hello"是共享同一个
    }

    @Test
    public void test2(){
        String s1 = "hello";
        String s2 = "hello";
        //上面的代码,有几个字符串对象呢?1个
        //这里虽然声明了2个字符串类型的变量
        //但是字符串对象只有一个,它们共享同一个字符对象
    }

    @Test
    public void test1(){
        String s = new String("hello");
        //上面这句代码有几个字符串对象?
        //2个
        //一个是字符串常量对象"hello",一个是新new的字符串对象
        //两个字符串对象的关系是  s对象的value数组,和"hello"对象的value是共享。
    }

字符串对象的内存分析

    public static void main(String[] args) {
//        String s; //在堆内存,或字符串常量值都没有对应的字符串对象,因为s未初始化,相当于只有一个局部变量s,它在栈中

//        String s = null;//在堆内存,或字符串常量值也都没有对应的字符串对象,但是和上面的区别时已经初始化了

//        String s = ""; //有一个字符串对象,只不过是空字符串对象,字符串对象没有内容,即内部的value数组的长度为0

 //       String s = new String();//有一个字符串对象,只不过是空字符串对象,字符串对象没有内容,即内部的value数组的长度为0
 //       String s = new String("");//有一个字符串对象,只不过是空字符串对象,字符串对象没有内容,即内部的value数组的长度为0

//        String s = "abc";//直接指向常量池中字符串对象
//        String s = new String("abc");//有2个对象,一个是堆中的实例,一个是常量池中的实例

        char[] arr = {'a','b'};
        String s = new String(arr); //思考:String类中的value数组和arr数组什么关系?
                                    //String类中value数组是基于arr数组又复制了一个新数组。
                                    //否则修改了arr,会导致s对象内容变了。

//        char[] arr = {'a','b','c','d','e'};
//        String s = new String(arr,0,3);
    }

字符串拼接问题

1、字符串拼接有几种方式?
(1) +
         只要+左右两边有String类型,那么就是字符串拼接,结果都是字符串。
(2)调用String类的concat方法
         public String concat(String str):必须有字符串对象调用,传入的参数也必须是字符串对象,结果也是字符串对象。当+两边都是 字符串常量池中的字符串(或者说是字面量字符串,即直接""引起来的字符串),结果一定在字符串常量池, 而且编译器会优化处理,相当于直接是拼接后的结果字符串。 即 “hello” + “world” 等价于 "helloworld"但是concat不会优化。concat拼接完的结果,一定是在堆中的新字符串对象。

2、+操作 哪些字符串的拼接结果在字符串常量池呢? 当+两边都是
字符串常量池中的字符串(或者说是字面量字符串,即直接""引起来的字符串),结果一定在字符串常量池 当+两边都是
指向字符串常量池中的字符串的final声明的变量,结果一定在字符串常量池 当+两边都是
指向字符串常量池中的字符串的final声明的变量,或字符串常量池中的字符串 结果一定在字符串常量池
结果如果在字符串常量池的话,只要内容相同,就是同一个对象,因为字符串常量对象共享。

当+两边有一边是 变量(而且这个变量不是指向字符串常量池中的字符串的final声明的变量),那么结果都是在堆, 当+两边有一边是 new
String对象,那么结果都是在堆, 结果如果在堆中的话,每一个结果都是独立的字符串对象。

只要是xx.intern(),得到的字符串结果一定是在字符串常量池。

结论:
(1)"?" + “?” 结果一定在字符串常量池
(2)xx.intern() 结果一定在字符串常量池 xx是一个拼接操作
(3) final String s1 = “?”;
final String s2 = “?”;
s1 + s2 结果一定在字符串常量池
只有以上三种拼接结果才会在字符串常量池,在字符串常量池的话,只要内容相同,就是同一个对象,因为字符串常量对象共享,==比较返回true。

其他的字符串拼接结果比较用==,都是false。

    @Test
    public void test6(){
        String s1 = new String("hello");
        String s2 = new String("world");
        String s3 = "hello" + "world";
        String s4 = "helloworld";
        String s5 = (s1 + s2).intern();
        String s6 = (s1 + "world").intern();
        String s7 = (s1.concat(s2)).intern();

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

    }

    @Test
    public void test5(){
        final String s1 = new String("hello");
        final String s2 = new String("world");
        String s3 = "hello" + "world";
        String s4 = "helloworld";
        String s5 = s1 + s2;
        String s6 = s1 + "world";

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

    @Test
    public void test4(){
        String s1 = new String("hello");
        String s2 = new String("world");
        String s3 = "hello" + "world";
        String s4 = "helloworld";
        String s5 = s1 + s2;
        String s6 = s1 + "world";

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

    }

    @Test
    public void test3(){
       final String s1 = "hello";
       final String s2 = "world";
        String s3 = "hello" + "world";
        String s4 = "helloworld";
        String s5 = s1 + s2;
        String s6 = s1 + "world";

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

    }
    @Test
    public void test2(){
        String s1 = "hello";
        String s2 = "world";
        String s3 = "hello" + "world";
        String s4 = "helloworld";
        String s5 = s1 + s2;
        String s6 = s1 + "world";

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

    }

    @Test
    public void test(){

        String s3 = "hello" + "world";
        String s4 = "helloworld";
        String s5 = "hello".concat("world");

        System.out.println(s3 == s4);//比较地址   true
        System.out.println(s4 == s5);//比较地址   false

    }

字符串的比较操作

1、字符串的比较操作有哪几种?
(1)==:比较两个字符串的地址,只有两个字符串常量池中的字符串比较结果才会为true,否则都是false
(2)equals:比较两个字符串的内容,只要字符串内容相同,都是true,但是严格大小写
(3)compareTo:比较两个字符串的大小,默认按照字符串中每一个字符的Unicode编码值比较大小,大小写字母的编码值是不同的
(4)equalsIgnoreCase:比较两个字符串的内容,只要字符串内容相同,都是true,不区分大小写,认为’a’和’A’内容相同
(5)compareToIgnoreCase:比较两个字符串的大小,认为大写字母和小写字母一样大
(6) 字符串对象的比较器.compare(字符串1, 字符串2)
字符串对象的比较器必须是java.util.Comparator接口
(7)java.text.Collator:Collator 类执行区分语言环境的 String 比较。
调用它的静态的getInstance()方法的得到一个对象,然后调用compare方法比较两个字符串大小,
因为Collator实现了java.util.Comparator接口,重写了compare方法,重写时,是按照具体的语言环境的自然语言顺序排列的

思考:
比较用户名和密码输入是否正确? equals
比较验证码输入是否正确? equalsIgnoreCase
对用户信息按照姓名排序显示结果? 字符串对象的比较器.compare(字符串1, 字符串2)

 	@Test
    public void test6(){
        String[] arr = {"张三","李四","王五","柴林燕"};
        Arrays.sort(arr, Collator.getInstance(Locale.CHINA));
        System.out.println(Arrays.toString(arr));
        /*
        [柴林燕, 李四, 王五, 张三]  按照汉语的自然语言顺序,拼音的顺序比较大小
         */
    }

    @Test
    public void test5(){
        String[] arr = {"张三","李四","王五","柴林燕"};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
        /*
        [张三, 李四, 柴林燕, 王五]  按照每一个汉字的Unicode编码值比较大小
        对于普通用户来说,不懂什么编码值
         */
    }

    @Test
    public void test4(){
        String[] arr = {"hello","java","world","chai","Bob","atguigu"};
        //字符串排序
        Arrays.sort(arr, new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {
                String s1 = (String) o1;
                String s2 = (String) o2;
                return s1.compareToIgnoreCase(s2);
            }
        });
        System.out.println(Arrays.toString(arr));
        //[atguigu, Bob, chai, hello, java, world]
        /*
        Arrays.sort(arr, Comparator接口的实现类对象)随着这里是匿名内部类的对象,也是实现了Comparator接口的。
        指定了字符串元素比较时,忽略大小写。
         */

    }

    @Test
    public void test3(){
        String[] arr = {"hello","java","world","chai","Bob","atguigu"};
        //字符串排序
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
        //[Bob, atguigu, chai, hello, java, world]
        /*
        Arrays.sort方法,比较两个元素的大小时,是用元素对象的compareTo方法比较大小的,即要求元素实现java.lang.Comparable接口。
        String类实现java.lang.Comparable接口,重写了compareTo方法,重写的是依据字符串的每一个字符的Unicode编码值比较大小的。

        Bob的B 比 atguigu的a要小,排在前面
         */
    }

    @Test
    public void test2(){
        String s1 = "hello";
        String s2 = "hello";
        String s3 = "Hello";
        String s4 = new String("hello");
        /*
        String类型实现了java.lang.Comparable接口,所以有compareTo方法
         */
        System.out.println(s1.compareTo(s2));//0
        System.out.println(s1.compareTo(s3));//32 正整数  表示s1 > s3  确实s1中h比s3中的H大
        System.out.println(s1.compareTo(s4));//0

        System.out.println(s1.compareToIgnoreCase(s2));//0
        System.out.println(s1.compareToIgnoreCase(s3));//0
        System.out.println(s1.compareToIgnoreCase(s4));//0

    }

    @Test
    public void test01(){
        String s1 = "hello";
        String s2 = "hello";
        String s3 = "Hello";
        String s4 = new String("hello");

        System.out.println(s1 == s2);//true
        System.out.println(s1 == s3);//false 大小写不一样
        System.out.println(s1 == s4);//false 一个在字符串常量池,一个在堆中

        System.out.println(s1.equals(s2));//true
        System.out.println(s1.equals(s3));//false  大小写不一样
        System.out.println(s1.equals(s4));//true   大小写内容一样

        System.out.println(s1.equalsIgnoreCase(s2));//true
        System.out.println(s1.equalsIgnoreCase(s3));//true  不区分大小写
        System.out.println(s1.equalsIgnoreCase(s4));//true  不区分大小写
    }

空字符的比较

1、什么是空字符串?
语法层面的空字符串是指字符串对象的内容为空,字符串的长度为0。

2、如何判断某个字符串变量是否是空字符串?
当我们通过某个方法,或者计算得到一个字符串结果,如何判断它是否是空字符串

3、逻辑意义上的空字符串?
" "里面除了的空格等空白字符串(空格,\t等)没有其他实质性的文本,也可以归到空字符串

@Test
    public void test4(){
        String str = "    ";
        System.out.println("".equals(str));//false
        System.out.println("".equals(str.trim()));//true
    }

    @Test
    public void test3(){
        String str = getString();
        /*
        在这里如何判断str是否是一个空字符串
         */
        if(str != null && str.length()==0){
            System.out.println("str是空字符串");
        }else{
            System.out.println("str是非空字符串");
        }

        if(str != null && str.isEmpty()){
            System.out.println("str是空字符串");
        }else{
            System.out.println("str是非空字符串");
        }

        if(str != null && str.equals("")){
            System.out.println("str是空字符串");
        }else{
            System.out.println("str是非空字符串");
        }

        if("".equals(str)){//开发中推荐这种写法
            System.out.println("str是空字符串");
        }else{
            System.out.println("str是非空字符串");
        }
    }

    public String getString(){
        String str = null;
        //...省略了计算
        return str;
    }

    @Test
    public void test2(){
        String s1 = "";
        String s2 = new String("");
        String s3 = new String();
        char[] arr = new char[0];
        String s4 = new String(arr);

        System.out.println(s1 != null && s1.length()==0);//true
        System.out.println(s2 != null && s2.length()==0);//true
        System.out.println(s3 != null && s3.length()==0);//true
        System.out.println(s4 != null && s4.length()==0);//true
    }

    @Test
    public void test1(){
        //这些都不是空字符串
        String s1 ;         //未初始化     没有字符串对象
        String s2 = null;   //初始化为null 没有字符串对象
        String s3 = "  ";   //有字符串对象,长度不是0,里面有空格


//        System.out.println(s1 != null && s1.length()==0);//编译报错,s1没有初始化
//        System.out.println(s2 != null & s2.length()==0);//编译不报错,但是运行报错NullPointerException  &不发生短路,左边不成立,右边继续
        System.out.println(s3 != null && s3.length()==0);//编译不报错,运行结果是false
    }

字符串的常用方法

(1)boolean isEmpty():字符串是否为空

(2)int length():返回字符串的长度

(3)String concat(xx):拼接,等价于+

(4)boolean equals(Object obj):比较字符串是否相等,区分大小写

(5)boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写

(6)int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小

(7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写

(8)String toLowerCase():将字符串中大写字母转为小写

(9)String toUpperCase():将字符串中小写字母转为大写

(10)String trim():去掉字符串前后空白符

(11)public String intern():结果在常量池中共享

常用方法

    @Test
    public void test2(){
        String str = "    hello   world    ";
        System.out.println("[" + str + "]");//[    hello   world    ]
        str = str.trim();
        System.out.println("[" + str + "]");//[hello   world]
    }

    @Test
    public void test1(){
        String str = "heLLOWorld";
        System.out.println(str.toLowerCase());//helloworld  直接输出新字符串对象

        str.toLowerCase();//没有接收变化后的新字符串对象
        System.out.println(str);//heLLOWorld  打印的是原来的字符串对象

        str = str.toLowerCase();
        System.out.println(str);//helloworld str指向了新的字符串对象
    }

查找

boolean contains(xx):是否包含xx

int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1

int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1

@Test
    public void test(){
        String str = "xxx是一家靠谱的培训机构,xxx可以说是IT培训的小清华,JavaEE是xxx的当家学科,xxx的大数据培训是行业独角兽。xxx的前端和运维专业一样独领风骚。";
        //判断str中是否包含 尚硅谷
        System.out.println(str.contains("xxx"));//true
        //尚硅谷在str中的下标
        System.out.println(str.indexOf("xxx"));//0

        System.out.println(str.lastIndexOf("xxx"));//62
    }

字符串截取

String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。

String substring(int beginIndex, int endIndex):返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。

 @Test
    public void test2(){
        String fileName = "atguigu/java/HelloWorld.java";
        //截取出文件名

        //先找到最后一个/的下标,以及最后一个.的位置
        int diagonalIndex = fileName.lastIndexOf("/");
        int dotIndex = fileName.lastIndexOf(".");
        //从最后一个.截取到字符串最后
        String name = fileName.substring(diagonalIndex+1, dotIndex);
        System.out.println("name = " + name);
    }

    @Test
    public void test(){
        String fileName = "java/HelloWorld.java";
        //截取出文件的后缀名
        
        //先找到最后一个.的下标
        int index = fileName.lastIndexOf(".");
        //从最后一个.截取到字符串最后
        String ext = fileName.substring(index);
        System.out.println("ext = " + ext);
    }

和字符相关

char charAt(index):返回[index]位置的字符

char[] toCharArray(): 将此字符串转换为一个新的字符数组返回

String(char[] value):返回指定数组中表示该字符序列的 String。

String(char[] value, int offset, int count):返回指定数组中表示该字符序列的 String。

static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String

static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String

static String valueOf(char[] data, int offset, int count) :返回指定数组中表示该字符序列的 String

static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String

	@Test
    public void test3(){
        char[] arr = {'a','b','c'};
        String s1 = new String(arr);
        String s2 = String.valueOf(arr);
        System.out.println("s1 = " + s1);
        System.out.println("s2 = " + s2);
    }

    @Test
    public void test2(){
        String str = "hello";
        char[] chars = str.toCharArray();//把字符串转为字符数组
        Arrays.sort(chars);
        System.out.println(chars);//ehllo
    }

    @Test
    public void test1(){
        String name = "张三";
        //得到第一个字符
        char first = name.charAt(0);
        System.out.println("first = " + first);
        
        char second = name.charAt(1);
        System.out.println("second = " + second);
    }

    @Test
    public void test(){
        Scanner input = new Scanner(System.in);

        System.out.print("请输入性别:");
        char gender = input.next().charAt(0);
        /*
        先调用input对象的next()得到一个字符串对象,
        然后调用字符串对象的charAt()方法,返回第1个字符
         */

        System.out.println("gender = " + gender);

        input.close();
    }

编码与解码

byte[] getBytes():编码,把字符串变为字节数组,按照平台默认的字符编码方式进行编码
----------------------------------- byte[] getBytes(字符编码方式):按照指定的编码方式进行编码

new String(byte[] ) 或 new String(byte[], int, int):解码,按照平台默认的字符编码进行解码
new String(byte[],字符编码方式 ) 或 new String(byte[], int, int,字符编码方式):解码,按照指定的编码方式进行解码

编码:把字符串转为字节数组 -->很多的IO操作都是基于字节
解码:把字节数组转为字符串 -->使用字节IO流读取的数据,怎么用字符串显示出来

char:占2个字节 ==>JVM内存中,Unicode编码值占2个字节
char->byte ==>用了环境编码 UTF-8,GBK等

        不同的编码对char表示方式不同。
        GBK->1个汉字2个字节
        UTF8->1个汉字3个字节
        ISO8859-1 ->所有字符都是1个字节
        ....

如果编码方式和解码方式使用不同的字符集,会乱码。

//IO流操作FileInputStream和FileOutputStream后面IO流章节学习,大家先不着急
    @Test
    public void test5()throws IOException{
        FileInputStream fis = new FileInputStream("d:\\1.txt");
        byte[] data = new byte[1024];
        int len;
        while((len = fis.read(data)) != -1){
            System.out.println(new String(data, 0, len,"GBK"));//以GBK解码文件内容
        }
        fis.close();

    }

    @Test
    public void test4() throws IOException {
        String str = "尚硅谷";
        FileOutputStream fos = new FileOutputStream("d:\\1.txt");
        fos.write(str.getBytes());//以字节的方式输出字符串
        fos.close();
    }

    @Test
    public void test3() throws UnsupportedEncodingException {
        byte[] data = {-55, -48, -71, -24, -71, -56};
        String str1 = new String(data);//按照平台默认的编码进行解码,这里按照UTF8进行解码
        System.out.println(str1);

        String str2 = new String(data, "GBK");
        System.out.println(str2);//尚硅谷
    }

    @Test
    public void test2() throws UnsupportedEncodingException {
        String s1 = "尚硅谷";
        byte[] bytes = s1.getBytes("GBK");
        System.out.println(Arrays.toString(bytes));
        //[-55, -48, -71, -24, -71, -56]
        /*
        GBK中1个汉字2个字节
         */
    }
    @Test
    public void test1(){
        String s1 = "尚硅谷";
        byte[] bytes = s1.getBytes();
        /*
        getBytes()表示按照平台默认的编码处理字符串。
        平台默认的编码,当前IDEA设置为UTF-8。
        UTF-8会汉字处理,一般的汉字都是1个汉字3个字节
         */
        System.out.println(Arrays.toString(bytes));
        /*
        [-27, -80, -102, -25, -95, -123, -24, -80, -73]
         */
    }

开头与结尾

boolean startsWith(xx):是否以xx开头
boolean endsWith(xx):是否以xx结尾

	@Test
    public void test2(){
        /*
        需求:判断某个用户是否是姓张的

         */
        String name = "章三丰";
        System.out.println(name.startsWith("张"));
    }

    @Test
    public void test1(){
        /*
        需求:判断某个文件是否是Java的源文件。
        Java源文件是以“.java”结尾的文件
         */
        String filename = "HelloWorld.class";
        System.out.println(filename.endsWith(".java"));//true
    }

正则表达式

boolean matches(正则表达式):判断当前字符串是否匹配某个正则表达式

正则表达式,又称规则表达式(英语:Regular Expression,在代码中常简写为regex、regexp或RE)。
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,
这个“规则字符串”用来表达对字符串的一种过滤逻辑。通常被用来检索、替换那些符合某个模式(规则)的文本。

    @Test
    public void test3(){
        //验证用户名和密码,要求第一个字必须为字母,一共6~16位字母数字下划线组成
        String str = "8chai123456";
        System.out.println(str.matches("^[a-zA-Z]\\w{5,15}$"));
        // ^:字符串的开头
        //$ :字符串的结尾
        //[a-zA-Z]:第一个字符是字母,大小或小写
        //\w:单词字符,[a-zA-Z_0-9] 字母、数字、下划线
        //{5,15}:至少5位,最多15位,因为第一个字符单独判断了,后面再加5~15位
    }

    @Test
    public void test2(){
        Scanner input = new Scanner(System.in);
        System.out.print("请输入一个字符串:");
        String words = input.next();

        /*
        判断用户输入的字符串是否是一个6位数的纯数字组成的字符串,例如:123456  ,例如银行密码啥的必须是纯数字组成。
         */
        //如果不用正则,就麻烦点
        //如果使用正则,就比较简单
        //字符串是1个或多个数字组成
        //正则:\d{6}  \在正则有特殊意义,在Java中也是转义
        System.out.println(words.matches("\\d{6}")); // \\表示一个\


        input.close();
    }

    @Test
    public void test(){
        Scanner input = new Scanner(System.in);
        System.out.print("请输入一个字符串:");
        String words = input.next();

        /*
        判断用户输入的字符串是否是一个纯数字组成的字符串,例如:123456  ,例如银行密码啥的必须是纯数字组成。
         */
        //如果不用正则,就麻烦点
        //如果使用正则,就比较简单
        //字符串是1个或多个数字组成
        //正则:\d+  \在正则有特殊意义,在Java中也是转义
        System.out.println(words.matches("\\d+")); // \\表示一个\
        input.close();
    }

替换

String replace(xx,xx):不支持正则
String replaceFirst(正则,value):替换第一个匹配部分
String replaceAll(正则, value):替换所有匹配部分

	@Test
    public void test2(){
        String str = "熊大最棒";
        str = str.replace("熊大","xx");
        System.out.println("str = " + str);
    }
    @Test
    public void test1(){
        String str = "hello562wor8ld8901java";
        //去掉里面的数字,保留所有的字母
        str = str.replaceAll("\\d","");//把所有数字替换为空字符串,相当于去掉数字
        System.out.println("str = " + str);
    }

    @Test
    public void test(){
        String str = "hello562wor8ld8901java";
        //去掉里面的数字,保留所有的字母
        str = str.replaceFirst("\\d","");//把第一个数字替换为空字符串,相当于去掉数字
        System.out.println("str = " + str);
    }

拆分

String[] split(正则):按照某种规则进行拆分

	@Test
    public void test3(){
        String str = "张三.23|李四.24|王五.25";
        //把上面的数据拆处理,放到学生对象中
        /*
        先按照|拆分为多个学生信息
         */
        String[] strings = str.split("\\|");
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }

        //创建一个学生的对象数组
        Student[] students =new Student[strings.length];

        /*
        对每一个学生,按照.拆分出姓名和成绩

        张三.23
        李四.24
        王五.25

        张三  23  分别放到nameAndScore数组的[0]和[1]元素中

         */
        for (int i = 0; i < strings.length; i++) {
            String[] nameAndScore = strings[i].split("\\.");
            students[i] = new Student(nameAndScore[0],Integer.parseInt(nameAndScore[1]));
        }

        for (int i = 0; i < students.length; i++) {
            System.out.println(students[i]);
        }

    }

    @Test
    public void test2(){
        String str = "1Hello2World3java4atguigu";
        str = str.replaceFirst("^\\d","");
        System.out.println("str = " + str);
        String[] strings = str.split("\\d");
        System.out.println("单词个数:" + strings.length);
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }
    }

    @Test
    public void test(){
        String str = "Hello,World,java,atguigu";
        //想要把这些单词一个一个拆分出来,存到一个字符串数组中
        //它们都是以,分割的
        String[] strings = str.split(",");
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }
    }

Student类

 private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", score=" + score +
                '}';
    }

StringBuilder-StringBuffer-普通字符

@Test
    public void testString(){
        long start = System.currentTimeMillis();//获取当前系统时间
        //接下来拼接了10000次的字符串,从0拼接到10000
        String s = new String("0");
        for(int i=1; i<=10000; i++){
            s += i;//字符串拼接
        }
        long end = System.currentTimeMillis();//又获取一次当前系统时间
        System.out.println("String拼接+用时:"+(end-start));//前后两次时间的差值,就相当于上面循环用的总时间  ,例如336毫秒

        /*
        Runtime.getRuntime():获取JVM运行环境
        totalMemory():总内存
        freeMemory():空闲内存
        totalMemory() - freeMemory():已使用内存
         */
        long memory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        System.out.println("String拼接+memory占用内存: " + memory);//例如:472427216字节
    }

    @Test
    public void testStringBuilder(){
        long start = System.currentTimeMillis();
        StringBuilder s = new StringBuilder("0");//使用StringBuilder类代替String类
        for(int i=1; i<=10000; i++){
            s.append(i);//字符串拼接,用的是StringBuilder的append方法
        }
        long end = System.currentTimeMillis();
        System.out.println("StringBuilder拼接+用时:"+(end-start));//4毫秒
        long memory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        System.out.println("StringBuilder拼接+memory占用内存: " + memory);//13421960字节
    }

    @Test
    public void testStringBuffer(){
        long start = System.currentTimeMillis();
        StringBuffer s = new StringBuffer("0");//这里StringBuffer和StringBuilder是亲兄弟,和String是堂兄弟
        for(int i=1;i<=10000;i++){
            s.append(i);
        }
        long end = System.currentTimeMillis();
        System.out.println("StringBuffer拼接+用时:"+(end-start));//3
        long memory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        System.out.println("StringBuffer拼接+memory占用内存: " + memory);//13422632
    }

StringBuilder-StringBuffer区别

因为String类的对象是不可变的,只要修改就会产生新对象。
那么如果程序中,涉及到对字符串的频繁的处理,有时候需要借助StringBuffer和StringBuilder来提高处理效率。

StringBuilder和StringBuffer是API方法完全一致的,差别就在于。
StringBuilder是线程不安全的,方法没有加synchronized修饰。
StringBuffer是线程安全的,方法前面加synchronized修饰。

因为大多数的字符串内容,不会被多个线程同时访问,是单个线程使用的,所以没必要加锁。加锁反而麻烦了。
StringBuilder类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。
如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。

StringBuffer和StringBuilder是可变字符串,称为字符串缓冲区。
要修改字符串内容,是在StringBuffer和StringBuilder原对象基础上直接修改的,不会返回新对象。
它们都支持:append(追加)、delete(删除)、insert(插入)、reverse(反转)等等操作。

为什么说它们是可变字符串缓冲区?
因为它们内部使用了一个非final修饰的char[]来存储字符串内容。
相当于StringBuffer和StringBuilder是一个动态数组,只不过里面的数组是char[],不是Object[].

 @Test
    public void test4(){
        StringBuilder s = new StringBuilder();
        s.append("hello")
                .append("world")
                .append("chailinyan");
    }


    @Test
    public void test3(){
        StringBuilder s = new StringBuilder("hello");
        s.reverse();//String类没有这个方法
        System.out.println(s);//olleh
    }

    @Test
    public void test2(){
        StringBuilder s = new StringBuilder();
        s.append("hello").append("world").append(1).append(true);
        System.out.println(s);//helloworld1true
    }


    @Test
    public void test1(){
        StringBuilder s1 = new StringBuilder();
        s1.append("hello");

        StringBuffer s2 = new StringBuffer();
        s2.append("hello");
    }

正则表达式构造摘要

(1)字符类

[abc]abc(简单类)

[^abc]:任何字符,除了 abc(否定)

[a-zA-Z]azAZ,两头的字母包括在内(范围)

(2)预定义字符类

.:任何字符(与行结束符可能匹配也可能不匹配)

\d:数字:[0-9]

\D:非数字: [^0-9]

\s:空白字符:[ \t\n\x0B\f\r]

\S:非空白字符:[^\s]

\w:单词字符:[a-zA-Z_0-9]

\W:非单词字符:[^\w]

(3)POSIX 字符类(仅 US-ASCII)

\p{Lower}小写字母字符:[a-z]

\p{Upper}大写字母字符:[A-Z]

\p{ASCII}所有 ASCII:[\x00-\x7F]

\p{Alpha}字母字符:[\p{Lower}\p{Upper}]

\p{Digit}十进制数字:[0-9]

\p{Alnum}字母数字字符:[\p{Alpha}\p{Digit}]

\p{Punct}标点符号:!"#$%&’()*+,-./:;<=>?@[]^_`{|}~

\p{Blank}空格或制表符:[ \t]

(4)边界匹配器

^:行的开头

$:行的结尾

(5)Greedy 数量词

X?X,一次或一次也没有

X*X,零次或多次

X+X,一次或多次

X{n}X,恰好 n

X{n,}X,至少 n

X{n,m}X,至少 n 次,但是不超过 m

(6)Logical 运算符

XYX 后跟 Y

X|YXY

(X):X,作为捕获组

(7)特殊构造(非捕获)

(?:X) :X,作为非捕获组

(?>X): X,作为独立的非捕获组

(?=X) :X,通过零宽度的正 lookahead

(?<=X) :X,通过零宽度的正 lookbehind

(?!X) :X,通过零宽度的负 lookahead

(?<!X) :X,通过零宽度的负 lookbehind

2、常见的正则表达式示例

  • 验证用户名和密码,要求第一个字必须为字母,一共6~16位字母数字下划线组成:(1\w{5,15}$)
  • 验证电话号码:xxx/xxxx-xxxxxxx/xxxxxxxx:(^(\d{3,4}-)\d{7,8}$)
  • 验证手机号码:( ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$ )
  • 验证身份证号: (\d{15}$)|(^\d{18}$)|(\d{17}(\d|X|x)$)
  • 验证Email地址:(^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$)
  • 只能输入由数字和26个英文字母组成的字符串:(2+$)
  • 整数或者小数:(3+(.[0-9]+){0,1}$)
  • 中文字符的正则表达式:([\u4e00-\u9fa5])
  • 金额校验(非零开头的最多带两位小数的数字):(^([1-9][0-9]*)+(.[0-9]{1,2})?$)
  • IPV4地址:(((\d{1,2})|(1\d{1,2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{1,2})|(2[0-4]\d)|(25[0-5]))

  1. a-zA-Z ↩︎

  2. A-Za-z0-9 ↩︎

  3. 0-9 ↩︎

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值