一,String字符串
1.1,String字符串是引用类型,且不可变
String str1 = "Hello";
String str2 = str1.concat(" World"); // 使用concat方法连接字符串,返回一个新的字符串对象
System.out.println(str1); // 输出:Hello,原始字符串对象并未改变
System.out.println(str2); // 输出:Hello World,新的字符串对象被创建并赋给str2
str1="test";
System.out.println(str1);//输出test
也就是说,String字符串并不会被修改,只是会重新找一个内存来存储,相当于新建一个引用类型的数据.
1.2,字符串的比较必须使用equals()方法而不能用
String str1 = "Hello";
String str2 = "world";
String str3 = "world";
System.out.println(str1==str2); // 输出:false
System.out.println(str2==str3); // 输出:true,//Java编译器在编译期,会自动把所有相同的字符串当作一个对象放入常量池,自然s1和s2的引用就是相同的。
System.out.println(str1.equals(str2)); // 输出:false
1.3,字符串的其他常用方法
// 是否包含子串:
"Hello".contains("ll"); // true
//其他搜索字串
"Hello".indexOf("l"); // 2
"Hello".lastIndexOf("l"); // 3
"Hello".startsWith("He"); // true
"Hello".endsWith("lo"); // true
//提取字串
"Hello".substring(2); // "llo"
"Hello".substring(2, 4); //"ll"
//去除首尾空格
" \tHello\r\n ".trim(); // "Hello"
//字符串判空
"".isEmpty(); // true,因为字符串长度为0
" ".isEmpty(); // false,因为字符串长度不为0
" \n".isBlank(); // true,因为只包含空白字符
" Hello ".isBlank(); // false,因为包含非空白字符
//替换字符replace或者正则表达式
String s = "hello";
s.replace('l', 'w'); // "hewwo",所有字符'l'被替换为'w'
s.replace("ll", "~~"); // "he~~o",所有子串"ll"被替换为"~~"
//分割字符串
String s = "A,B,C,D";
String[] ss = s.split("\\,"); // {"A", "B", "C", "D"}
//拼接字符串
String[] arr = {"A", "B", "C"};
String s = String.join("***", arr); // "A***B***C"
//其他类型转化为字符串:String.valueOf
String.valueOf(123); // "123"
String.valueOf(45.67); // "45.67"
String.valueOf(true); // "true"
//char []和String本质上同个东西,可以相互转化
char[] cs = "Hello".toCharArray(); // String -> char[]
String s = new String(cs); // char[] -> String
1.4,StringBuilder类
在在上文中,我们说过STring对象不可修改,而是不断新分配内存给它,那字符串操作频繁了,每次都会创建新的字符串对象,然后扔掉旧的字符串。这样,绝大部分字符串都是临时对象,不但浪费内存,还会影响GC效率。
于是,java标准库提供了StringBuilder,它是一个可变对象,可以预分配缓冲区,这样,往StringBuilder中新增字符时,不会创建新的临时对象,而且它还支持链式操作:
StringBuilder sb = new StringBuilder(1024);
sb.append("Mr ")
.append("Bob")
.append("!")
.insert(0, "Hello, ");
System.out.println(sb.toString());
1.5,StringJoiner拼接数组
分隔符拼接数组的需求很常见,所以Java标准库还提供了一个StringJoiner:
String[] names = {"Bob", "Alice", "Grace"};
StringJoiner sj = new StringJoiner(", ");
for (String name : names) {
sj.add(name);
}
System.out.println(sj.toString());//Bob, Alice, Grace
二,包装类
我们已经知道,Java的数据类型分两种:
基本类型:byte,short,int,long,boolean,float,double,char
引用类型:所有class和interface类型
引用类型可以赋值为null,表示空,但基本类型不能赋值为null,为了实现把int基本类型变成一个引用类型,我们可以定义一个Integer类,它只包含一个实例字段int,这样,Integer类就可以视为int的包装类(Wrapper Class):
public class Integer {
private int value;
public Integer(int value) {
this.value = value;
}
public int intValue() {
return this.value;
}
public static Integer valueOf(int intValue){
Integer instance=new Integer(intValue);
return instance;
}
}
实际上,因为包装类型非常有用,Java核心库为每种基本类型都提供了对应的包装类型:
我们可以直接使用,并不需要自己去定义,对于包装类型,使用的方式如下:
//创建使用Integer.valueOf方法
Integer n2 = Integer.valueOf(100);
//访问使用该实例的intValue()方法
System.out.println(n2.intValue());
因为int和Integer可以相互转化,所以可以利用这一点让编译器自动拆箱:
Integer n = 100; // 编译器自动使用Integer.valueOf(int)
int x = n; // 编译器自动使用Integer.intValue()
但是因为包装类型是引用类型,所以需要使用equals()进行比较:a.equals(b)
三,枚举类
枚举类的定义使用关键字enum来进行:
enum Weekday {
SUN, MON, TUE, WED, THU, FRI, SAT;
}
定义的enum实际上就是一个class类.
因为enum是一个class,每个枚举的值都是class实例,因此,这些实例有一些方法:
//name()方法返回常量名
String s = Weekday.SUN.name(); // "SUN"
//ordinal()方法返回索引值
int n = Weekday.MON.ordinal(); // 1
枚举类的实例,还可以定义一些属性值:
enum Weekday {
MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");
public final int dayValue;
private final String chinese;
private Weekday(int dayValue, String chinese) {
this.dayValue = dayValue;
this.chinese = chinese;
}
@Override
public String toString() {
return this.chinese;
}
}
枚举通常会和switch一起使用:
public class HelloWorld {
public static void main (String[] args){
Weekday day = Weekday.SUN;
switch(day.dayValue) {
case 1:
case 2:
case 3:
case 4:
case 5:
System.out.println("Today is " + day + ". Work at office!");
break;
case 6:
case 0:
System.out.println("Today is " + day + ". Work at home!");
break;
default:
throw new RuntimeException("cannot process " + day);
}
}
}
enum Weekday {
MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");
public final int dayValue;
private final String chinese;
private Weekday(int dayValue, String chinese) {
this.dayValue = dayValue;
this.chinese = chinese;
}
//覆写toString,定义枚举类的实例值返回内容
@Override
public String toString() {
return this.chinese;
}
}
四,记录类record
我们平时非常常用的一种类,在我们想要定一个类的时候,肯定是先定义需要的属性和获取该值的方法,每次都写就很麻烦,于是我们就想把它简化掉,让编辑器自动帮我们写,于是就有了记录类:使用record方法进行修饰.
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() {
return this.x;
}
public int y() {
return this.y;
}
}
等价于:
record Point(int x, int y) {}
过使用record类,可以更加简洁地定义数据传输对象,并且省去了编写大量重复代码的工作。
五,大数类
BigInteger类,java.math.BigInteger就是用来表示任意大小的整数。BigInteger内部用一个int[]数组来模拟一个非常大的整数:
对BigInteger做运算的时候,只能使用实例方法,例如,加法运算:
BigInteger i1 = new BigInteger("1234567890");
BigInteger i2 = new BigInteger("12345678901234567890");
BigInteger sum = i1.add(i2); // 12345678902469135780
那要是浮点数呢?我们可以使用BigDecimal表示一个任意大小且精度完全准确的浮点数。
BigDecimal bd = new BigDecimal("123.4567");
System.out.println(bd.multiply(bd)); // 15241.55677489
六,Math类
提供了一些数学的计算方法.
//绝对值
Math.abs(-100); // 100
//求最大或者最小
Math.max(100, 99); // 100
Math.min(1.2, 2.3); // 1.2
//求x的y次方
Math.pow(2, 10); // 2的10次方=1024
//求根号
Math.sqrt(2); // 1.414...
//求e的x次方
Math.exp(2); // 7.389...
//三角函数
Math.sin(3.14); // 0.00159...
Math.cos(3.14); // -0.9999...
Math.tan(3.14); // -0.0015...
Math.asin(1.0); // 1.57079...
Math.acos(1.0); // 0.0
//几个常量
double pi = Math.PI; // 3.14159...
double e = Math.E; // 2.7182818...
Math.sin(Math.PI / 6); // sin(π/6) = 0.5