Java String API 常用的String方法详解

标题


这块仅仅是方法的简单使用 至于底层是如何进行的感兴趣自己在点开看源码 以及如何跟具体业务联合使用还得多练,熟能生巧。

String类的特性

String类 是final修饰的,不可以被继承。
String类的底层是基于char数组的。

Java中String类的构造方法

public String():空构造
public String ( String original):把字符常量值转成字符串
public String(byte[] bytes):把字符串数组反转成字符串
把字符数组的一部分转成字符串

/**
* 注意是字符char或byte数组 
*/
  		byte[] b={'1','2','4','6','7'};
        String s = new String(b);
        String s1 = new String(b,2,2);
        System.out.println(s);//12467
        System.out.println(s1);//46


	 String s2 = new String(new char[]{'a', 'b', 'c'}, 0, 3);
	 System.out.println("s2:" + s2);//abc
	 //非byte char会有问题
  String s3 = new String(new int[]{1, 'b', 'c'}, 0, 3);
  System.out.println("s3:" + s3);//s3:bc

String类的 intern() 注意还跟jdk有关

(JDK版本不同,字符串常量池的位置不一样,里面存放的内容也不同。JDK1.6及之前的版本,常量池是在方法区的,则字符串字面量的对象是直接存放在常量池中的;而JDK1.7及之后的版本,常量池中存放的是对象的引用(避免对象多次创建)。)

该方法的作用意义:
个人觉得给String类中加入这个方法可能是为了提升一点点性能,因为从常量池取数据比从堆里面去数据要快一些。下面说法更好点:

intern()方法的用途: 在用new的方式去创建大量的字符串的时候,我们可以在其后调用intern()方法, 这样在底层操作的时候,会先在堆中创建一个对象,然后在去字符串常量池中创建一个字符串对象 (这是在常量池中没有该字符串的情况),由于字符串常量池中不会存在内容相同的两个字符串, 都是唯一的,正式这样的原因,才会明显的降低内存的使用大小, 在引用时会直接从常量池中取相应的字符串, 而堆中那个在没有引用时就会被GC(垃圾回收掉)了。
像一些大型的社交网站,需要创建大量的字符串,这样的就可以使用intern()方法了。

intern()是字符串对象的一个方法,它底层是一个native直接是调用了本地方法
2、调用这个方法之后 就是去看当前字符串是否在常量池中存在

    (1)存 在:那就直接返回该字符串在字符串常量池中所对应的地址给栈中要引用这个字符串的变量。
    (2)不存在:
    ① jdk 1.6:先在字符串常量池中创建该字符串,地址与堆中字符串地址不相同。
     然后再返回刚创建的字符串在字符串常量池中所对应的地址给栈中要引用这个字符串的变量。
    ② jdk 1.7及以后:直接将堆中(不是字符串常量池中)该字符串的地址复制到字符串常量池中,
     这样字符串常量池就有了该字符串的地址引用,也可以说此时字符串常量池中的字符串
     只是一个对  堆中字符串对象的引用,它们两个的地址相同,
     然后再把这个地址返回给栈中要引用这个字符串的变量。

如果不是用双引号直接声明的String对象,可以使用String 提供的intern 方法:
intern方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中。例如:
String str = new String(“I love you?”).intern();
jdk 1.7 分析:首先上面这个str会进栈,然后会在堆中创建一个 new String()对象,
再把这个对象在堆中的地址复制给字符串常量池中,最后再将常量池中的该字符串地址引用到栈中str。
通俗点讲,intern String 就是确保字符串在内存里有一份拷贝,这样可以节约内存空间,
加快字符串操作的任务的执行速度,注意,这个值会被存放在字符串内部池中。也就是
System.out.println((“a” + “b” + “c”).intern() == “abc”);//true
在jdk 1.7 及之后字符串常量池和静态变量就放到了堆中。堆中的字符串对象创建一般都是在eden(伊甸园)中创建的,
而字符串常量池虽然也在堆中,但它们两压根就不是在一个内存区域中。

针对jdk1.7之后 下面例子弄懂就差不多了


        //todo ==或equals为 false   在怎么intern 也是 false  intern是区分大小写的    这一小块有点绕别给自己干进去了
        String str0 =  new String("计算机");
        String str1 = new StringBuilder("计算机").toString();
        //todo 这里 str1 跟 str2 没调用append 其实都跟 new String("计算机") 一个意思
        String str2 = new StringBuilder("计算机").toString();

        System.out.println(str0 == str0.intern());//false
        System.out.println(str1 == str1);//true
        System.out.println(str1.intern() == str1);//todo false   str1.intern()相当于 String str1 = "计算机"
        System.out.println(str1== str1.intern());//todo false

        System.out.println(str2 == str2.intern());//todo false
        System.out.println(str2.intern() == str2);//todo false

        System.out.println(str1.intern() == str2.intern());//true

        //todo 注意跟上面不太一样
        String str3 = new StringBuilder("计算机").append("软件").toString();
        String str4 = new StringBuilder("计算机").append("软件").toString();
        String str34 = new StringBuilder("计算机34").append("软件").toString();
        System.out.println(str3 == str3);//true
        System.out.println(str3 == str3.intern());//todo true 因为之前没有StringBuilder("计算机") 所以创建的引用和intern()返回的引用相同
        System.out.println(str3.intern() == str3);//todo true
        System.out.println(str3.intern() == str3.intern());//true

        System.out.println(str4 == str4);//true
        System.out.println(str4 == str4.intern());//todo false //"java在StringBuilder("计算机")之前已经出现过",所以intern()返回的引用与新创建的引用不是同一个
        System.out.println(str4.intern() == str4);//todo false
        System.out.println(str4.intern() == str4.intern());//true

        System.out.println(str34.intern() == str34);//true 因为之前没有StringBuilder("计算机34") 所以创建的引用和intern()返回的引用相同



        //todo  这一块有点意思 .intern()前后可能为true也会为false 你的确认当前常量池中到底有没有该字符串常量
        String str5 = new String("a") + new String("b"); //todo 因为+号存在 隐式转化为String字符串了
        System.out.println(str5.intern() == str5);// true


        String str6 = new String("a") + new String("b");
        //当str5 为这两种形式提前出现 String str5 = "ab";  String str5 = new String("ab");  也会造成false
        System.out.println(str6.intern() == str6);// false   todo  因为上面 str5的存在已经在常量池创建了ab 这里不会在创建
        String str7 = "ab";
        System.out.println(str7 == str5);// true
        System.out.println(str7 == str6);// false

		String strg1 = "aaa";
        String strg2 = "bbb";
        String strg3 = "aaabbb";
        String strg4 = strg1 + strg2;
        System.out.println(strg3 == strg4); // false
        System.out.println(strg3 == strg4.intern()); // true

       

深入理解

String strOne = new String("11");//在堆中和字符串常量池中都创建了该字符串11对象,但它们地址不相同
strOne.intern();//调用此方法之前,字符串常量池中已经存在了"11",所以什么也不做  在intern之前,string池已经有了11,因而intern返回11,不会指向strOne
String s22 = "11";//这时在字符串常量池中已经存在11对象了,所以此步只是把new String()在常量池中创建11对象地址赋给s2
System.out.println(strOne == s22);//jdk6:false   jdk7/8:false   一个地址是在堆中一个在常量池中肯定不相等
System.out.println(strOne.intern() == s22);//true

 String strTwo = new String("9") + new String("9");//s3变量记录的地址为:new String("99")
//执行完上一行代码以后,字符串常量池中,是否存在"99"呢?答案:不存在!!
strTwo.intern();//todo 在字符串常量池中生成"99"。如何理解:
//jdk6:创建了一个新的对象"99",也就有新的在常量池中的地址。
//jdk7:此时常量中并没有创建"99,而是创建一个指向堆空间中new String("99")的地址,两个地址相同
String s4 = "99";//s4变量记录的地址:使用的是上一行代码代码执行时,在常量池中生成的"99"的地址
System.out.println(strTwo == s4);//jdk6:false  jdk7/8:todo  true
 

String str61 = new String("ac") + new String("bc");
System.out.println(str61.intern() == str61);// true
String strtwo1 = "acbc";
System.out.println(strtwo1 == str61);// true

//todo  注意
String str1w = "abcd";
String str2w = "abcd";
System.out.println((str1w + "a") == (str2w + "a"));//false;进行了+连接地址不一样
System.out.println(("abcd" + "a") == ("abcd" + "a"));//true        
	    String a = "123abc";
        String b = "123";
        String c = b + "abc"; //此处由于b是变量,编译器是算不出来的,第4点只根据一行进行判断
        System.out.println(a==c); //false

        String d = '1'+23+"abc";
        String d2 = "1"+23+"abc";
        System.out.println(Integer.valueOf('1'));//49
        System.out.println(d); //72abc  注意:'1'的值是49,所以结果是72abc
        System.out.println(a==d); //false
        System.out.println(d2==a); //true

如何保证变量S指向的是字符串常量池中的数据呢?

3种方式:

		//todo
        String one = "hello";// 方法一:字面量定义的方式
        String two = new String("hello").intern();// 方式二:
        String three = new StringBuilder("hello").toString().intern();//方式三

        String two1 = new String("hello");
        String three1 = new StringBuilder("hello").toString();
		//结论:equals比较是值都为true无争意, 而使用==的话比较内存地址 
		//此时只有使用intern()使得指向字符串常量池,其结果才会为true,否则false
        System.out.println(one.equals(two));//true
        System.out.println(one.equals(two1));//true
        System.out.println(one.equals(three));//true
        System.out.println(one.equals(three1));//true
        System.out.println(two.equals(three));//true
        System.out.println(two1.equals(three1));//true
        System.out.println("*****************************");
        System.out.println(one==two);//true
        System.out.println(one==two1);//false
        System.out.println(one==three);//true
        System.out.println(one==three1);//false
        System.out.println(two==three);//true
        System.out.println(two1==three1);//false
        System.out.println("*****************************");

关于String中 new String(“XXX”)系列到底创建了几个对象?

场景1:String s1 = “a” + “b”;创建了几个对象?

答:最多1个,多个字符串常量相加会被编译器优化为一个字符串常量即"ab",如果字符串常量池不存在,则创建该对象。

String s1 = “a” + “b”; 赋值符号右边的"a"、“b”都是常量
对于常量,编译时就直接存储它们的字面值而不是它们的引用
在编译时就直接讲它们连接的结果提取出来变成了"ab"
该语句在class文件中就相当于String s1 =“ab”
然后当JVM执行到这一句的时候, 就在String pool里找
如果没有这个字符串,就会产生一个。

但是如果改成 String s = a+b; 呢 又是几个了。
跟上面的区别是这里是变量
由于编译器的优化,最终代码为通过StringBuilder完成:
StringBuilder builder = new StringBuilder();
builder.append(a);
builder.append(b);
String s = builder.toString();
总结:三个对象分别为
1 StringBuilder
2 new char[capacity]
3 new String(value,0,count);
如果说String对象,则为1个。


我们先看看StringBuilder的构造器
public StringBuilder() {undefined
super(16);
}
看下去
AbstractStringBuilder(int capacity) {undefined
value = new char[capacity];
}
可见,分配了一个16自己长度的char数组
我们看看append的整个过程(注意,源代码我从各个类进行了整合,他们实际上不在一个类里面的)
public StringBuilder append(String str) {undefined
super.append(str);
return this;
}
public AbstractStringBuilder append(String str) {undefined
if (str ==  null)
str = "null";
int len  = str.length();
if (len  == 0)
return this;
int newCount = count + len;
if (newCount > value.length)
expandCapacity(newCount);
str.getChars(0, len, value, count);
count = newCount;
return this;
}
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {undefined
if (srcBegin 
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > count) {undefined
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {undefined
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, offset + srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
可见,我们的代码不会超过16个,所以不会出现扩展value的情况。
而append里面使用了arraycopy的复制方式,也没有产生新的对象。
最后,我们再看StringBuildertoString()方法:
public String toString() {undefined
// Create a copy, don't share the array
return new String(value, 0, count);
}
这里通过前面的数组生成了一个新的String。
大家注意那个默认的16容量,如果题目出现了总长度超过16,则会出现如下的再次分配的情况
void expandCapacity(int minimumCapacity) {undefined
int newCapacity = (value.length + 1) * 2;
if (newCapacity 
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {undefined
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
public static char[] copyOf(char[] original, int newLength) {undefined
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
return copy;

}
可见,expand容量时,增加为当前(长度+1)*2。
注意这里用了Arrays的方法,注意不是前面的 System.arraycopy方法哦。这里产生了一个新的
copy的char数组,长度为新的长度

场景2:new String(“XXX”)

单纯执行new String(“XXX”),底层会创建两个对象(前提常量池没有该常量)。一个是在堆中创建XXX的对象, 另一个是在堆中字符串常量池中创建。这两个对象的内容都是一样的,但是地址是不相同的。

场景3:new String(“a”)+new String(“b”)
答:至少4个,最多6个。
1个new StringBuilder()和2个new String()
另外"a"、“b"可能会在常量池新建对象
最后1个是,StringBuilder()的toString()方法底层实现是new String(value, 0, count)
即:
对象1: new StringBuilder()
对象2: new String(“a”)
对象3: 常量池中的"a”
对象4: new String(“b”)
对象5: 常量池中的"b"
对象6 :new String(“ab”)// StringBuilder 的 toString() 方法中有 new String(value, 0, count) ,
有的同学可能会有疑问,那"ab"字符串不会在常量池中也创建吗?
答案是,不会,最后StringBuilder的toString() 的调用,并不会在字符串常量池中去创建"ab"对象。

场景4:String s3= new String(“a”) + new String(“b”);s3.intern();创建了几个对象?
最难的无非就是再调用intern()方法,比如:
String s3= new String(“a”) + new String(“b”);s3.intern();创建了几个对象?
答:最少4个,最多7个
1个new StringBuilder()和两个new String
另外"a"、"b"可能会在常量池新建对象
最后1个是,StringBuilder()的toString()方法底层实现是new String(value, 0, count)
最后是调用intern()方法,会去找到字符串常量池,判断"ab"是否存在,不存在,则创建"ab"对象。

场景5、场景6暂时不知道正确答案

场景5:String s = new String (“ab”)+"c"创建几个对象了?
这个答案众说纷纭,知道答案的小伙伴还望留言告知,感谢!!!
如果c是变量又是几个????
new 在对象池中创建对象–ab
new+c 在对象池中创建新对象–abc
String s 存储的是新对象“abc”的位置
(也有说:创建了4个字符串对象和1个StringBuilder对象。)
单独使用 ” “ 引号创建的字符串都是直接量,编译期就已经确定存储到常量池中;
使用new String(“”)创建对象会存储到对内存中,是运行期才创建;
使用只包含直接量的字符串连接符如”aa“+”bb”创建的也是直接量编译器就能确定存储到常量池中;
使用包含string直接量(无final修饰符)的字符串表达式(如”aa“+s1)创建的对象是运行期才创建的,存储在堆中(注意:变量在运行时候才知道值为多少便宜时候是不知道的);
通过变量/调用方法连接字符串,都只能在运行时候才能确定变量的值和方法的返回值,不存在编译优化操作

下面这个说法我还是赞成的:
String str = “abc” + new String(“def”);创建了4个,5个,还是6个对象?
结论:创建了4个字符串对象和1个StringBuilder对象。
4个对象的说法:常量池中分别有“abc”和“def”,堆中对象new String(“def”)和“abcdef”。

这种说法对吗?不完全对,如果说上述代码创建了几个字符串对象,那么可以说是正确的。但上述的代码Java虚拟机在编译的时候同样会优化,会创建一个StringBuilder来进行字符串的拼接,实际效果类似:

String s = new String(“def”);
new StringBuilder().append(“abc”).append(s).toString();
很显然,多出了一个StringBuilder对象,那就应该是5个对象。

那么创建6个对象是怎么回事呢?有同学可能会想了,StringBuilder最后toString()之后的“abcdef”难道不在常量池存一份吗?

这个还真没有存,我们来看一下这段代码:

@Test
public void testString3() {
String s1 = “abc”;
String s2 = new String(“def”);
String s3 = s1 + s2;
String s4 = “abcdef”;
System.out.println(s3==s4); // false
}
按照上面的分析,如果s1+s2的结果在常量池中存了一份,那么s3中的value引用应该和s4中value的引用是一样的才对。下面我们看一下debug的效果。

很明显,s3和s4的值相同,但value值的地址并不相同。即便是将s3和s4的位置调整一下,效果也一样。s4很明确是存在于常量池中,那么s3对应的值存储在哪里呢?很显然是在堆对象中。

我们来看一下StringBuilder的toString()方法是如何将拼接的结果转化为字符串的:

@Override
public String toString() {
// Create a copy, don’t share the array
return new String(value, 0, count);
}
很显然,在toString方法中又新创建了一个String对象,而该String对象传递数组的构造方法来创建的:

public String(char value[], int offset, int count)
也就是说,String对象的value值直接指向了一个已经存在的数组,而并没有指向常量池中的字符串。

因此,上面的准确回答应该是创建了4个字符串对象和1个StringBuilder对象。

场景6: String str=new String(“abc”+”def”) 总共创建了几个对象

这个答案众说纷纭,知道答案的小伙伴还望留言告知,感谢!!!
abc一个 def一个 abc+def一个 str一个 总共四个。
4 个,在java中碰到双引号就会创建对象(双引号里内容不同的话),所以abc 、def分别都会创建对象,同时java的字符串是只读的,所以abc+def后又会生成一个新的对象(原来的对象还在内存里),在使用new操作符时又会自动创建新对象,所以共计4个。

也有说两个的 意思是 等价于 String str=new String(“abcdef”) 那么就是1——2个

还有说3个的
“abc”+“def” 被编译器优化成 “abcdef” , 是一个String对象 , 里面包含了一个 char[]数组,数组是一种特殊类型的对象
new String(“abcdef”) 生成一个String类,内容也是 “abcdef”,但是内部的char[]和上面那个String用的同一个,所以没有新的char[]生成
一共是3个。

String 类支持的常用方法列表:

 		String demoStr = "Admin";
        String newDemoStr = new String("Admin");
        String sbDemoStr = new StringBuffer("Admin").toString();
        char[] charDemoStr = {'A', 'd', 'm', 'i', 'n'};
        System.out.println(new String(charDemoStr));//Admin
        System.out.println(charDemoStr);//Admin

char charAt(int index) 返回指定索引处的字符。

 注:值为数值类型 范围从0开始 到 字符串长度-1   毕竟就是当做一个数组
 根据下标去取的值 超过此范围肯定数组下标越界异常
String demoStr = "Admin";
System.out.println(demoStr.charAt(0));//A

int compareTo(Object o) 将这个字符串与另一个对象比较。

int compareTo(Object o):把这个字符串和另一个对象比较
int compareTo(String anotherString):按字典顺序比较两个字符串

int compareTo(String anotherString)  比较两个字符串的字典顺序。
int compareToIgnoreCase(String str)  比较两个字符串按字典顺序,不区分大小写的差异。
注:
如果参数字符串等于此字符串,则返回值 0;
如果此字符串小于字符串参数,则返回一个小于 0 的值;
如果此字符串大于字符串参数,则返回一个大于 0 的值

如果第一个字符和参数的第一个字符不等,结束比较,返回第一个字符的ASCII码差值。
如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,以此类推,直至不等为止,返回该字符的ASCII码差值。
如果两个字符串不一样长,可对应字符又完全一样,则返回两个字符串的长度差值。
int compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑大小写,结论跟上面一致

        //长度相同时:如果第一个字符和参数的第一个字符不等,结束比较,返回第一个字符的ASCII码差值。
        System.out.println("a".compareTo("d"));//-3
        System.out.println("d".compareTo("a"));//3
        System.out.println("dc".compareTo("ad"));//3
        //长度相同时:如果第一个字符和参数的第一个字符相等,则以第二个字符和参数的第二个字符做比较,
        // 以此类推,直至不等为止,返回该字符的ASCII码差值。
        System.out.println("ab".compareTo("ac"));//-1
        System.out.println("ad".compareTo("aa"));//3
        System.out.println("adf".compareTo("aag"));//3
        //如果两个字符串不一样长,可对应字符又完全一样,则返回两个字符串的长度差值。
        System.out.println("abc".compareTo("abcdefg"));//-4
        System.out.println("abc".compareTo("abCdefg"));//32
        System.out.println("abc".compareToIgnoreCase("abCdefg"));//-4
String demoStr = "Admin";
String newDemoStr = new String("Admin");
System.out.println(demoStr.compareTo(newDemoStr) == 0 ? "相等" : "不相等");//相等  一模一样就相等
System.out.println(demoStr.compareTo("Admin") == 0 ? "相等" : "不相等");//相等  一模一样就相等
System.out.println(demoStr.compareToIgnoreCase("admiN") == 0 ? "相等" : "不相等");//相等  忽略大小写后一模一样就相等

Java获得字符串的ASCII值

在线进行字符的ASCII求值,以不同的进制展示结果
常见字符的ASCII码,java中如何获取字符的ASCII码
字符才有ASCII值

//使用Integer.valueOf就可以直接将char类型的数据转为十进制数据表现形式.
int value=Integer.valueOf('1');//49
int value=Integer.valueOf('a');//97
//将这个字符直接赋值给int变量,然后这个int变量的值就是对应的ascii码
char tar = '1';
int res = tar;//49

int res1 = '1';//49  上面合并到一步

int a = '\u002E';//46
int b = '.';//46
System.out.println(Integer.valueOf('.'));//46

java中午字符串(string)和ASCII码互相转换

   public static void fun1() {// ASCII转换为字符串

        String s = "22307 35806 24555 20048";// ASCII码

        String[] chars = s.split(" ");
        System.out.println("ASCII 汉字 \n----------------------");
        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i] + " "
                    + (char) Integer.parseInt(chars[i]));
        }
    }

    public static void fun2() {// 字符串转换为ASCII码

        String s = "新年快乐!";// 字符串

        char[] chars = s.toCharArray(); // 把字符中转换为字符数组

        System.out.println("\n\n汉字 ASCII\n----------------------");
        for (int i = 0; i < chars.length; i++) {// 输出结果

            System.out.println(" " + chars[i] + " " + (int) chars[i]);
        }
    }

String concat(String str) 将指定的字符串串连到这个字符串的结尾。

String demoStr = "Admin";
StringBuffer sbDemoStr = new StringBuffer("Admin")
System.out.println(demoStr.concat(sbDemoStr.toString()));//AdminAdmin
System.out.println(demoStr.concat("Admin"));//AdminAdmin
System.out.println(demoStr+"Admin");//AdminAdmin

boolean contentEquals(StringBuffer sb) 将此字符串与指定的 StringBuffer 比较

如字符串与指定 StringBuffer 表示相同的字符序列,则返回 true;否则返回 false。
有2个contentEquals()方法
public boolean contentEquals(StringBuffer chars)         要判断的stringBuffer
public boolean contentEquals(CharSequence chars)         要判断的字符序列
  String demoStr = "Admin";
  String newDemoStr = new String("Admin");
  System.out.println(demoStr.contentEquals(newDemoStr));//true

  String str1 = "String1";
  String str2 = "String1";
  StringBuffer str3 = new StringBuffer( "String1");
  System.out.println(str1.contentEquals( str3));//true
  System.out.println(str1.contentEquals(str2));//true

  System.out.println(str1.equals(str3.toString()));//true
  System.out.println(str1.equals(str3));//false 因为str3不是String类型

下面两个很简单不赘述了

boolean equals(Object anObject) 比较此字符串与指定的对象。

boolean equalsIgnoreCase(String anotherString) 比较这个字符串到另一个字符串,忽略大小写的考虑。

String的equals与contentEquals区别

这2个方法都可以用来比较String对象内容是否相同。
但是equals只能对2个String对象内容比较,否则返回false;
contentEquals比较类型为java.lang.CharSequence的对象内容是否相同。
String#equals()不仅比较这个字符串的内容还检查另一个被比较的对象是否是String类型,
String#contentEquals()只比较两者的内容是否相同,不检查被比较对象的类型。
比较String类型与String,StringBuilder, StringBuffer, CharBuffer,
等类型内容的相等性使用String#contentEquals()。
 String str1 = "String1";
 StringBuffer str3 = new StringBuffer( "String1");
 System.out.println(str1.contentEquals(str3));//true
 System.out.println(str1.equals(str3));//false

boolean contains(CharSequence s) 当且仅当此字符串包含指定的 char 值序列; 可以是字符、对象

String demoStr = "Admin";
String newDemoStr = new String("Admin");
StringBuffer sbDemoStr = new StringBuffer("Admin")
//判断指定内容中是否包含括号中的内容;
System.out.println(demoStr.contains(sbDemoStr.toString()));//true 
System.out.println(demoStr.contains(sbDemoStr));//true 
 System.out.println(demoStr.contains(newDemoStr));//true 

static String copyValueOf() 返回表示所指定的数组中的字符序列的字符串。

static String copyValueOf(char[] data)   
static String copyValueOf(char[] data, int offset, int count)      
data:char数组、	offset:int值,表示char数组的开始索引、count:int值,表示char数组的长度
返回字符串数组拼接结果,还可以指定起始位置和偏移位置
主要是将java定义的字符串数组转为一个字符串,
StringIndexOutOfBoundsException:如果offset为负的或者超出范围,
或者count大于char数组的长度,或者为负的,则引发此异常。
String demoStr = "Admin";
char[] charDemoStr = {'A', 'd', 'm', 'i', 'n'};
System.out.println(String.copyValueOf(charDemoStr));//Admin
System.out.println(demoStr.copyValueOf(charDemoStr));//Admin 值是char[] data
System.out.println(String.copyValueOf(charDemoStr,0,1));//A

boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束。

endsWith()方法检查字符串是否以指定的字符结尾。
此方法如果参数所表示的字符序列是由该对象表示的字符序列的后缀返回true, 否则为false; 请注意,如果参数是空字符串或等于此String对象由equals(Object)方法确定结果为 true。

endwith和equals方法有些相似,但是不同的是endwith判断是否以指定字符结尾,有点正则表达式的意思

  System.out.println("demoStr ".endsWith("r "));//true

boolean startsWith(String prefix) 方法用于检测字符串是否以指定的前缀开始。

String类的startsWith() 方法用于检测字符串是否以指定的前缀开始,如果字符串以指定的前缀开始,则返回 true;否则返回 false。

语法:public boolean startsWith(String prefix, int toffset) 或 public boolean startsWith(String prefix)

参数: prefix – 前缀 、toffset – 字符串中开始查找的位置

 String Str = new String("xiaohouzi.com");
 System.out.println(Str.startsWith("xiao") );//true
 System.out.println(Str.startsWith("ao") );//false
 System.out.println(Str.startsWith("hou", 4) );//true

byte getBytes() 将此String解码使用平台的默认字符集,并将结果存储到一个新的字节数组中的字节序列。

在Java中,String的 getBytes()方法是得到一个操作系统默认的编码格式的字节数组。这个表示在不同OS下,返回的东西不一样!
String.getBytes(String decode)方法会根据=指定的decode编码返回某字符串在该编码下的byte数组表示

1、 str.getBytes(); 如果括号中不写charset,则采用的是Sytem.getProperty(“file.encoding”),即当前文件的编码方式,

2、 str.getBytes(“charset”);//指定charset,即将底层存储的Unicode码解析为charset编码格式的字节数组方式

3、String str=new String(str.getBytes(“utf-8”),“gbk”)); // 将已经解析出来的字节数据转化为gbk编码格式的字符串,在内存中即为gbk格式的字节数组转为Unicode去交互传递

String.getBytes(Stringdecode)方法会根据指定的decode编码返回某字符串在该编码下的byte数组表示,如:

 //将分别返回“中”这个汉字在GBK、UTF-8、ISO8859-1和unicode编码下的byte数组表示
byte[] b_gbk = "中".getBytes("GBK");//长度为2
byte[] b_utf8 = "中".getBytes("UTF-8");//长度为3
byte[] b_iso88591 = "中".getBytes("ISO8859-1");//长度为1
byte[] b_unicode = "中".getBytes("unicode");//长度为4

将分别返回"中"这个汉字在GBK、UTF-8和ISO8859-1编码下的byte数组表示,此时
b_gbk的长度为2,           b_utf8的长度为3,       b_iso88591的长度为1。

而与getBytes相对的,可以通过new String(byte[], decode)的方式来还原这个"中"字,
这个newString(byte[],decode)实际是使用指定的编码decode来将byte[]解析成字符串.

		String s_gbk = new String(b_gbk,"GBK");//中
        String s_utf8 = new String(b_utf8,"UTF-8");//中
        String s_iso88591 = new String(b_iso88591,"ISO8859-1");//?乱码
        String s_unicode = new String(b_unicode,"unicode");//中

通过输出s_gbk、s_utf8、s_unicode 和s_iso88591,会发现s_gbk和s_utf8及s_unicode 都是"中",而只有s_iso88591是一个不被识别的字符(可以理解为乱码),为什么使用ISO8859-1编码再组合之后,无法还原"中"字?原因很简单,因为ISO8859-1编码的编码表根本就不包含汉字字符,当然也就无法通过"中".getBytes(“ISO8859-1”);来得到正确的"中"字在ISO8859-1中的编码值了 ,所以,再通过newString()来还原就更是无从谈起。
因此,通过String.getBytes(Stringdecode)方法来得到byte[]时,一定要确定decode的编码表中确实存在String表示的码值,这样得到的byte[]数组才能正确被还原。

Java String.getBytes()---------解决utf-8乱码
String str = “XXXXXXXXX”;
new String(str.getBytes(“ISO-8859-1”),“utf-8”);

有时候,为了让中文字符适应某些特殊要求(如httpheader要求其内容必须为iso8859-1编码),可能会通过将中文字符按照字节方式来编码的情况,如:
String s_iso88591 = newString(“中”.getBytes(“UTF-8”),“ISO8859-1”),这样得到的s_iso8859-1字符串实际是三个在ISO8859-1中的字符,在将这些字符传递到目的地后,目的地程序再通过相反的方式Strings_utf8 = newString(s_iso88591.getBytes(“ISO8859-1”),“UTF-8”)来得到正确的中文汉字"中",这样就既保证了遵守协议规定、也支持中文。
因为ISO8859-1不支持中文对照表,这里是先转化为utf对应的字节码,然后存储该字节码,然后在逆向过来

//这样得到的s_iso8859-1字符串
String s_iso88591 = newString("中".getBytes("UTF-8"),"ISO8859-1");
//通过相反的方式来得到正确的中文汉字"中"
Strings_utf8 = newString(s_iso88591.getBytes("ISO8859-1"),"UTF-8");




getBytes() 方法处理后返回的 byte[] 数组中的内容:
byte[] 数组中存放的是字符串响应位置对应的字母的哈希值 ,如字符串中的字母 a 对应 byte[] 数组中的 97 。
另外:返回的 byte[] 数组的长度,与原字符串的长度相等。(中文会出现差异)

    	String str = "abc";
    	byte[] byt = str.getBytes();
        for (byte b : byt) {
            System.out.println(b);//97、98、99
        }

        String str2 = "中国";
        byte[] byt2 = str2.getBytes();
        for (byte b : byt2) {
            System.out.println(b); //-28、-72、-83、-27、-101、-67
        }

		String str3 = "中国";
        byte[] byt3 = str3.getBytes("ISO8859-1");
        for (byte b : byt3) {
            System.out.println(b); //63、63
        }
        
        byte[] byt4 = str3.getBytes("GBK");
        for (byte b : byt4) {
            System.out.println(b); //-42、-48、-71、-6
        }
        
        byte[] byt5 = str3.getBytes("GBK");
        for (byte b : byt5) {
            System.out.println(b); //-42、-48、-71、-6
        }
       

关于如何正确使用String.getBytes().length的情况

同样,在开发会检查字符长度,以免数据库字段的长度不够而报错,考虑到中英文的差异,肯定不能用String.length()方法判断,而需采用String.getBytes().length;而本方法将返回该操作系统默认的编码格式的字节数组。如字符串“Hello!你好!”,在一个中文WindowsXP系统下,结果为12,而在英文的UNIX环境下,结果将为9。因为该方法和平台(编码)相关的。在中文操作系统中,getBytes方法返回的是一个GBK或者GB2312的中文编码的字节数组,其中中文字符,各占两个字节,而在英文平台中,一般的默认编码是"ISO-8859-1",每个字符都只取一个字节(而不管是否非拉丁字符)。所以在这种情况下,应该给其传入字符编码字符串,即String.getBytes(“GBK”).length。

//一个汉字 GBK下2、  UTF-下3、 ISO8859-1下1、unicode下2(n+1)
//一个字符 GBK下1、  UTF-下1、 ISO8859-1下1、unicode下2(n+1)
 		String a = "I love 中国";
        System.out.println(a.length());//9
        System.out.println(a.getBytes().length);//13
        System.out.println(a.getBytes("GBK").length);//11
        System.out.println(a.getBytes("UTF-8").length);//13
        System.out.println(a.getBytes("ISO8859-1").length);//9
        System.out.println(a.getBytes("unicode").length);//20


//  有时候,为了让中文字符适应某些特殊要求(如http header头要求其内容必须为iso8859-1编码)
//  可能会通过将中文字符按照字节方式来编码的情况,如
//String s_iso88591REAL = new String("深".getBytes("UTF-8"),"ISO8859-1");
//String s_iso88591REAL = new String("深".getBytes("GBK"),"ISO8859-1");
String s_iso88591REAL = new String("深".getBytes("unicode"),"ISO8859-1");
System.out.println(s_iso88591REAL);//æ·±    Éî     þÿmñ
System.out.println(s_iso88591REAL.length());//3  2   4


// 这样得到的s_iso8859-1字符串实际是三个在 ISO8859-1中的字符,在将这些字符传递到目的地后,
// 目的地程序再通过相反的方式 
//来得到正确的中文汉字“深”。这样就既保证了遵守协议规定、也支持中文。
//String real = new String(s_iso88591REAL.getBytes("ISO8859-1"),"UTF-8");
//String real = new String(s_iso88591REAL.getBytes("ISO8859-1"),"GBK");
String real = new String(s_iso88591REAL.getBytes("ISO8859-1"),"unicode");
System.out.println(real);//深
System.out.println(real.length());//1


//下面很有意思 以自己编码还原自己编码 后的长度为1
String s_gbk = new String( "深".getBytes("GBK"), "GBK");//长度为1
String s_utf8 = new String("深".getBytes("UTF-8"), "UTF-8");//长度为1
String s_iso88591 = new String("深".getBytes("ISO8859-1"), "ISO8859-1");//长度为1
String s_unicode = new String("深".getBytes("unicode"), "unicode");//长度为1

void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)从这个字符串复制字符到目标字符数组。

第一个參数sourceStart指出了字符串截取所開始的位置; 第二个參数sourceEnd指出了字符串截取所结束的位置(不包含);
第三个參数指出目标(即接收)字符数组;第四个參数指出目标字符数据接收的開始下标。

getChars() 方法将此字符串中的字符目标字符复制到目标字符数组中。
它不返回任何值,但可能会抛出IndexOutOfBoundsException。

  char c[],d[];//定义 c d两个char类型数组
        String s = "巴西足球队击败德国足球队";
        c = new char[2];

        /**
         * 5,表示从s的第5个字符开始
         * 7,表示到s的第7-1个字符结束
         * c,表示或缺的字符放到字符数组c中
         * 0,表示从c的位置0开始存放
         */
        s.getChars(5,7,c,0);//下标5开始 包含5  下标7结束 不包括7  7-5=2 也就是目标的字符长度
        System.out.println(c);//击败
        String c1 = new String(c);
        System.out.println(c1);//击败
        d = new char[s.length()];//此时d为长度12的数组
        s.getChars(7, 12, d, 0);
        System.out.println(d);//德国足球队       (7个空格) 空格来源  s.length()-(12-7)=12-5=7
        s.getChars(5, 7, d, 5);//注意此时d是上面那个值 现在这波操作继续把值放到d
        System.out.println(d);//德国足球队击败     (5个空格)  //通过上面不难得出这里的结果
        s.getChars(0, 5, d, 7);
        System.out.println(d);//德国足球队击败巴西足球队
         System.out.println(s);//巴西足球队击败德国足球队  todo 原有字符

        /**
         *  该方法4个参数
         * 字符开始位置
         * 字符结束位置
         * 字符放到目标字符数组中
         * 从标字符数组的哪个位置开始存放
         *  todo 注: 全程中 不会改变原有字符  只是把原有字符按照你给的参数 放入你的接收数组中
         *  声明接收打数组最佳值为:endPoistion-startPoistion+最后一位参数值
         */
        String r="this啊isa student.";
        int startPoistion=1;
        int endPoistion=7;
        char pointChars[]=new char[endPoistion-startPoistion+1];//最佳长度
        r.getChars(startPoistion,endPoistion,pointChars,1);
        System.out.println(pointChars);//(1个空格) his啊is

int hashCode() 为这个字符串返回一个哈希代码。

谈到hashCode就不得不说equals方法,二者均在Object类里,由于Object类是所有类的基类,所以一切类里都可以重写这两个方法。
java中的==是比较两个对象在JVM中的地址。
equals相等hashCode不一定相等 ,hashCode相等equals不一定相等,hashCode不等 equals一定不等
Java中==和equals的区别,equals和hashCode的区别
Object中的equals()

   public boolean equals(Object obj) {
            return this == obj;// 可见默认的equals方法,直接调用==,比较对象地址。
        //(1)String类中的equals首先比较地址,如果是同一个对象的引用,可知对象相等,返回true。
        //(2)若果不是同一个对象,equals方法挨个比较两个字符串对象内的字符,只有完全相等才返回true,否则返回false。
        }

Object中的hashCode()返回值是在JVM中的32位地址。

public int hashCode() {
    int lockWord = shadow$_monitor_;
    final int lockWordStateMask = 0xC0000000;  // Top 2 bits.
    final int lockWordStateHash = 0x80000000;  // Top 2 bits are value 2 (kStateHash).
    final int lockWordHashMask = 0x0FFFFFFF;  // Low 28 bits.
    if ((lockWord & lockWordStateMask) == lockWordStateHash) {
        return lockWord & lockWordHashMask;
    }
    return System.identityHashCode(this);
}

String.hashCode()
判断对象值是否相等时,会先判断其hashCode是否相等。如果hashCode不相等,则equals()方法返回false;不然,再进行比较。
jvm默认hashCode不相等,则对象值也不相等。其逆反命题是:若对象值相等,则其hashCode也相等。
重写equals()时,必须也重写hashCode()。并且需要保证,值相等的对象,有相同的hashCode。

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
选择数字31的原因:https://blog.csdn.net/weixin_43660856/article/details/102459472
选择数字31是因为它是一个奇质数,如果选择一个偶数会在乘法运算中产生溢出,导致数值信息丢失,因为乘二相当于移位运算。选择质数的优势并不是特别的明显,但这是一个传统。
同时,数字31有一个很好的特性,即乘法运算可以被移位和减法运算取代,来获取更好的性能:31 * i == (i << 5) - i,现代的 Java 虚拟机可以自动的完成这个优化。

默认情况下,“==” 比较对象的存储地址,hashCode返回的是对象的存储地址。
equal比较对象,默认也是比较对象在JVM中的地址,同 “ ==”
大多数类都根据自己的功能重写了equals(),但一般重写equals()就要覆盖hashCode(),重新定义散列码规范。

    从声明看出很明显是对两个对象的地址值进行的比较(即比较引用是否相同)。
     但是我们必需清楚,当String 、Math、还有Integer、Double等这些封装类在使用equals()方法时,
     已经覆盖了object类的 equals()方法。
    其次是hashcode() 方法,在object类中定义如下: public native int hashCode();
    默认情况下,Object中的hashCode() 返回对象的32位jvm内存地址。
    也就是说如果对象不重写该方法,则返回相应对象的32为JVM内存地址。  
    说明是一个本地方法,它的实现是根据本地机器相关的。  
     hash地址不一定是实际的内存地址。
     若干规范
    若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)
     方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,
     那么他们的hashcode应该 相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)
     返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。
    如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法
     得到两个不相同的数(更印证了hash地址不一定是实际的内存地址)。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。
    1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等。
    2、如果两个对象不equals,他们的hashcode有可能相等。
    3、如果两个对象hashcode相等,他们不一定equals(我理解是由于hash冲突造成的)。
    4、如果两个对象hashcode不相等,他们一定不equals。
    todo Java语言对equals()的要求如下,这些要求是必须遵循的:
    对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。
    反射性:x.equals(x)必须返回是“true”。
    传递性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。
    一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。
    任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回false
     以上这五点是重写equals()方法时,必须遵守的准则,如果违反会出现意想不到的结果,请大家一定要遵守

hashcode方法的作用
在java中hashcode是用于快速查找对象物理存储区使用的,主要作用于散列集合(HashSet,HashMap,HashTable…),
在插入散列集合前需要判断obj是否存在,首先判断插入obj的hashcode值是否存在,hashcode值不存在则直接插入集合,
值存在还需判断equals方法判断对象是否相等。使用hashcode码确定对象存放区,
若存放区不存在则对象一定不存在无需equals判断直接插入。若该区存在只比较该区对象equals判断。所以这种方法大量节省判断时间。

 System.out.println("".hashCode());//空字符串的哈希值为 0。
 System.out.println("a".hashCode());//97

int indexOf(String str) :返回第一次出现的指定子字符串在此字符串中的索引。及lastIndexOf

indexOf 方法返回一个整数值,指出 String 对象内子字符串的开始位置。如果没有找到子字符串,则返回-1(注意空格可不是)。
如果 startindex 是负数,则 startindex 被当作零。如果它比最大的字符位置索引还大,则它被当作最大的可能索引。
int indexOf(String str, int startIndex):从指定的索引处开始,返回第一次出现的指定子字符串在此字符串中的索引。

//如果是空字符串,lastIndexOf则返回的结果与length方法的返回结果相同,即返回整个字符串的长度
System.out.println("hello".lastIndexOf(""));//5
System.out.println("hello".indexOf(""));//0  没给第二个参数默认从0开始
System.out.println("hello".lastIndexOf("p"));//-1
System.out.println("hello".indexOf("p"));//-1
//第二个位置参数永远是从左往右数的 即字符下标开始位置 且范围是 0到 length-1
System.out.println("hello".indexOf("o",4));//4
System.out.println("hello".indexOf("o",5));//-1

System.out.println("hello".indexOf(""));//0  
System.out.println("hello".indexOf("",4));//4
System.out.println("hello".indexOf("",5));//5
System.out.println("hello".indexOf("",6));//5
 

String s = "wabcabcabc";
//从指定位置开始找 获取第一次找到时所在整个字符串中的位置
System.out.println(s.indexOf("a", 2));   //4  
// 从第四个字符位置开始往后继续查找,包含当前位置
System.out.println(s.indexOf("c", 3));   //3
//返回目标字符串首字符在字符串中第一次出现的位置
System.out.println(s.indexOf("abc")); //1   先找到abc 在拿a
System.out.println(s.indexOf("abc", 1)); //1
System.out.println(s.indexOf("abc", 2)); //4
System.out.println(s.indexOf("wabcabcabc")); //0  返回的是“wabcabcabc”中“w”的位置。


//todo 下面就是字符对应的数字玩法
String string = "aaa456ac";
//(与之前的差别:上面的参数是 String 类型,下面的参数是 int 类型)参考数据:a-97,b-98,c-99
// 从头开始查找是否存在指定的字符
System.out.println(string.indexOf(99));//indexOf(int ch);返回结果:7
System.out.println(string.indexOf('c'));//indexOf(int ch);返回结果:7
//从fromIndex查找ch,这个是字符型变量,不是字符串。字符a对应的数字就是97。
System.out.println(string.indexOf(97, 3));//indexOf(int ch, int fromIndex);返回结果:6
System.out.println(string.indexOf('a', 3));//indexOf(int ch, int fromIndex);返回结果:6

lastIndexOf 类似原理 只是一个正着来一个反着来
int lastIndexOf(String str, int fromIndex): 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始返向(左)搜索
注意:lastIndexOf() 方法的查找策略是从右往左查找,如果不指定起始索引,则默认从字符串的末尾开始查找。


String str2 = "hellorworld";
//如果是字符串 ,指定位置    窍门:先获取到此时字符串 
//再看最后一次目标字符串首字符出现的位置  没有返回-1
int i6 = str2.lastIndexOf("or", 6);//   hellorw     4
int i7 = str2.lastIndexOf("or", 3);//  hell     -1
int i8 = "hello".lastIndexOf("llo", 3);//  hell     2
//通过上面我们不难看出来substring跟lastIndexOf的关系
System.out.println(Str.substring(0,6+1));//hellorw
System.out.println("helloworld".lastIndexOf("llo"));//2
System.out.println("helloworld".lastIndexOf("llo",0));//-1
System.out.println("helloworld".substring(0,0));//空

String Str = new String("菜鸟教程:www.runoob.com");
//从第14个位置查找字符 o 最后出现的位置  现在的字符串其实就是 菜鸟教程:www.runoob
System.out.println(Str.lastIndexOf( 'o', 14 ));//13
System.out.println("菜鸟教程:www.runoob".lastIndexOf('o'));//13
//通过上面我们不难看出来substring跟lastIndexOf的关系
System.out.println(Str.substring(0,14+1));//菜鸟教程:www.runoob

这一块开始我没弄明白 ,重点

        // note: 下面会输出2,可能是因为此时我们从索引2开始,helloworld的索引2为l,
        // 与"llo"的第一个元素相同,此时会继续往后(右边)寻找,知道匹配完成
        System.out.println(new String("helloworld").lastIndexOf("llo", 2)); // 2
        System.out.println("helloworld".substring(0,2+1).lastIndexOf("llo"));//hel  -1
        System.out.println(new String("hellworllod").lastIndexOf("llo", 3)); // -1
        System.out.println("hellworllod".substring(0,3+1).lastIndexOf("llo"));//hell  -1
        System.out.println(new String("helloworllod").lastIndexOf("llo", 3)); // 2
        System.out.println("helloworllod".substring(0,3+1).lastIndexOf("llo"));//hell  -1

 System.out.println(new String("hellworllod").lastIndexOf("llo", 3)); // -1
 System.out.println("hell".lastIndexOf("llo"));//-1

System.out.println(new String("helloworld").lastIndexOf("llo", 2)); // 2
System.out.println("hel".lastIndexOf("llo"));//-1

//结论:new String("helloworld").lastIndexOf("llo", 2);这个我们得到的目标字符串其实是
       System.out.println("helloworld".substring(0, 2 + 1 + "llo".length() - 1));//hello
       System.out.println("hello".lastIndexOf("llo"));//2

 		//下面是 hel   搜寻目标是 llo  他就的再看搜寻目标长度-1  也就是此时字符串是 hello
        System.out.println(new String("helloworld").lastIndexOf("llo", 2)); // 2
        //下面是 hel   搜寻目标是 llo  他就的再看搜寻目标长度-1  也就是此时字符串是 hellq
        System.out.println(new String("hellqoworld").lastIndexOf("llo", 2)); // -1
        //下面是 hel   搜寻目标是 ll  他就的再看搜寻目标长度-1  也就是此时字符串是 hell
        System.out.println(new String("helloworld").lastIndexOf("ll", 2)); // 2
        //下面是 hel   搜寻目标是 lo  他就的再看搜寻目标长度-1  也就是此时字符串是 hell
        System.out.println(new String("helloworld").lastIndexOf("lo", 2)); // -1
        //下面是 hell   搜寻目标是 llo  他就的再看搜寻目标长度-1  也就是此时字符串是 hellwo
        System.out.println(new String("hellworllod").lastIndexOf("llo", 3)); // -1
        //下面是 hell   搜寻目标是 ll  他就的再看搜寻目标长度-1  也就是此时字符串是 hellw
        System.out.println(new String("hellworllod").lastIndexOf("ll", 3)); // 2
        //下面是 hell   搜寻目标是 lo  他就的再看搜寻目标长度-1  也就是此时字符串是 hellw
        System.out.println(new String("hellworllod").lastIndexOf("lo", 3)); // -1

掌握了上面技巧下面就不是问题

        String str = "01234567890123456789";
        System.out.println(str.length());//20
        //查找字符串“01234567890123456789”中字符‘8'所在的位置(索引从0开始,从前往后搜索)
        System.out.println(str.lastIndexOf('8')); //18
        //查找字符串“01234567890123456789”中字符‘8'所在的位置,从索引为9的位置,即“0123456789”,从后往前搜索。
        System.out.println(str.lastIndexOf('8', 9)); //8
        System.out.println(str.lastIndexOf('8', 11)); //8
        //查找字符串“01234567890123456789”中字符串‘56'所在的位置(索引从0开始,从前往后搜索),返回的是“56”中“5”的位置。
        System.out.println(str.lastIndexOf("56")); //15
        //查找字符串“01234567890123456789”中字符‘8'所在的位置,从索引为9的位置,即“0123456789”,从后往前搜索,返回的是“56”中“5”的位置。
        System.out.println(str.lastIndexOf("56", 9)); //5
        //注意:System.out.println(str.lastIndexOf("56",5))在这个例子中,按理说在“012345”中是查找不到“56”,但返回的却不是-1 ,而是5。
        System.out.println(str.lastIndexOf("56", 5));//5  todo
        //  经过测试,由于查找字符串时,只返回匹配到的字符串中第一个字符的下标。所以即使你将fromIndex的值设置了“5”,你匹配“567890123456789”也是能匹配到的,返回值也是5。
        //  类似例如:
        String str1 = "Hello World!";
        System.out.println(str1.lastIndexOf('o')); //7
        System.out.println(str1.lastIndexOf("o ", 4)); //4
        System.out.println(str1.lastIndexOf("o World", 4)); //4  todo

search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。
search方法可以根据正则表达式查找指定字符串(可以忽略大小写,并且不执行全局检索),同时没有可选参数(即设置开始的检索位置)。

charAt(int index) 返回指定索引处的字符。

可以在字符串内根据指定的索引查找字符,
提示:字符串本质上是字符数组,因此它也有索引,索引从零开始。

String words = "today,monday,sunday";
System.out.println(words.charAt(0));    // 结果:t
System.out.println(words.charAt(1));    // 结果:o
System.out.println(words.charAt(8));    // 结果:n

int length() 返回此字符串的长度。 长度等于字符串中 16 位 Unicode 代码单元的数量。及 String.codePointCount( )

java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性。
java中的length()方法是针对字符串String说的,如果想看这个字符串的长度则用到length()这个方法。


        int[] arr = new int[3];
        System.out.println(arr.length);//使用length获取数组的程度
        String str = "abc";
        System.out.println(str.length());//使用length()获取字符串的长度
      
       

Java String.length( ) 和 String.codePointCount( )区别

java String类提供以下两个方法获取字符串长度:
int length( )
int codePointCount(int beginIndex, int endIndex)

    String.length() 返回字符串所使用的代码单元个数,
    或者说返回字符串占用的char类型数据个数。
    String.codePointCount() 则返回字符串的码点个数,一个字符对应一个码点,
    所以该方法可以真正返回字符串当中的字符个数。

length()方法和codePointCount()方法在某些情况下返回值相等,即字符串当中字符都是常见字符时(码点小于等于0xFFFF).

System.out.println("我爱你中国aa".length());//7
System.out.println("我爱你中国aa".codePointCount(0,"我爱你中国aa".length()));//7

String s = "\uD835\uDD6B"; // 该字符串只有一个特殊字符?,使用其utf-16值描述该字符
System.out.println(s);
System.out.println(s.length());//2
System.out.println(s.codePointCount(0,s.length()));//1

        //下面核心就是"要跟\u0022配对
        //程序打印的是表达式"a".length()+"b".length(),即2。
        System.out.println("a\u0022.length()+\u0022b".length());//2
        //下面这个实际上是在转义" 是字符串整体的一部分
        System.out.println("a\".length()+\"b".length());//14
        System.out.println("a'.length()+'b".length());//14

        System.out.println("a\u0022+\u0022b".length());//al
        System.out.println("a\u0022+\u0022".length());//ao
        System.out.println("\u0022+\u0022".length());//0
        // \u0022 是双引号的Unicode转义字符   它可不能直接放在""里
        System.out.println("\u002E".length());//1
//        System.out.println("\u0022".length() );//报错 未结束的字符串文字
        System.out.println("\\u0022".length());//6
        System.out.println("\"".length());//1



        //todo 感受一下退格符  至于长度 \b作为字符串 2个长度  作为退格符一个长度
        System.out.println("a\b");//空  todo  \b  退格符(Backspace)
        String strA = "\b";//输出 空  长度 1
        String strA1 = "a\b";//输出空  字符串长度2
        String strA2 = "a\bd";//输出空d  字符串长度3
        String strA3 = "wa\bd";//输出空wd  字符串长度4
        String strA51 = "a\\\b";//输出 a 字符串长度3
        String strA61 = "a\\\b";//输出 a 字符串长度3
        //todo 根据a\b可以得出结论 至于长度 \b作为字符串 2个长度  作为退格符一个长度  输出为 往前删一位剩下连接起来

为什么数组有length属性?
首先,数组是一个容器对象,其中包含固定数量的同一类型的值。一旦数组被创建,他的长度就是固定的了 。数组的长度可以作为final实例变量的长度。因此,长度可以被视为一个数组的属性。
有两种创建数组的方法: 无论使用哪种方式,一旦数组被创建,其大小就固定了。

 int[][] arrOne = new int[3][];//  1、通过数组表达式创建数组。
 int[] arrTwo = {1,2,3};//  2、通过初始化值创建数组。

这里可能会有一个疑问,既然数组大小是初始化时就规定好的,那么int[][] arr = new int[3][];
定义的数组并没有给出数组的第二维的大小,那么这个arr的长度到底是如何“规定好”的呢?
其实,arr的长度就是3。其实Java中所有的数组,无论几维,其实都是一维数组。例如arr,分配了3个空间,
每个空间存放一个一维数组的地址,这样就成了“二维”数组。但是对于arr来说,他的长度就是3。

        int[][] b=new int[3][5];
        System.out.println(b.length);//3

Java中为什么没有定义一个类似String一样Array类
因为数组也是对象,所以下面的代码也是合法的:

        Object obj = new int[10];
        int[] intArry = new int[3];
        double[] doubleArry = new double[3];
        //“class [I”代表着”成员类型是int的数组”的class对象运行时类型的签名
        System.out.println(intArry.getClass());//class [I 
        System.out.println(doubleArry.getClass());//class [D

java中length,length(),size()区别

  1. java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性. todo length属性:用于获取数组长度。
  2. java中的length()方法是针对字符串String说的,如果想看这个字符串的长度则用到length()这个方法. todo length()方法:用于获取字符串长度。
  3. java中的size()方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看! todo size()方法:用于获取泛型集合有多少个元素。

boolean matches(String regex) 判断此字符串是否与给定的正则表达式匹配。

①字符匹配 ②分割字符串 ③替换字符串 ④查找替换指定字符串 ⑤查找输出字符串
用来比较两个字符串中指定区域的子串。不设置第一个参数默认大小写敏感 如果这两个子字符串表示相同的字符序列,则结果为 true。

先看源码:

//boolean matches(String regex)
//boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
//boolean regionMatches(int toffset, String other, int ooffset, int len)
 
    public boolean matches(String regex) {
        return Pattern.matches(regex, this);
    }

 public boolean regionMatches(int toffset, String other, int ooffset, int len) {
        byte tv[] = value;
        byte ov[] = other.value;
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0) ||
             (toffset > (long)length() - len) ||
             (ooffset > (long)other.length() - len)) {
            return false;
        }
        byte coder = coder();
        if (coder == other.coder()) {
            if (!isLatin1() && (len > 0)) {
                toffset = toffset << 1;
                ooffset = ooffset << 1;
                len = len << 1;
            }
            while (len-- > 0) {
                if (tv[toffset++] != ov[ooffset++]) {
                    return false;
                }
            }
        } else {
            if (coder == LATIN1) {
                while (len-- > 0) {
                    if (StringLatin1.getChar(tv, toffset++) !=
                        StringUTF16.getChar(ov, ooffset++)) {
                        return false;
                    }
                }
            } else {
                while (len-- > 0) {
                    if (StringUTF16.getChar(tv, toffset++) !=
                        StringLatin1.getChar(ov, ooffset++)) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

 public boolean regionMatches(boolean ignoreCase, int toffset,
            String other, int ooffset, int len) {
        if (!ignoreCase) {
            return regionMatches(toffset, other, ooffset, len);
        }
        // Note: toffset, ooffset, or len might be near -1>>>1.
        if ((ooffset < 0) || (toffset < 0)
                || (toffset > (long)length() - len)
                || (ooffset > (long)other.length() - len)) {
            return false;
        }
        byte tv[] = value;
        byte ov[] = other.value;
        byte coder = coder();
        if (coder == other.coder()) {
            return coder == LATIN1
              ? StringLatin1.regionMatchesCI(tv, toffset, ov, ooffset, len)
              : StringUTF16.regionMatchesCI(tv, toffset, ov, ooffset, len);
        }
        return coder == LATIN1
              ? StringLatin1.regionMatchesCI_UTF16(tv, toffset, ov, ooffset, len)
              : StringUTF16.regionMatchesCI_Latin1(tv, toffset, ov, ooffset, len);
    }

		 // 要验证的字符串
        String str = "service@xsoftlab.net";
        // 邮箱验证规则
        String regEx = "[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}";
        //告知此字符串是否匹配给定的正则表达式
        System.out.println("www.baidu.com".matches("(.*)baidu(.*)"));//true
        System.out.println("www.baidu.com".matches("(.*)google(.*)"));//false
        System.out.println("www.baidu.com".matches("www(.*)"));//true
        System.out.println(str.matches(regEx));//true
        System.out.println(Pattern.matches(regEx, str));//true  todo
        System.out.println(Pattern.compile(regEx).matcher(str).matches());//true  todo
        System.out.println(Pattern.compile(regEx).matcher(str).find());//true  todo
		String str = "service@xsoftlab.net";
        String regEx = "[a-zA-Z_]{1,}[0-9]{0,}@(([a-zA-z0-9]-*){1,}\\.){1,3}[a-zA-z\\-]{1,}";
		 // 编译正则表达式
        Pattern pattern = Pattern.compile(regEx);
        // 忽略大小写的写法
        // Pattern pat = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        // 字符串是否与正则表达式相匹配
        boolean rs = matcher.matches();
        System.out.println(rs);//true

        // 要验证的字符串
        String str4 = "baike.xsoftlab.net";
        // 正则表达式规则
        String regEx4 = "baike.*";
        System.out.println(str4.matches(regEx4));//true
        // 编译正则表达式
        Pattern pattern1 = Pattern.compile(regEx4);
        // 忽略大小写的写法
        // Pattern pat = Pattern.compile(regEx, Pattern.CASE_INSENSITIVE);
        Matcher matcher1 = pattern1.matcher(str4);
        // 查找字符串中是否有匹配正则表达式的字符/字符串
        boolean rs1 = matcher1.find();
        System.out.println(rs1);//true

        //todo JAVA正则表达式,matcher.find()和matcher.matches()到底什么区别?
        // todo 结论:当正则完全匹配字符串,从头到尾正好匹配上字符串,matches()方法是true,find()方法为false
        //  当正则只能匹配字符串中的部分内容,matches()方法是fasle ,find()方法是true
        //find():是否存在与该模式匹配的下一个子序列。简单来说就是在字符某部分匹配上模式就会返回true,
        // 同时匹配位置会记录到当前位置,再次调用时从该处匹配下一个。
        //matches():整个字符串是否匹配上模式,匹配上则返回true,否则false。
        //find是去找有没有包含。  matches是去匹配
        //matches是将整个输入串与模式匹配,find是查找输入串中与模式匹配的子串。
        //1.find()方法是部分匹配,是查找输入串中与模式匹配的子串,如果该匹配的串有组还可以使用group()函数。
        //matches()是全部匹配,是将整个输入串与模式匹配,如果要验证一个输入的数据是否为数字类型或其他类型,一般要用matches()。
        String strMatch = "^(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])\\.(\\d{1,2}|1\\d\\d|2[0-4]\\d|25[0-5])";
//        String strMatch = "^(2[0-5]{2}|2[0-4][0-9]|1?[0-9]{1,2}).(2[0-5]{2}|2[0-4][0-9]|1?[0-9]{1,2}).(2[0-5]{2}|2[0-4][0-9]|1?[0-9]{1,2}).(2[0-5]{2}|2[0-4][0-9]|1?[0-9]{1,2})$";
        String inputStr = "192.168.1.262";
        Pattern pattern3 = Pattern.compile(strMatch);
        Matcher matcher3 = pattern3.matcher(inputStr);
        if (matcher3.find()) {
            System.out.println("matches find");//matches find
        } else {
            System.out.println("not matches find");
        }
        if (matcher3.matches()) {
            System.out.println("matches");
        } else {
            System.out.println("not matches");//not matches
        }
        System.out.println("------------------");
        Pattern patternw = Pattern.compile("abc");
        Matcher matcherw = patternw.matcher("abcd");
        if (matcherw.matches()) {
            System.out.println("matcher.matches() == true");
        } else {
            System.out.println("matcher.matches() == false");//matcher.matches() == false
        }
        if (matcherw.find()) {
            System.out.println("matcher.find() == true");//matcher.find() == true
        } else {
            System.out.println("matcher.find() == false");
        }
        System.out.println("---------------");
        Pattern patternr = Pattern.compile("abcd");
        Matcher matcherr = patternr.matcher("abcd");
        if (matcherr.matches()) {
            System.out.println("matcher.matches() == true");//matcher.matches() == true
        } else {
            System.out.println("matcher.matches() == false");
        }
        if (matcherr.find()) {
            System.out.println("matcher.find() == true");
        } else {
            System.out.println("matcher.find() == false");//matcher.find() == false
        }
        // todo 结论:当正则完全匹配字符串,从头到尾正好匹配上字符串,matches()方法是true,find()方法为false
        //  当正则只能匹配字符串中的部分内容,matches()方法是fasle ,find()方法是true
        //start(),点进方法可以看到返回的是上一个匹配项的起始索引,如果没有匹配项将抛出IllegalStateException异常。同理,end()则为结束的索引
        //matcher.start() 返回匹配到的子字符串在字符串中的索引位置.
        //matcher.end()返回匹配到的子字符串的最后一个字符在字符串中的索引位置.
        //matcher.group()返回匹配到的子字符串
        //上面不理解  再看
        String strs1 = "hellohellohello";
        String regexs = "hello";
        String regexs2 = "(hello)*$";
        Pattern patternwr = Pattern.compile(regexs);
        Pattern patternwr2 = Pattern.compile(regexs2);
        Matcher matcherwr = patternwr.matcher(strs1);
        Matcher matcherwr2 = patternwr2.matcher(strs1);
        System.out.println("---注意重点来了 matcherwr.find()---");
        // 我如果在执行4次matcherwr.find() 就会得到false 因为只有3个hello  也就是说
        //我们还是进入matches()方法看看,从this.oldLast = this.last可以看出,matches()更新了最后匹配位置,所以在使用find()
        // 去找下一个匹配位置时,就找不到了,所以为false。而如果要重置匹配位置,可以使用find(0)(说明:find(int start),
        // 重置匹配器,然后尝试查找索引start开始的下一个满足匹配的子序列,所以find(0)相当于重置为最原始状态)。
        System.out.println(matcherwr.find());//true   //todo  这里执行了一次 matcherwr.find() 导致下面遍历丢失第一次的值
        System.out.println(matcherwr.matches());//false
        System.out.println(matcherwr2.find());//true
        System.out.println(matcherwr2.matches());//true
        System.out.println("================");
        matcherwr.reset();//这里重置否则否则 0->5(丢失)   //使用reset方法重置匹配位置
//        matcherwr.lookingAt();//也可以重置
        while (matcherwr.find()) {
            System.out.println(matcherwr.start() + "->" + matcherwr.end());//0->5(丢失)  5->10  10->15
        }
        System.out.println("================");
        //①字符匹配
        String strS = "target";
        String expression = "t.*";//正则规范
        Pattern p = Pattern.compile(expression); // 正则表达式
        Matcher m = p.matcher(strS); // 操作的字符串
        boolean b = m.matches(); //返回是否匹配的结果
        System.out.println(b);//true

        Pattern p1 = Pattern.compile(expression); // 正则表达式
        Matcher m1 = p1.matcher(strS); // 操作的字符串
        //lookingAt 部分匹配,总是从第一个字符进行匹配,匹配成功了不再继续匹配,匹配失败了,也不继续匹配。
        boolean b1 = m1.lookingAt(); //返回是否匹配的结果
        System.out.println(b1);//true

        Pattern p2 = Pattern.compile(expression); // 正则表达式
        Matcher m2 = p.matcher(strS); // 操作的字符串
        //find  部分匹配,从当前位置开始匹配,找到一个匹配的子串,将移动下次匹配的位置。
        boolean b2 = m2.find(); //返回是否匹配的结果
        System.out.println(b2);//true


        //②分割字符串
        Pattern patterns = Pattern.compile(expression); //正则表达式
        String[] strs = patterns.split(strS); //操作字符串 得到返回的字符串数组

        //③替换字符串
        Pattern p3 = Pattern.compile(expression); // 正则表达式
        Matcher m3 = p3.matcher("text"); // 操作的字符串
        String s3 = m3.replaceAll(strS); //替换后的字符串

        //④查找替换指定字符串
        Pattern p4 = Pattern.compile(expression); // 正则表达式
        Matcher m4 = p4.matcher("text"); // 操作的字符串
        StringBuffer sb = new StringBuffer();
        int i = 0;
        while (m4.find()) {
            m4.appendReplacement(sb, strS);
            i++;    //字符串出现次数
        }
        m4.appendTail(sb);//从截取点将后面的字符串接上
        String s = sb.toString();
        //⑤查找输出字符串
        Pattern p5 = Pattern.compile(expression); // 正则表达式
        Matcher m5 = p5.matcher("text"); // 操作的字符串
        while (m5.find()) {
            m5.start();
            m5.end();
        }

        Pattern patternEnd = Pattern.compile("\\d{3,5}");
        String charSequence = "123-34345-234-00";
        Matcher matcherEnd = patternEnd.matcher(charSequence);
        //false 4 true 123 - 0 true 34345 - 4 true 123 - 0 true 123 - 0

        //虽然匹配失败,但由于charSequence里面的"123"和pattern是匹配的,所以下次的匹配从位置4开始
        System.out.println(matcherEnd.matches());//false
        //测试匹配位置
        matcherEnd.find();//true

        System.out.println(matcherEnd.start());//4
        //使用reset方法重置匹配位置
        matcherEnd.reset();
        //第一次find匹配以及匹配的目标和匹配的起始位置
        System.out.println(matcherEnd.find());//true
        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//123 - 0
        //第二次find匹配以及匹配的目标和匹配的起始位置
        System.out.println(matcherEnd.find());//true
        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//34345 - 4
        System.out.println(matcherEnd.find());//true
        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//234 - 10
        System.out.println(matcherEnd.find());//false
//        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//java.lang.IllegalStateException

        System.out.println("=========");
        //第一次lookingAt匹配以及匹配的目标和匹配的起始位置
        System.out.println(matcherEnd.lookingAt());//true
        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//123 - 0
        System.out.println(matcherEnd.find());//true
        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//34345 - 4
        System.out.println(matcherEnd.find());//true
        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//234 - 10
        System.out.println(matcherEnd.find());//false

        //第二次lookingAt匹配以及匹配的目标和匹配的起始位置
        System.out.println(matcherEnd.lookingAt());//true
        System.out.println(matcherEnd.group()+" - "+matcherEnd.start());//123 - 0

boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 测试两个字符串的区域等于。

检测两个字符串在一个区域内是否相等
ignoreCase如果为 true,则比较字符时忽略大小写
toffset此字符串中子区域的起始偏移量。
other字符串参数。
ooffset字符串参数中子区域的起始偏移量。
len要比较的字符数

        //ignoreCase -- 如果为 true,则比较字符时忽略大小写。 //toffset -- 此字符串中子区域的起始偏移量。
        //other -- 字符串参数。 //ooffset -- 字符串参数中子区域的起始偏移量。//len -- 要比较的字符数。
        //下面5种情况一下子就得到  false
        //toffset 为负。ooffset 为负。toffset+len 大于此 String 对象的长度。ooffset+len 大于另一个参数的长度。
        //存在某个小于 len 的非负整数 k,它满足:this.charAt(toffset+k) != other.charAt(ooffset+k) 都是false
        System.out.println("www.baidu.COM".regionMatches(4, "sss.baidu.com", 4, 9));//false
        //忽略大小写
        System.out.println("www.baidu.COM".regionMatches(true, 4, "s.baidu.com", 2, 9));//true
        //通过实验 设置负数 基本上都是 false  即便是正数  起始位置一致 且字符串一致 length超标后依然false  别说你负数了
        System.out.println("www.baidu.COM".regionMatches(2, "www.baidu.COM", 2, 12));//false
        // www.baidu.COM 长度13 起始位置是2  现在剩余最大长度为 13-2=11
        System.out.println("www.baidu.COM".regionMatches(2, "www.baidu.COM", 2, 11));//true

String replace(char oldChar, char newChar) 返回一个新的字符串,

它是通过用 newChar替换此字符串中出现的所有 oldChar 得到的 即可以支持字符的替换,也支持字符串的替换。

String replaceAll(String regex, String replacement) 替换此字符串中给定的正则表达式与给定替换相匹配的每个子字符串。

String replaceFirst(String regex, String replacement) 方法用指定的文本替换与字符串的正则表达式匹配的第一个子字符串。

        //regex是正则表达式,替换成功返回替换的字符串,替换失败返回原字符串
        //如果要替换的字符不在字符串中,则replace()返回原始字符串。大白话:(字符不在字符串中  则不替换) 注:字符的大小写保持一致
        // 这是因为replace()方法将第一个zz替换为x
        System.out.println("zzz".replace("zz", "x")); // xz
        System.out.println("zzzz".replace("zz", "x")); // xx
        //如果需要基于正则表达式替换子字符串,请使用Java String replaceAll()方法。
        // replaceAll()方法用指定的文本替换与字符串的正则表达式匹配的每个子字符串。
        String str1 = "aabbaaac";
        String str2 = "Learn223Java55@";
        String regex = "\\d+";//"\\d+" 是一个匹配一个或多个数字的正则表达式。
        //所有出现的“aa”都换成“zz”
        System.out.println(str1.replace("aa", "zz")); // zzbbzzac
        //todo 一个典型的字符串本身就是一个正则表达式。
        System.out.println(str1.replaceAll("aa", "zz")); // zzbbzzac//从字符串开头向末尾执行
        //用空格替换数字或数字序列
        System.out.println(str2.replaceAll(regex, " ")); // Learn Java @
        //在正则表达式中,有些字符具有特殊含义。这些元字符是: \ ^ $ . | ? * + {} [] ()
        //如果需要匹配包含这些元字符的子字符串,则可以使用\或使用replace()方法对这些字符进行转义。

        // 将 "+" 替换"#" 使用 replaceAll()方法  使用replaceAll()将“+”替换为“#”
        System.out.println("+a-+b".replaceAll("\\+", "#")); // #a-#b
        // 当我们使用replace()方法时,我们不需要转义元字符。 替换"+" 为 "#" 使用 replace()
        System.out.println("+a-+b".replace("+", "#")); // #a-#b
        //如果只需要替换匹配子字符串的第一个匹配项,请使用Java String replaceFirst()方法。
        //第一次出现的“aa”被替换为“zz”   典型的字符串本身就是正则表达式
        System.out.println("aabbaaac".replaceFirst("aa", "zz")); // zzbbaaac
        //将第一个数字序列替换为空格
        System.out.println("Learn223Java55@".replaceFirst("\\d+", " ")); // Learn Java55@
        System.out.println("a+a-++b".replaceFirst("\\+", "#")); // a#a-++b

replace和replaceAll是JAVA中常用的替换字符的方法,它们的区别是:
相同点是都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串。
另外,如果replaceAll()和replaceFirst()所用的参数据不是基于规则表达式的,(典型的字符串本身就是正则表达式)
则与replace()替换字符串的效果是一样的,即这两者也支持字符串的操作;
参数上:
replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换 两个参数都是字符(串)
replaceAll的参数是regex或者char,即基于规则表达式的替换, 一个正则 一个字符(串)

replace替换的只能是字符或字符串形式,
replaceAll和replaceFirst()是基于规则表达式(正则表达式)的替换
replaceAll是替换所有的,而replaceFirst()仅替换第一次出现的。
另外,如果replaceAll()和replaceFirst()所用的参数据不是基于规则表达式的,
则与replace()替换字符串的效果是一样的,即这两者也支持字符串的操作;
还有一点注意::执行了替换操作后,源字符串的内容是没有发生改变的, 所以替换后 你的去接收这个替换后的结果。

玩懂Java的转义字符


几种特殊的提取过来
//仅仅当正则中只有双\\且之后是非特殊字符 直接匹配不到返回原串,
 System.out.println("a".replaceAll("\\a", "rd"));//a
// \\后若是特殊字符
System.out.println("a/b".replaceAll("\\/", "\\\\"));//a\b
System.out.println("a$b".replaceAll("\\$", "c"));//acb
//原名字符带双\\ 以及正则双\\ 有多种情况
System.out.println("\\a$b".replaceAll("\\$", "c"));//\acb
System.out.println("\\abac".replace("\\abac", "d")); //d
System.out.println("\\abac".replace("\\ab", "d")); //dac
System.out.println("\\abac".replace("\\bac", "d")); //\abac

//第二位需要转义两次所以必须的4个\
 System.out.println("a/b".replaceAll("/", "\\"));//java.lang.IllegalArgumentException
 System.out.println("a/b".replaceAll("/", "\\\\"));//a\b
System.out.println("a/b".replace("/", "\\"));//a\b
//剖析:这里/当成一个特殊字符 此时需要转义 \/来表示我们的这个(/)特殊字符 它需要前面在来个\来转义我们这个\/
//大白话就是:\/代表的是/ 他需要\来转义 所以就成了\\/
System.out.println("a/b".replaceAll("\\/", "\\\\"));//a\b
System.out.println("a/b".replaceAll("\\\\/", "\\\\"));//a/b

这一块放了很多例子啊,没事多试试,答案是对的 ,有些解释可能不太对,自己领悟吧,只要给你个例子你能得到正确答案就行。

      //首先,java会把“\\\\”解释成一个字符串(其中包含两个char)。
      //接下来,由于replaceAll是以正则表达式作为参数,
  // 所以“\\”被解释成一个regex。对于一个regex来说这就代表着一个字符,
 //就是“\”。对后面的那个8个\来说,最终会被解释成“\\”。
        String s = "sdf\\a\\aa";
        System.out.println(s);//   sdf\a\aa
//        System.out.println(s.replaceAll("\\\\", "\\"));//java.lang.IllegalArgumentException
        //todo 参数作为正则 两参数需要转义两次、原字符串转义一次,参数作为字符串两参数只转义一次、原字符串不转义
        System.out.println(s.replaceAll("\\\\", "\\\\"));//sdf\a\aa
        System.out.println(s.replaceAll("\\\\", "\\\\\\\\"));//sdf\\a\\aa
        System.out.println(s.replace("\\", "\\\\"));//sdf\\a\\aa
        System.out.println(s.replace("\\", "\\"));//sdf\a\aa

//        注意: 当正则中只有双\\而且后面跟的是非java特殊字符  直接匹配不到返回原串,
//原名字符带双\\ 以及正则双\\这种情况另外分析
        //多看看 这里结论说不出来 只可意会不可言传 ,得到答案应该不难
        System.out.println("abac".replaceAll("\\a", "rd"));//abac
        System.out.println("a".replaceAll("\\a", "rd"));//a
        System.out.println("a".replaceAll("\\\\a", "rd"));//a
        System.out.println("\\ab".replaceAll("\\\\a", "rd"));//rdb
        System.out.println("\\ab".replaceAll("a", "rd"));//\rdb

        System.out.println("\\abac".replaceAll("\\a", "\\\\d")); //\abac
        System.out.println("\\abac".replaceAll("\\a", "gg")); //\abac

        System.out.println("\\abac".replaceAll("\\abac", "d")); // \abac

        System.out.println("\\abac".replaceAll("\\\\abac", "d")); //d
        System.out.println("\\abacee".replaceAll("\\\\abac", "d")); //dee
        System.out.println("\\abac".replaceAll("\\\\\\\\abac", "d")); //\abac
        System.out.println("\\abac".replaceAll("\\a", "\\\\h")); //\abac
        System.out.println("\\abac".replaceAll("\\a", "\\h")); //\abac
        System.out.println("\\abac".replaceAll("\\a", "h")); //\abac
        System.out.println("\\abac".replaceAll("\\abac", "d")); //\abac
        System.out.println("abac".replace("\\abac", "d")); //abac
        System.out.println("\\abac".replaceAll("abac", "d")); //\d
        //注意这种情况 原名字符带双\\ 以及正则双\\
        System.out.println("\\abac".replace("\\abac", "d")); //d
        System.out.println("\\abac".replaceAll("\\\\a", "d")); // dbac

这块好像有问题,答案是对的 但是解释是否这样待定

        // todo 转义符号使用
		System.out.println("\"Hello!\"");//   "Hello!"  因为"是特殊字符需要\"形式达到转义
        System.out.println("\u0022+\u0022\"hello\"\u0022+\u0022");//"hello"

        //注意 转义关系    CODE: \\\\   Java: \\   Regex: \
        System.out.println("abac".replace("a", "\\a")); //\ab\ac     此时\\a 是\a
        System.out.println("abac".replaceAll("a", "\\a")); //abac     此时\\a 是 a
        System.out.println("abac".replaceFirst("a", "\\a")); //abac   此时\\a 是 a
        System.out.println("abac".replaceAll("a", "\\\\a")); //\ab\ac 此时\\\\a 是 \a
        System.out.println("abac".replaceFirst("a", "\\\\a")); //\abac 此时\\\\a 是 \a
        System.out.println("abac".replaceFirst("\\a", "\\a")); //abac 没找到\a所以输出原字符串
        System.out.println("abac".replaceFirst("\\a", "\\\\a")); //abac 没找到\a所以输出原字符串
       
        String a = "H\\llo";
        System.out.println(a); //=>H\llo
        System.out.println(a.replace("f", "d")); //=>H\llo
        System.out.println(a.replace("\\", "\\\\")); //=>H\\llo
        //todo \\\\是\   \\\\\\\\是\\   也就是三个\\\才能转义一个\  记住它
        System.out.println(a.replaceAll("\\\\", "\\\\\\\\")); //=>H\\llo
        System.out.println(a.replaceAll("f", "d")); //=>H\llo

        //注意:如果是用Stringbuffer或者Stringbuilder定义的字符串,如果要使用如上的replace方法
        // 那么需要在replace前面加上toString,因为Stringbuffer本身的replace方法格式和功能与String的replace方法有所不同。
        //加toString是为了将Stringbuffer类型转化成String类型来处理

        System.out.println("\\");//   \
        System.out.println("\\\\");//   \\
        System.out.println("\\" + "\\\\");// \\\
        System.out.println("\\\\\\");// \\\
        System.out.println("\\\\\\\\");// \\\\

        System.out.println("a/b");//a/b
        System.out.println("abc\b");//ab
        System.out.println("abc\\b");//abc\b
        System.out.println("abc\\\b");//abc
        System.out.println("abc\\\\b");//abc\\b
        //剖析:前面/这里当成一个字符串 此时不需要转义 非特殊字符
        //第二个参数:是\
        System.out.println("a/b".replaceAll("/", "\\\\"));//a\b
        System.out.println("a/kh".replaceAll("/", "\\\\"));//a\kh
        System.out.println("a/b".replaceAll("/", "\b"));//b
//        System.out.println("a/b".replaceAll("/", "\\"));//java.lang.IllegalArgumentException

        System.out.println("\\a$b".replaceAll("\\$", "c"));//\acb
        System.out.println("a$b".replaceAll("\\$", "c"));//acb
        System.out.println("a/b".replaceAll("\\\\/", "\\\\"));//a/b



        //todo 感受一下退格符  至于长度 \b作为字符串 2个长度  作为退格符一个长度
        System.out.println("a\b");//空  todo  \b  退格符(Backspace)
        System.out.println("a\b".replaceAll("\\\\", ""));//因为"a\b" 已经是空了 不管后面参数是什么都是空
        String strA = "\b";//输出 空  长度 1
        String strA1 = "a\b";//输出空  字符串长度2
        String strA2 = "a\bd";//输出空d  字符串长度3
        String strA3 = "wa\bd";//输出空wd  字符串长度4
        String strA51 = "a\\\b";//输出 a 字符串长度3
        String strA61 = "a\\\b";//输出 a 字符串长度3
        //todo 根据a\b可以得出结论 至于长度 \b作为字符串 2个长度  作为退格符一个长度  输出为 往前删一位剩下连接起来

        String strA4 = "a\\b";//输出 a\b 字符串长度3 //todo 这里 前面的\转义后面的\使得后面的\b当做一个字符  不是退格符了
        //todo 这里同理哦 第一个\转义第二个\ 第三个\b就成了退格符了   本来是a/删除/变成a
        String strA5 = "a\\\b";//输出 a 字符串长度3  todo 本来是a\\b 只不过\b是退格符 所以输出 a 长度3
        //第一个/转义第二个/第三个/转义\b 此时是字符  下面都一样不再赘述
        String strA6 = "a\\\\b";//输出 a\\b  字符串长度4
        String strA7 = "a\\\\\b";//输出 a\  字符串长度4
        String strA8 = "a\\\\\\b";//输出 a\\\b  字符串长度5
        String strA9 = "a\\\\\\\b";//输出 a\\  字符串长度5
        String strA10 = "a\\\\\\\\b";//输出 a\\\\b  字符串长度6
        //todo  下面一共9个/ 其中 1,3,5,7为转义 在7的时候转义的是8处的\ 9的时候是\b  此时是退格符
        String strA11 = "a\\\\\\\\\b";//输出 a\\\  字符串长度6
        String strA12 = "a\\\\\\\\\\b";//输出 a\\\\\b  字符串长度7
        //总结:仅仅针对\b    这块得到输出结果已经没有问题了  至于长度 \b作为字符串 2个长度  作为退格符一个长度


        //\表示将下一字符标记为特殊字符。  \\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义。
        //\\中的第一个\表示java的转义字符\由编译器解析,第二个\是正则表达式\由正则表达式引擎解析。
        //Java正则表达式中匹配一个普通的反斜杠是\\\\
        System.out.println("a/b".replaceAll("/", "\\\\"));//a\b
        System.out.println("a/b".replaceAll("//", "\\\\"));//a/b  没匹配到等于原字符串
        System.out.println("a/b".replaceAll("\\/", "\\\\"));//a\b
        System.out.println("a/b".replaceAll("\\//", "\\\\"));//a/b 没匹配到等于原字符串


//        System.out.println("a/b".replaceAll("/", "\\"));//java.lang.IllegalArgumentException
        System.out.println("a/b".replace("/", "\\"));//a\b
        //单引号引的数据 是char类型的——>   单引号只能引一个字符(表示单个字符)
        //双引号引的数据 是String类型的——> 而双引号可以引0个及其以上(引用字符串
        System.out.println("a/b".replace('/', '\\'));//a\b   单引号   转义中单引号双引号区别
//        System.out.println("a/b".replaceAll('/', "f"));//编译不通过 两个参数逗得是String


        //有了上面铺垫下面一眼看出结果
        boolean flg = Pattern.matches("\\\\", "\\");//true  todo 验证了正则4个/代表一个/
        char a = 'a';
        String b = "abc";
        String c = "你好\n\t棒";//
        System.out.println(c);//你好(换行)(\t是补全当前字符串长度到8的整数倍 最少1个最多8个空格)	棒
        char d = '\'';//'
        String e = "\"";//"
        String f = "\\";//\
        String j = "\\\\";
        System.out.println(f + j);// \\\
        String h = "{\"name\":\"翎野君\"}";//{"name":"翎野君"}
        String g = "{\\\"age\\\":\\\"99\\\"}";//{\"age\":\"99\"}
        String k = g.replaceAll("\\\\", "");//{"age":"99"}
        String str = "{\\\"name\\\":\\\"spy\\\",\\\"id\\\":\\\"123456\\\"}";
        System.out.println("str = " + str);//str = {\"name\":\"spy\",\"id\":\"123456\"}

        System.out.println("\\|\\|");// \|\| 

正则表达式中的*,+,?以及\w和\W的区别等常见问题的总结
\s:用于匹配单个空格符,包括tab键和换行符;
\S:用于匹配除单个空格符之外的所有字符;
\d:用于匹配从0到9的数字;
\w:用于匹配字母,数字或下划线字符;
\W:用于匹配所有与\w不匹配的字符;
. :用于匹配除换行符之外的所有字符。

		 较为常用的定位符包括: “^”, “$”, “\b” 以及 “\B”。
		“^”定位符规定匹配模式必须出现在目标字符串的开头 
		“$”定位符规定匹配模式必须出现在目标对象的结尾 
		“\b”定位符规定匹配模式必须出现在目标字符串的开头或结尾的两个边界之一 
		“\B”定位符则规定匹配对象必须位于目标字符串的开头和结尾两个边界之内, 
		即匹配对象既不能作为目标字符串的开头,也不能作为目标字符串的结尾。

java转义字符对照表

转义字符对应编码转义字符对应编码
.u002E*u002A
$u0024+u002B
^u005E``````
{u007B[u005B
(u0028)u0029
?u003F\u005C
"u0002
        String test3 = "*{year}";
        String test = "${year}";
        String test2 = "\\${year}";//如果源字符串有转义字符 优先还原出 转义后的字符串  即:\${year}
        System.out.println(test3.replaceAll("\\*", "20"));//20{year}
        System.out.println(test3.replaceAll("\\?", "20"));//*{year}
        System.out.println(test3.replaceAll("\\\\*", "20"));// todo 20*20{20y20e20a20r20}20
        System.out.println(test3.replaceAll("\\+", "20"));//*{year}
        System.out.println(test3.replaceAll("\\\\+", "20"));//*{year}
        System.out.println(test.replaceAll("$", "20"));//todo ${year}20
        System.out.println(test.replaceAll("\\$", "20"));//20{year}
        System.out.println(test2.replaceAll("\\$", "20"));//todo  \20{year}
        System.out.println(test2.replaceAll("\\\\$", "20"));//  \${year}
        System.out.println(test.replaceAll("\\\\$", "20"));//  ${year}

其他特殊字符自己去试试不一一列举

        System.out.println("hellow\r");//hellow
        System.out.println("hello\rw");//w
        System.out.println("\rhellow");//hellow
        System.out.println("\rhe\rll\row");//ow

JAVA网址带中文问题

java.net.URLEncoder.encode(“xxxx”,“utf-8”)将中文转为16进制字符。

java.net.URLDecoder.decode(“xxxx”,“utf-8”)将16进制字符转为中文。
这个方法根据自己需求进行更改,不能直接使用

System.out.println(decode("http://192.168.1.17:8096/detection-admin\\video\\2020\\11\\4\\浙B99939\\3604252011040004\\浙B99939_1_PDASP_01.mp4", true));
System.out.println(decode("http://192.168.1.17:8096/detection-admin/video/2020/11/4/%E6%B5%99B99939/3604252011040004/%E6%B5%99B99939_1_PDASP_01.mp4", false));
   
 /**
     * @author Longchengbin
     * @description 将网址反斜杠转成正斜杠并将中文转为16进制字符
     * @since 2020-11-4 16:33
     **/
    public static String decode(String url, boolean flag) {

        String s = "";
        try {

            if (flag) {
                String[] strings = url.split("\\\\");
                String s1 = strings[strings.length - 1];//中文位置
                String s2 = strings[strings.length - 3];//中文位置
                //将反斜杠替换成正斜杠
                s = url.replaceAll("\\\\", "/")
                        .replace(s1, URLEncoder.encode(s1, "utf-8")) //将中文转成16进制字符
                        .replace(s2, URLEncoder.encode(s2, "utf-8"));
            } else {
                String[] strings = url.split("/");
                String s1 = strings[strings.length - 1];
                String s2 = strings[strings.length - 3];
                //将正斜杠替换成反斜杠
                s = url.replaceAll("/", "\\\\\\\\")
                        .replace(s1, URLDecoder.decode(s1, "utf-8")) //将16进制字符转为中文。
                        .replace(s2, URLDecoder.decode(s2, "utf-8"));
                String[] split = s.split("\\\\\\\\", 4);
//                for (String s3 : split) {
//                    System.out.println(s3);
//                }
                s=split[0]+"//"+split[2]+"/"+split[3];

            }

        } catch (UnsupportedEncodingException e) {

        }
        return s;
    }

String[] split(String regex) 分割围绕给定的正则表达式匹配的这个字符串。

根据给定正则表达式的匹配拆分此字符串
将一个字符串分割为子字符串,然后将结果作为字符串数组返回。
逐个分隔字符串。split(“”);里面是空,不是空格。

System.out.println(Arrays.toString("hello".split("")));//[h, e, l, l, o]   

String[] split(String regex, int limit)
根据匹配给定的正则表达式来拆分此字符串
. $ | 和 * 等转义字符,必须得加
当分隔符有多个时,用 | 作为连接

      String temp1 = "Welcome-to-Runoob";
        for (String str: temp1.split("-", 2)){
            System.out.println(str);//Welcome、  to-Runoob
        }
       
        String temp2 = "www.runoob.com";
        for (String str: temp2.split("\\.", 3)){
            System.out.println(str);//www、  runoob、  com
        }
        System.out.println();
        String temp3 = "acount=? and uu =? or n=?";
        for (String str: temp3.split("and|or")){
            System.out.println(str);//acount=? 、   uu =? 、  n=?
        }

CharSequence subSequence(int beginIndex, int endIndex) 返回一个新的字符序列,这个序列的子序列。 (左闭右开)

String substring(int beginIndex, int endIndex) 返回一个新的字符串,它是此字符串的一个子字符串。(左闭右开)

String substring(int beginIndex) beginIndex 字符串开始下标,下标从0开始
这个方法经常使用,同时还能搭配indexOf、str.length来使用
注意:substring() 方法是按字符截取,而不是按字节截取。
说明:返回值 一个新的字符串,该字符串值包含 stringObject 的一个子字符串,其内容是从 beginIndex 处到 endIndex-1 处的所有字符,
其长度为 endIndex 减 beginIndex  
如果 start 与 end 相等,那么该方法返回的就是一个空串(即长度为 0 的字符串)。
如果 start 比 end 大 、结尾长度大于字符串长度 报错StringIndexOutOfBoundsException
只要 start 或 end 为负数,报错StringIndexOutOfBoundsException
即:抛出:IndexOutOfBoundsException - 如果 beginIndex或endIndex 为负,
或 endIndex 大于此 String 对象的长度,或 beginIndex 大于 endIndex。
java中subSequence方法和subString方法的区别
根据JDK的文档,String.subSequence只是为了实现CharSequence接口上的同名方法而放在那里的,其行为与String.substring一样。
区别是:substring和subSequence的返回类型不一样,substring返回的是String,subSequence返回的是实现了CharSequence接口的类
也就是说使用subSequence得到的结果,只能使用CharSequence接口中的方法。不过在String类中已经重写了subSequence,
调用subSequence方法,可以直接下转为String对象。
结果一样 不过取出来的东西要做强制类型转换成String

  public CharSequence subSequence(int beginIndex, int endIndex) {
        return this.substring(beginIndex, endIndex);
    }

       CharSequence charSequence = "Admin".subSequence(0, 3);//Adm
        String a = String.valueOf(charSequence);//Adm
        String b = (String)charSequence;//Adm
        System.out.println("Admin".subSequence(0,3));//Adm

        String strSub = "this is my original string";
        //截取将其赋值给str(自身) 这就改变了自己的原有字符串
        strSub=strSub.substring(3);//s is my original string
        strSub=strSub.substring(3,9);//s my o

char[] toCharArray() 这个字符串转换为一个新的字符数组。

字符串转换成字符数组后,每个字符的ASC码与字符T的ASC码进行二进制异或运算。最后把结果转换回字符。

        System.out.println("www.baidu.com".toCharArray());//todo  www.baidu.com
        char myChar[] = "www.baidu.com".toCharArray();//数组  可以遍历数组
        char[] myChar2 = "www.baidu.com".toCharArray();//数组  可以遍历数组
        System.out.println(myChar);//www.baidu.com
        System.out.println(myChar2);//www.baidu.com
        System.out.println(myChar2.toString());//[C@1b2c6ec2
        //虽然上面看似输出的是字符串 但是实际就是数组 你调不了String的方法 请注意


注:要想把char[]转成字符串有以下方式:

 char[] helloArray = {'h', 'e', 'l', 'l', 'o', '.'};

 String helloString = new String(helloArray); //hello.
 System.out.println(String.copyValueOf(helloArray));//hello.
 System.out.println(String.valueOf(helloArray));//hello.
 

下面是对上面的补充

        char[] helloArray = {'h', 'e', 'l', 'l', 'o', '.'};
        String helloString = new String(helloArray);//hello.  todo 方式一 new String() 快速将一个char数组合并成字符串
        //下面都是方式一得来的
        System.out.println(String.valueOf(helloString));//hello.//这种是方式一变形
        System.out.println(helloString);//hello.//这种是方式一变形
        System.out.println(helloString.toString());//hello.//这种是方式一变形
        //方式二
        System.out.println(String.copyValueOf(helloArray));//hello.//这种是方式二
        System.out.println(String.copyValueOf(helloArray, 0, helloArray.length));//方式二变形
        //方式三
        System.out.println(helloArray);//hello.  todo  这个虽然输出是字符串 但是你要把它当做一个字符串掉字符串的操作方法必须下面转一下
        //只要把它转化为真的字符串就可以掉操作字符串的方法
        System.out.println(String.valueOf(helloArray).substring(1, 2));//e
比如System.out.println(xx),括号里面的“xx”如果不是String类型的话,就自动调用xx的toString()方法

 char[] charDemoStr = {'A', 'd', 'm', 'i', 'n'};
 System.out.println(charDemoStr);
 
public void println(char[] x) {
        if (getClass() == PrintStream.class) {
            writeln(x);
        } else {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    }

    public void println(String x) {
        if (getClass() == PrintStream.class) {
            writeln(String.valueOf(x));
        } else {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    }

 public void println() {
        newLine();
    }

 public void println(boolean x) {
        if (getClass() == PrintStream.class) {
            writeln(String.valueOf(x));
        } else {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    }

public void println(char x) {
        if (getClass() == PrintStream.class) {
            writeln(String.valueOf(x));
        } else {
            synchronized (this) {
                print(x);
                newLine();
            }
        }
    }

longint doublefloatchar[] x、StringObjectcharboolean 




Java字符串toLowerCase()方法将字符串的所有字符转换为小写字母。

String toUpperCase() 使用默认语言环境的规则将此String中所有的字符转换为大写。

这两个方法只对英文字母有效,对除了A~Z和a~z的其余字符无任何效果。
String toLowerCase(Locale locale) 将所有在此字符串中的字符使用给定Locale的规则小写。
String toUpperCase(Locale locale) 使用给定Locale的规则将此String中所有的字符转换为大写。
注:这一块字面上没什么大的讲点,有的话就是 参数:Locale 以及比较方法使用.equals()

  //不给 Locale 参数底层调的是  Locale.getDefault()
        String str = "abcdeF 我 ghijklmn";//非字母不受影响
        System.out.println(str.toLowerCase());    // 输出:abcdef 我 ghijklmn
        System.out.println(str.toUpperCase());    // 输出:ABCDEF 我 GHIJKLMN

        System.out.println("trTR".toUpperCase());//TRTR
        System.out.println("trTR".toUpperCase(Locale.forLanguageTag("en")));//TRTR
        System.out.println("trTR".toUpperCase().equals("trTR".toUpperCase(Locale.forLanguageTag("en"))));//true
        //只能用equals比
        System.out.println("abcdeF".toLowerCase()=="abcdeF".toLowerCase());//false
        System.out.println("abcdeF".toLowerCase(Locale.US)=="abcdeF".toLowerCase(Locale.US));//false
        System.out.println("abcdeF".toLowerCase().equals("abcdeF".toLowerCase()));//true

java.lang.String.toUpperCase(Locale locale)方法将所有的字符在该字符串使用给定Locale的规则转为大写。toLowerCase同理
因此我们在使用toLowerCase()方法时,尽量使用toLowerCase(Locale.US)即:给个参数
这个方法来代替(或使用equalsIgnoreCase()方法来比较),这样就不会因为在不同语言的机器上出现一些让人莫名其妙的问题了。
直接使用Locale的静态对象

        Locale aDefault = Locale.getDefault();
        Locale english = Locale.ENGLISH;
        Locale us = Locale.US;

还有另一种方式来创建Locale实例,例如使用静态Locale.forLanguageTag()方法。 具体怎么使用 感兴趣的小伙伴自行百度。

        // Locales with the language "tr" for TURKISH
        //"en" for ENGLISH is created
        Locale TURKISH = Locale.forLanguageTag("tr");
        Locale ENGLISH = Locale.forLanguageTag("en");

Locale类提供了三种构造函数:
• 区域设置(String语言)
• 区域设置(String语言,String 国家)
• 区域设置(String语言,String国家,String变量)
详解Java中用于国际化的locale类
Java中也有用于转换和划分地区的国际化类java.lang.Locale,国际化在程序中设置语言和时间等时非常有用,下面我们就来详解Java中用于国际化的locale类。

Locale 表示地区。每一个Locale对象都代表了一个特定的地理、政治和文化地区。
在操作 Date, Calendar等表示日期/时间的对象时,经常会用到;因为不同的区域,时间表示方式都不同。
下面说说Locale对象的3种常用创建方式。

1、获取默认的Locale
使用方法: 
Locale locale = Locale.getDefault()

2、直接使用Locale的静态对象
Locale.java中提供了以下静态对象
public static final Locale CANADA
public static final Locale CANADA_FRENCH
public static final Locale CHINA
public static final Locale CHINESE
public static final Locale ENGLISH
public static final Locale FRANCE
public static final Locale FRENCH
public static final Locale GERMAN
public static final Locale GERMANY
public static final Locale ITALIAN
public static final Locale ITALY
public static final Locale JAPAN
public static final Locale JAPANESE
public static final Locale KOREA
public static final Locale KOREAN
public static final Locale PRC
public static final Locale ROOT
public static final Locale SIMPLIFIED_CHINESE
public static final Locale TAIWAN
public static final Locale TRADITIONAL_CHINESE
public static final Locale UK
public static final Locale US

3、通过Locale的构造函数创建Locale对象
Locale的构造函数共有3个。如下:
Locale(String language)
Locale(String language, String country)
Locale(String language, String country, String variant)
如:Locale local = new Locale("zh", "CN");

Locale类支持非常多的国家和地区。我们可以通过以下方法,查看Locale支持的全部区域:

Locale[] ls = Locale.getAvailableLocales();
for (Locale locale:ls) {
  System.out.println("locale :"+locale);
}
结果:
All Locales: ja_JP, es_PE, en, ja_JP_JP, es_PA, sr_BA, mk, es_GT, ar_AE, no_NO, sq_AL, 
bg, ar_IQ, ar_YE, hu, pt_PT, el_CY, ar_QA, mk_MK, sv, de_CH, en_US, fi_FI, is, cs, en_MT, 
sl_SI, sk_SK, it, tr_TR, zh, th, ar_SA, no, en_GB, sr_CS, lt, ro, en_NZ, no_NO_NY, lt_LT,
es_NI, nl, ga_IE, fr_BE, es_ES, ar_LB, ko, fr_CA, et_EE, ar_KW, sr_RS, es_US, es_MX, 
ar_SD, in_ID, ru, lv, es_UY, lv_LV, iw, pt_BR, ar_SY, hr, et, es_DO, fr_CH, hi_IN, 
es_VE, ar_BH, en_PH, ar_TN, fi, de_AT, es, nl_NL, es_EC, zh_TW, ar_JO, be, is_IS, es_CO,
es_CR, es_CL, ar_EG, en_ZA, th_TH, el_GR, it_IT, ca, hu_HU, fr, en_IE, uk_UA, pl_PL, 
fr_LU, nl_BE, en_IN, ca_ES, ar_MA, es_BO, en_AU, sr, zh_SG, pt, uk, es_SV, ru_RU, 
ko_KR, vi, ar_DZ, vi_VN, sr_ME, sq, ar_LY, ar, zh_CN, be_BY, zh_HK, ja, iw_IL, bg_BG, 
in, mt_MT, es_PY, sl, fr_FR, cs_CZ, it_CH, ro_RO, es_PR, en_CA, de_DE, ga, de_LU, de, 
es_AR, sk, ms_MY, hr_HR, en_SG, da, mt, pl, ar_OM, tr, th_TH_TH, el, ms, sv_SE, da_DK,es_HN

下面选择其中的两个进行说明,如何利用它们来创建Locale对象:
例如,第一个输出是“ja_JP”。
其中,ja代表“语言”,这里指日语;“JP”代表国家,这里指日本。
我们可以通过如下方法,创建“语言是日语,国家是日本的Locale对象”。
Locale locale = new Locale("ja", "JP");

例如,第三个输出是“en”。
其中,en代表“语言”,这里指英语。
我们可以通过如下方法,创建“语言是英文的Locale对象”。
Locale locale = new Locale("en");

String toString() 这个对象(它已经是一个字符串!)返回字符串形式(这里是自己本身)。

因为toString方法是Object里面已经有了的方法,而所有类都是继承Object,所以“所有对象都有这个方法”。
它通常只是为了方便输出,比如System.out.println(xx),括号里面的“xx”如果不是String类型的话,就自动调用xx的toString()方法
总而言之,它只是sun公司开发java的时候为了方便所有类的字符串操作而特意加入的一个方法
undefined和null没有toString()方法 undefined.toString();//错误 null.toString();//错误
布尔型数据true和false返回对应的’true’和’false’ true.toString();//‘true’ false.toString();//‘false’

String a = null;
String b = "";
//null.toString();//编译不通过:无法取消引用<nulltype>
//true.toString();//不是 'true'  报错:无法取消引用boolean
//false.toString();//不是  'false'报错:无法取消引用boolean
//Boolean.toString();//"function Boolean() { [native code] }" 无法从静态上下文中引用非静态 方法 toString()
//Number.toString();//无法从静态上下文中引用非静态 方法 toString()

//System.out.println(a.toString());//报异常java.lang.NullPointerException
System.out.println(b.toString());//空串

//上面应该是js那边的不是java:  https://www.cnblogs.com/huan-guo/p/8404891.html
        Boolean aBoolean = new Boolean(true);
        System.out.println(aBoolean);//true
        System.out.println(aBoolean.toString());//true

        boolean flag = false;
       // flag.toString();//爆红 boolean没有此方法
        Boolean aBoolean1 = new Boolean(flag);
        System.out.println(aBoolean1.toString());//false

String trim() 返回字符串的一个副本,开头和结尾的空格去除。

作用是去出字符串两端的空格,无论一串字符串两端有多少空格都会去掉, 字符串中间的不会影响,
除此之外,还可以去掉一些特殊的如:\t \n \v \f \r \x0085 \x00a0 ? \u2028 \u2029(也局限于两端)
翻译过来分别是:水平制表符,换行符,垂直制表符,换页符,回车,后面的这几个除了问号外,其他的都是转义符形式写法。
注:它并没有改变源字符串 除非你在赋值给它。

trim方法一般用来去除空格,但是根据JDK API的说明,该方法并不仅仅是去除空格,它能够去除从编码’\u0000′ 至 ‘\u0020’ 的所有字符。 至于说到底还能去除啥感兴趣的自行百度,入门阶段不整理那么细致,留给后面补充,知道的小伙伴欢迎留言。
参考网址:

String myStr = " Hello World ";
myStr.trim();
// myStr = myStr.trim(); 注掉 i1为0   打开为  5
int i1 = myStr.indexOf(" ");//0  因为 myStr.trim();  没有重新赋值给mystr


//  \v   \u2028  \u2029  \x0085  \x00a0  ? 好像去不掉  目前只验证了后5种成立
System.out.println("   admin  fd g  fg \u2029 ".trim());//admin  fd g  fg System.out.println("   admin  fd g  fg \u2028 ".trim());//admin  fd g  fg System.out.println("   admin  fd g  fg \f ".trim());//admin  fd g  fg 这个是没空格的
System.out.println("   admin  fd g  fg \r ".trim());//admin  fd g  fg 这个是没空格的
System.out.println("   admin  fd g  fg \t ".trim());//admin  fd g  fg 这个是没空格的
System.out.println("   admin  fd g  fg \n ".trim());//admin  fd g  fg 这个是没空格的
System.out.println("   admin  fd g  fg \r\n ".trim());//admin  fd g  fg 这个是没空格的
        System.out.println("".trim());//空字符
        System.out.println(" ".trim());//空字符
        System.out.println("  ".trim());//空字符
        System.out.println("  ".trim().equals(""));//true
        System.out.println("  ".trim()=="");//false
        System.out.println(""=="");//true
        System.out.println(null==null);//true

Java去除空格的几种方法

注意:有时候因为某些原因,你拿到的字段有空格需要去除,但是怎么也去不掉,它可能不是一个常规空格,我有一次就遇到了,他是&nbsp;形成的空格。 用 "\s*"解决

介绍了5种java中去除空格的方法,分别是String.trim()、str.replace(" “, “”);、replaceAll(” +“,”");以及自定义的remove函数,非常的简单实用。

1. String.trim()

trim()是去掉首尾空格

2.str.replace(" ", ""); 去掉所有空格,包括首尾、中间

String str = " hell o ";
String str2 = str.replaceAll(" ", "");
System.out.println(str2);

3.或者replaceAll(" +",""); 去掉所有空格

4.str = .replaceAll("\s*", "");
可以替换大部分空白字符, 不限于空格
s 可以匹配空格、制表符、换页符等空白字符的其中任意一个

5.或者下面的代码也可以去掉所有空格,包括首尾、中间
public String remove(String resource,char ch)
  {
    StringBuffer buffer=new StringBuffer();
    int position=0;
    char currentChar;

    while(position<resource.length())
    {
      currentChar=resource.charAt(position++);
      if(currentChar!=ch) buffer.append(currentChar); } return buffer.toString();
  }


\s 不支持全角,
\s匹配任何空白字符,包括空格、制表符、换页符等等;中文全角空格
\s 并不能匹配中文全角空格。
\s 只能匹配下面六种字符(半角空格( )、水平制表符(\t)、竖直制表符、回车(\r)、换行(\n)、换页符(\f)

正则匹配0个或多个空格,我是这样写的 \\s*
正则匹配一个或多个空格,我是这样写的 \\s+
如何匹配全角空格,正则可以这么写:"[\\s\\p{Zs}]+" , 注意java代码中的转义。

半角空格:“ ”. Unicode编码为:\u0020 可以通过正则表达式中的\s进行匹配
全角空格:“ ” Unicode编码为:\u3000 不能通过正则表达式中的\s进行匹配
不换行空格(连续空格)
Unicode编码为:\u00A0,主要用在office中。 不能通过正则表达式中的\s进行匹配
匹配这三种空格\s 改用 [\u3000|\u0020|\u00A0]

单独说下 \s及\S
\s表示匹配任意空格(包括空格,制表符,换页符)
\s :任何一个空白字符,等价于[\f\r\n\t\v],用来匹配退格字符 [\b] 是一个特例;
它不再类元字符 \s 中
\S 任何一个非空白字符,等价于[^\f\r\n\t\v]


请说,这些表达式有什么区别
x = x.replaceAll("\\s", "");
x = x.replaceAll("\\s+", "");
这两个调用总是会产生相同的结果x。但是,需要注意的是,这两个正则表达式并不相同
\\s  - 匹配单个空格字符  
\\s+  - 匹配一个或多个空白字符的序列。
在这种情况下,它没有什么区别,因为你用一个空字符串替换了所有的东西(尽管\\s+从效率的角度来看最好使用)。如果你用一个非空字符串替换,两者的行为会有所不同。

回答2:第一个匹配单个空白,而第二个匹配一个或多个空白空间。它们是所谓的正则表达式量词.


	    String s1 = "     ";// 5个空格
        String a = s1.replaceAll("\\s", "");//空字符
        String b = s1.replaceAll("\\s+", "");//空字符
        System.out.println(a==b);//false
        System.out.println(a.equals(b));//true
        String a1 = s1.replaceAll("\\s", "a");//aaaaa
        String b1 = s1.replaceAll("\\s+", "a");//a

在这里插入图片描述

static String valueOf(primitive data type x) 返回传递的数据类型参数的字符串表示形式。

valueOf() 方法有以下几种不同形式:

 valueOf(boolean b): 返回 boolean 参数的字符串表示形式。.
 valueOf(char c): 返回 char 参数的字符串表示形式。
 valueOf(char[] data): 返回 char 数组参数的字符串表示形式。
 valueOf(char[] data, int offset, int count): 返回 char 数组参数的特定子数组的字符串表示形式。
 valueOf(double d): 返回 double 参数的字符串表示形式。
 valueOf(float f): 返回 float 参数的字符串表示形式。
 valueOf(int i): 返回 int 参数的字符串表示形式。
 valueOf(long l): 返回 long 参数的字符串表示形式。
 valueOf(Object obj): 返回 Object 参数的字符串表示形式。 
 即:将 obj 对象转换成 字符串, 等于 obj.toString() 
        double d = 1100.00d;
        float f = 110.00f;
        boolean b = true;
        long l = 1234567890L;
        char[] arr = {'h', 'e', 'l', 'l', 'o' };
        System.out.println(String.valueOf(d) );//1100.0
        System.out.println(String.valueOf(f) );//110.0
        System.out.println(String.valueOf(b) );//true
        System.out.println(String.valueOf(l) );//1234567890
        System.out.println(String.valueOf(arr,1,3) );//ell
        System.out.println(1100d);//1100.0
        System.out.println(1100.0d);//1100.0
        System.out.println(1100.01d);//1100.01

顺带普及一下 由 String 转换成 数字的基本数据型态
使用基本数据型态的包装类别 的parse
这一类的方法如果无法将 s 分析 则会丢出 NumberFormatException

要将 String 转换成基本数据型态转 ,大多需要使用基本数据型态的包装类别 
比如说 String 转换成 byte ,可以使用 Byte.parseByte(String s) ,
这一类的方法如果无法将 s 分析 则会丢出 NumberFormatException1byte : Byte.parseByte(String s) : 将 s 转换成 byte2Byte.parseByte(String s, int radix) : 以 radix 为基底 将 s 转换为 byte ,比如说 Byte.parseByte("11", 16) 会得到 173double : Double.parseDouble(String s) : 将 s 转换成 double4float : Double.parseFloat(String s) : 将 s 转换成 float5int : Integer.parseInt(String s) : 将 s 转换成 int6long : Long.parseLong(String s)

在补充点Byte.parseByte(String s, int radix):以 radix 为基底 将 s 转换为 byte

         //Byte.parseByte(String s, int radix) : 以 radix 为基底 将 s 转换为 byte
        //int radix 是指的基数 ,就是指的进制基数  范围 [2-36]
        System.out.println( Byte.parseByte("11", 16));//17
        //如果你给的string 不能转换,或者基数小于2或大于36 会抛出异常 点开源码可以看到这,自己去看
        //System.out.println(Byte.parseByte("12", 2));//12不能转化报错
        //表示 字符串11以2为基数表示为10进制的byte值是 3 ,这里的11表示的是一个2进制数
        System.out.println(Byte.parseByte("11", 2));//3
        //表示 字符串11以3为基数表示为10进制的byte值是 4 ,这里的11表示的是一个3进制数
        System.out.println(Byte.parseByte("11", 3));//4
        System.out.println(Byte.parseByte("12"));//12

        Integer x =Integer.valueOf(1);//1
        Double c = Double.valueOf(4);//4.o
        Float a = Float.valueOf("80");//80.0

        Integer b = Integer.valueOf("1024",16);//4132   // 使用 16 进制

比如说 String 转换成 byte ,可以使用 Byte.parseByte(String s) 这块有踩坑点

        //把一个16进制的String转成byte   踩坑记录
        //想把 "9D" 转成 byte, 使用下面方法:java.lang.NumberFormatException Value out of range. Value:"9D" Radix:16
        //说值的范围越界了: 查看源码,byte 的范围是 -128~127,如果把 9D 当成正数来转换,结果是 157,当然越界了。
//        byte v = Byte.parseByte("9D", 16);
        //所以有这样两个处理办法
        byte v = (byte) Integer.parseInt("9D", 16);//-99
        byte v1 = Integer.valueOf("9D", 16).byteValue();//-99

public boolean isEmpty(): 判断字符串的内容是否为空

判断字符串length()长度是否==0来判断是否为空
字符串通过length()方法计算字符串长度,如果返回 0,即为空字符串

    @Override
    public boolean isEmpty() {
        return value.length == 0;
    }
        System.out.println("Runoob".isEmpty()); //false
        System.out.println("".isEmpty());       //true
        System.out.println("      ".isEmpty()); //false
        System.out.println(" ".isEmpty()); //false
        String a = null;
//      System.out.println(a.isEmpty()); //java.lang.NullPointerException

isBlank()与isEmpty()
两种方法都用于检查Java中的空白或空字符串。两种方法之间的区别在于,当且仅当字符串长度为0时, isEmpty()方法返回 true
isBlank()方法仅检查非空白字符。它不检查字符串长度。

String.isBlank()方法确定给定的字符串是空白还是空或仅包含空格。

注意 java 8版本不存在此方法, isBlank()方法已添加到 Java 11 中。

       
        // String.isBlank()方法确定给定的字符串是空白还是空或仅包含空格。 isBlank()方法已添加到 Java 11 中。
        //如果给定的字符串为空或仅包含空格代码点,则此方法返回 true ,否则返回 false 。
        System.out.println( "ABC".isBlank() );			//false
        System.out.println( " ABC ".isBlank() );		//false
        System.out.println( "  ".isBlank() );			//true
        System.out.println( "".isBlank() );				//true

public int offsetByCodePoints(int index , int codePointOffset)

返回此 String 中从给定的 index 处偏移 codePointOffset 个代码点的索引。
第一位参数取值范围[0-str.length()] ,
第二位参数取值范围 [-str.length(),str.length()]
两参数和范围:[0-str.length()]
不满足上述三条件java.lang.IndexOutOfBoundsException


        System.out.println("hello".offsetByCodePoints(0, 3));//3
        System.out.println("hello".offsetByCodePoints(0, 5));//5
        System.out.println("hello".offsetByCodePoints(2, 3));//5
        System.out.println("hello".offsetByCodePoints(1, 4));//5
        System.out.println("hello".offsetByCodePoints(2, 3));//5
        System.out.println("hello".offsetByCodePoints(3, -3));//0
        System.out.println("hello".offsetByCodePoints(5, -5));//0
      

public int codePointAt(int index)

返回指定索引处的字符(Unicode 代码点)。索引引用 char 值(Unicode 代码单元),其范围从 0 到 length() - 1。

        System.out.println("hello".codePointAt(4));//111
        System.out.println("hello".charAt(4));//o
        System.out.println((int)"hello".charAt(4));//111

String类的charAt方法和codePointAt方法区别

区别

提供以下两个方法索引字符串中单个字符:
char charAt(int index) 返回指定索引位置的char值。 索引范围为0~length()-1。
int codePointAt(int index) 返回指定索引位置的Unicode值 。 索引范围为0~length()-1。

System.out.println("hello".codePointAt(4));//111
System.out.println("hello".charAt(4));//o
        
String s = "\uD835\uDD6B"; // 该字符串只有一个特殊字符?,使用其utf-16值描述该字符
System.out.println(s);
System.out.println(s.length());//2
System.out.println(s.codePointCount(0,s.length()));//1
int cp=s.codePointAt(0);//120171
System.out.println(Integer.toHexString(cp));//1d56b
int v1=s.charAt(0);//55349
System.out.println(Integer.toHexString(v1));//d835
int v2=s.charAt(1);//56683
System.out.println(Integer.toHexString(v2));//0xdd6b
//以看到只有一个特殊字符的字符串s的length()返回值为2,codePointCount返回值为1,
// 通过codePointAt()方法过去了该字符对应码点,两次调用charAt()方法返回了该字符所有char 数据

Java codePoint()方法及.chars()方法

该codePoint()方法用于显示给定序列中的代码点值流。
chars()是Java 8中的一个int流


        IntStream intStream = "我爱你中国aa".codePoints();
        "我爱你中国aa".codePoints().forEach( i -> System.out.println((char)i));
        intStream.forEach( System.out::println);
        int[] ints = "我爱你中国aa".codePoints().toArray();
        //[25105, 29233, 20320, 20013, 22269, 97, 97]
        System.out.println(Arrays.toString("我爱你中国aa".codePoints().toArray()));


        "我爱你中国aa".chars().forEach(i -> System.out.println((char)i));
        IntStream intStream1 = "我爱你中国aa".chars();
        intStream1.forEach( System.out::println);
        //[25105, 29233, 20320, 20013, 22269, 97, 97]
        System.out.println(Arrays.toString("我爱你中国aa".chars().toArray()));

public String indent(int n) 它以整数n作为输入并相应地进行缩进。

JDK 12在Java.lang.String类中引入了indent()方法。此方法对于从行的开头添加或删除空格以调整每个字符串行的缩进很有用。

indent()方法是12版本引入的这里不在详讲自行百度

Java 11 – String.lines()介绍

Java 11 – String.lines()介绍
它返回从给定多行字符串中提取的行流,并用行终止符分隔。

Java 11 – String.repeat()介绍

Java 11 – String.repeat()介绍
此方法返回一个字符串,该字符串的值是给定字符串的重复 count 次的串联。如果字符串为空或 count 为零,则返回空字符串。

String类的strip(), stripLeading()和 stripTrailing()方法

String strip()    – 返回一个字符串,其值指定为字符串,并且所有左右空格都已删除。
String stripLeading()  – 返回其值为字符串的字符串,其中所有左空白都已删除。
String stripTrailing()   – 返回其值为字符串的字符串,并删除所有右空白。

Java 11 – String.strip()介绍
String类的strip(), stripLeading()和 stripTrailing()方法来删除不需要的空格来自 Java 11 中的给定字符串。

Java String stripLeading()
stripLeading()方法用于从字符串中去除前导空格,即stripLeading()方法仅在字符串的开头删除所有空格。
Java String stripTrailing()用法及代码示例
此方法用于从字符串中去除尾随空格,即stripTrailing()方法仅在字符串末尾删除所有空格。

StringBuilder&StringBuffer

https://blog.csdn.net/zhangxuelong461/article/details/103730135

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值