1.对象数组的排序和查找
java中核心类库中排序一般用两种Comparable和Compare to
package com.atguigu.java;
import java.util.Arrays;
public class SortTest {
public static void main(String[] args) {
Person[] ps = new Person[4];
ps[0] = new Person(1,"a",20);
ps[1] = new Person(3,"c",18);
ps[2] = new Person(2,"b",21);
ps[3] = new Person(4,"d",22);
Arrays.sort(ps);//通过调用对象的compareTo方法进行的排序
for (int i = 0; i < ps.length; i++) {
System.out.println(ps[i]);//调用的是对象的toString方法
}
//注意:不是通过对象的地址值 通过属性的内容。
int i = Arrays.binarySearch(ps, new Person(2,"b",21));
System.out.println(i);
}
}
class Person implements Comparable{
public int id;
public String name;
public int age;
public Person(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return id + " " + name + " " + age;
}
@Override
public int compareTo(Object o) {
//校验:
Person p = (Person) o;
return this.age - p.age;
}
}
2.String的概述
1.为了节省内存 String 底层的Char类型数组中文2Btye 字母1Btye 而在混合时均为2Btye
2.String在内存区域内存在一个字符串常量池 其内常量不可改变
import org.junit.Test;
/*
String :
说明:
1.String被final所修饰那么String这个类不能被其它类继承
2.String实现了Comparable接口 那么可以比较字符串内容。
3.String的底层是一个char类型的数组(JDK9开始变成了byte[]--原因是为了节省内存)
JDK9之前 JDK9开始
char[] 编译UTF-16 byte[](编译 latin1 - UTF-16)
a -> char a - 1个byte
中 -> char 中 - 2个byte
a中 -> 2个char a中 - 4个byte
4.String是一个不可变的字符序列
①String不能被子类继承--那么就没有了子类可以对父类的操作
②char[]是被final修饰 - char[]的对象(字符串)不能被修改 -- 只看到这还无法保证数组的内容被修改
③char[]是被private修饰 - 类的名部不能操作该数组同时类的内部不提供对数组内容本身修改的方法
5.为什么String要设置成不可变呢? 因为不可变才能被共享,因为共享才能节省内存。
因为字符串在内存存储的区域是一个比较特殊的区域 - 字符串常量池(相同的对象只能有一份)
*/
public class StringTest {
/*
创建字符串对象
*/
@Test
public void test(){
//方式一
String s = new String("abc");
//方式二
String s2 = "abc";
}
/*
创建String对象两种方式的区别
*/
@Test
public void test2(){
String s3 = "abc";
String s4 = "abc";
String s = new String("abc");
String s2 = new String("abc");
System.out.println(s == s2);//false
System.out.println(s3 == s4);//true
}
/*
案例二
*/
@Test
public void test3(){
String s = "a";
String s2 = s;
s = "b"; //把一个新的对象赋值给了s
System.out.println(s == s2);//false
}
/*
案例三
*/
@Test
public void test4(){
String s = "abcd";
//将字符串中的字符a被A替换 - 字符串是一个不可变的字符序列 原来的字符串并没有修改而是创建了一个新的
String s2 = s.replace('a', 'A');
System.out.println("s:" + s);//abcd
System.out.println("s2:" + s2);//Abcd
System.out.println(s2 == s); //false
}
/*
案例四
*/
@Test
public void test5(){
String str = new String("world");
char[] ch = new char[]{'h','e','l','l','o'};
change(str,ch);
System.out.println(str);//world
System.out.println(String.valueOf(ch));//abcde
}
public void change(String str, char[] arr){
str = "change";
arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';
arr[3] = 'd';
arr[4] = 'e';
}
}
import org.junit.Test;
public class StringTest2 {
@Test
public void test(){
char[] c = {'a','b','c'};
String s = new String(c); // 字符串常量池中有没有abc? 没有
System.out.println(s);
}
}
ackage com.atguigu.java;
public class StringTest3 {
/*
[面试题] String s = "a" + "b" + "c" 创建了几个对象 ? 1个-字符串常量池
[面试题] String s = new String("abc") 创建了几个对象 ?
如果字符串常量池中没有abc 那么会创建2个对象 1个在字符串常量池 1个在堆中
如果字符串常量池中已经存在abc 那么会创建1个对象在堆中
*/
public static void main(String[] args) {
String s = "hello";
String s2 = "hel" + "lo"; //编译的时候就是 "hello"
String s3 = "hel";
String s4 = "lo";
/*
总结:只要有变量参与字符串拼接就会用StringBuilder中的toString方法在该方法中new String 并返回
*/
String s5 = "hel" + s4;//有变量参与字符串拼接 -- 底层调用StringBuilder中的toString方法在该方法中new String 并返回
String s6 = s3 + "lo";//有变量参与字符串拼接 -- 底层调用StringBuilder中的toString方法在该方法中new String 并返回
String s7 = s3 + s4;//有变量参与字符串拼接-- 底层调用StringBuilder中的toString方法在该方法中new String 并返回
/*
intern() : 调用该方法时会直接去字符串常量池中寻找有没有该内容。如果有直接返回。
如果没有往字符串常量池中放一份并返回。
注意:返回值是从字符串常量池中寻找后返回的结果。
*/
String s8 = (s3 + s4).intern(); //优化 - 节省了内存(从字符串常量池中获取的)
System.out.println(s == s2); //true
System.out.println(s == s5); //false
System.out.println(s2 == s6); //false
System.out.println(s == s7); //false
System.out.println(s5 == s6);//false
System.out.println(s2 == s7);//false
System.out.println(s == s8);//true
}
}
String新建对象时字符串常量池中没有就新建
有则使用常量池中对象
3.Sting的构造器
import org.junit.Test;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
public class StringAPI01 {
/*
构造器
* `public String() ` :初始化新创建的 String对象,以使其表示空字符序列。
* ` String(String original)`: 初始化一个新创建的 `String` 对象,使其表示一个与参数相同的字符序列;
换句话说,新创建的字符串是该参数字符串的副本。
* `public String(char[] value) :通过当前参数中的字符数组来构造新的String。
* `public String(char[] value,int offset, int count) :通过字符数组的一部分来构造新的String。
* `public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。
* `public String(byte[] bytes,String charsetName) :通过使用指定的字符集解码当前参数中的字节数组来构造新的String。
*/
@Test
public void test() throws UnsupportedEncodingException {
String s = new String(); //相当于 ""
System.out.println("a" + s + "b");
String s2 = new String("longge");
System.out.println("======================================");
char[] c = {'a','b','c','d','e'};
String s3 = new String(c);
System.out.println(s3);
//public String(char[] value,int offset, int count) :通过字符数组的一部分来构造新的String。
String s4 = new String(c, 2, 2);// 第一个2是索引位置 第二个2是长度
System.out.println(s4);
System.out.println("======================================");
/*
public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。
*/
byte[] b = {97,98,99}; //整数
String s5 = new String(b);
System.out.println(s5);
System.out.println("======================================");
/*
public String(byte[] bytes,String charsetName) :通过使用指定的字符集解码当前参数中的字节数组来构造新的String。
*/
byte[] b2 = {97,98,99}; //整数
String s6 = new String(b,"utf-8");
System.out.println(s6);
//将字符串转成byte[]
byte[] bytes = "小鬼子".getBytes("gbk"); //[-48, -95, -71, -19, -41, -45]
System.out.println(Arrays.toString(bytes));
bytes = "小鬼子".getBytes("utf-8");
System.out.println(Arrays.toString(bytes)); //[-27, -80, -113, -23, -84, -68, -27, -83, -112]
String ss2 = new String(bytes, "gbk");//因为bytes中放的是UTF-8的编码集的内容 然后非得转成gbk编码 肯定乱码
System.out.println(ss2);
}
}
4.字符串拼接
在常量池中的字符串:
1.双引号中
2.intern方法:需要返回值接收 否则就是常量池中寻找并且(没有就添加)返回
import org.junit.Test;
public class StringTest4 {
/*
什么样的字符串在常量池中?
1.双引号中
2.调用了intern方法
*/
@Test
public void test(){
String s1 = "hel";
String s2 = "lo";
String s3 = s1 + s2;
/*
intern() : 调用该方法时会直接去字符串常量池中寻找有没有该内容。如果有直接返回。
如果没有往字符串常量池中放一份并返回。
注意:返回值是从字符串常量池中寻找后返回的结果。
*/
s3.intern();
String s4 = "hello";
System.out.println(s3 == s4);//true
//System.out.println(result == s4);
}
@Test
public void test2(){
String s1 = "hel";
String s2 = "lo";
String s3 = s1 + s2;
String s4 = "hello";
/*
intern() : 调用该方法时会直接去字符串常量池中寻找有没有该内容。如果有直接返回。
如果没有往字符串常量池中放一份并返回。
注意:返回值是从字符串常量池中寻找后返回的结果。
*/
s3.intern(); //因为常量池中已经有hello了所以s3是不会再放到常量池中的
System.out.println(s3 == s4);//false
}
}
5.String的API
拼接 +
比较 equals 从第一个字母开始比较 同则后推
忽视大小写 equalsIgnoreCase
比较内容 CompareTo
同样也可忽视大小写CompareToIgnoreCase
Loca。China 转中文拼音
import org.junit.Test;
import java.text.Collator;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Locale;
public class StringAPITest {
/*
* static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String
* static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String
* static String valueOf(char[] data) : 返回指定数组中表示该字符序列的 String
* static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String
* static String valueOf(xx value):xx支持各种数据类型,返回各种数据类型的value参数的字符串表示形式。
*/
@Test
public void test(){
char[] cs = {'a','b','c','d','e','f'};
String s = String.copyValueOf(cs);
System.out.println(s);
String s2 = String.copyValueOf(cs, 1, 2);
System.out.println(s2);
//基本数据类型 -> 字符串
String s3 = String.valueOf(11);
}
/*
字符串拼接
*/
@Test
public void test2(){
String s = "a".concat("b");//底层new String
String s2 = "a" + "b";
//字符串比较
boolean bo = "abc".equals("abd");//比较字符串的内容(比较每一个字符)
}
@Test
public void test3(){
System.out.println("abc".equals("AbC"));//false
//比较内容 -忽略大小写
System.out.println("abc".equalsIgnoreCase("ABC"));//true
System.out.println("abc".compareTo("bde"));//比较内容 - 可以用来排序
System.out.println("===================================================");
System.out.println("a".compareTo("A"));
System.out.println("a".compareToIgnoreCase("A"));//比较内容时忽略大小写
}
@Test
public void test4(){
String[] names = {"aa","cc","bb","dd"};
Arrays.sort(names);
System.out.println(Arrays.toString(names));
System.out.println("======================================");
String[] names2 = {"宝宝","弟弟","姐姐","哥哥"};
Arrays.sort(names2, new Comparator<String>() {//我们传一个Comparator接口的实现类的对象目的是自己定义排序规则
@Override
public int compare(String o1, String o2) {
Collator collator = Collator.getInstance(Locale.CHINA);
return collator.compare(o1,o2);//该方法中做了两件事①将文字转换成拼音 ②对拼音进行比较
}
});
System.out.println(Arrays.toString(names2));
}
}
空串与null
import org.junit.Test;
public class StringAPITest2 {
/*
空字符串
*/
@Test
public void test(){
String s = "";
String s2 = null;
String s3 = new String();//空串 - “”
//isEmpty() : 字符串的内容是否为空
System.out.println(s.isEmpty());
System.out.println(s3.isEmpty());
//System.out.println(s2.isEmpty());//NullPointerException
}
@Test
public void test2(){
char[] cs = {}; //char[] cs = new char[0];
//空串
String s = new String(cs);
stringCheck(null);
}
public void stringCheck(String str){
//如果是空串或null就不处理了
if (str == null || str.isEmpty()){
System.out.println("不需要处理");
}
/*
下面的写法不对 如果传的是一个null 就会发生空指针异常
if (str.isEmpty() || str == null ){
System.out.println("不需要处理");
}
*/
}
/*
一个变量和一个双引号引起来的字符串进行内容比较
最好是双引号引起来字符串在前面 调用equals方法 为了避免空指针异常
*/
@Test
public void test3(){
String s = null;
//System.out.println(s.equals("aaa")); // 如果s为null直接就空指针异常了
System.out.println("aaa".equals(s));//这个好 s为null也不会发生空指针异常
}
@Test
public void test4(){
String s = "a";
String s2 = "b";
String s3 = s + s2;
}
}
长度 int length
String toLowerCase 转字符串中字母为小写
String toUpperCase转字符串中字母为大写
boolean startsWith(xx) 是否以xx开头
boolean endsWith(xx) 是否以xx结尾
String trim() 去掉字符串前后空白行
boolean contains(xx)是否包含xx
int indexOf(xx)从前往后在字符串中找xx 返回第一次下标没有返回-1
int lastIndexOf(xx)从后往前在字符串中找xx返回最后一次下标没有返回-1
String substring(int beginIndex)返回新字符串
String substring(int beginIndex, int endIndex) :返回一个新字符串,
它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
char charAt(index):返回[index]位置的字符
char[] toCharArray(): 将此字符串转换为一个新的字符数组返回
将字符数组转为String对象,可以使用之前介绍过的构造器和静态方法valueOf或copyValueOf等
import org.junit.Test;
import java.util.Arrays;
public class StringAPITest3 {
/*
int length():返回字符串的长度
String toLowerCase():将字符串中大写字母转为小写
String toUpperCase():将字符串中小写字母转为大写
*/
@Test
public void test(){
System.out.println("abc".length());
System.out.println("abCDEf".toLowerCase());
System.out.println("abCDEf".toUpperCase());
}
/*
(4)boolean startsWith(xx):是否以xx开头
(5)boolean endsWith(xx):是否以xx结尾
(6)String trim():去掉字符串前后空白符
(7)boolean contains(xx):是否包含xx
(8)int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1
(9)int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1
*/
@Test
public void test2(){
System.out.println("abcdef".startsWith("acbc"));
System.out.println("如何让龙哥挣1个亿.txt".endsWith(".txt"));
System.out.println(" a b ".trim());
System.out.println("abclonggeaaaheihei".contains("longge"));
System.out.println("=====================");
System.out.println("ffabcddabceeabc".indexOf("abc"));
System.out.println("ffabcddabceeabc".lastIndexOf("abc"));
}
/*
(10)String substring(int beginIndex) :返回一个新的字符串,
它是此字符串的从beginIndex开始截取到最后的一个子字符串。
(11)String substring(int beginIndex, int endIndex) :返回一个新字符串,
它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
(12)char charAt(index):返回[index]位置的字符
(13)char[] toCharArray(): 将此字符串转换为一个新的字符数组返回
将字符数组转为String对象,可以使用之前介绍过的构造器和静态方法valueOf或copyValueOf等
*/
@Test
public void test3(){
System.out.println("abclongge".substring(3));
System.out.println("abclongge".substring(3,8));
String s = "abcde";
for (int i = 0; i < s.length(); i++) {
System.out.println(s.charAt(i));
}
System.out.println("===================================");
char[] charArray = s.toCharArray();
System.out.println(Arrays.toString(charArray));
}
}