Java核心类笔记(字符串方法、StringBuilder(Joiner)、包装、JavaBean、枚举、Math、随机数)

String字符串注意点和常用方法

怎样理解字符串的不可变性?

在Java中,String是通过private final char[]实现的,没有任何修改char[]的方法,所以是不可变的。

在字符串操作中,其实是复制了一份新的字符串,然后再进行操作,返回的是新的字符串,不是在原有的字符串上进行操作。

如果想要改变的话,可以用char[] cs = "hello".toCharArray()把字符串转换成字符型数组,然后改变字符型数组。

为什么字符串不能用==比较?

因为字符串默认是一种引用,如果直接使用==就相当于是在比较两个字符串的地址,必须使用equal()方法,才能比较字符串的内容。

String s1 = "hello";
String s2 = "hello";
System.out.println(s1==s2);				// true
System.out.println(s1.equals(s2));		// true

例如在这段代码中,其实line3的本质上,java只分配了一个字符串,然后s1和s2都指向这个字符串,所以地址一样,第二个才是真正比较两个字符串的内容。

字符串常用的一些方法

method 方法说明 输入 输出
== 比较两个字符串地址 布尔值
s1.equals(s2) 比较两个字符串内容 布尔值
s1.equalsIngnoreCase(s2) 比较两个字符串内容,忽略大小写 布尔值
s1.contains(s2) 查找是否包含子串,类似于word里的find 子串字符串 布尔值
s1.substring(2,6) 截取子串,坐标是左闭右开 区间坐标[2,6) 截取的字符串
trim(s1) 修剪首尾的空白字符,包括tab,回车 新的字符串
strip(s1) 同上,还能移除一些特殊字符
(还可以单独去除头部或者尾部)
新的字符串
isempty(s1) 检查长度是否为0 布尔值
isblank(s1) 检查内容是否为空 布尔值
s1.split(",") 字符串分割 分隔符 多个字符串
String.join("***",arr) 使用分隔符***将字符串数组连接 字符串数组和连接符 一个新的字符串
S1.replace(“a”,“b”) 字符串替换,后面的替换前面 被替换和替换字符串 新的字符串
“%s%d”.formatted(“ming”,20) 将s1中的%s和%d用内容填充
String.format("%s%d",“ming”,20) 静态方法
String.valueOf() 将类型转换成字符串 各种类型 String
Integer.parseInt(“123”) 将类型转换成int 各种类型 int
Boolean.parseBoolean(“true”) 将字符串类型转换成布尔类型 String bool
char[] cs = “s1”.toCharArray() 将字符串转换成字符数组形式 String char[]
String c = new String(cs) 将字符串数组转换成字符串格式 char[] String
cs.clone() char[]的克隆,防止被改变 原始char[] 新的char[]

StringBuilder和StringJoiner有啥用?

StringBuilder是一个可变对象,在往里面增加字符的时候,不会一直复制创建新的对象,本质上一直在return this,所以可以进行链式操作,例如不断地使用append()方法。

public class Main {
    public static void main(String[] args) {
        String[] fields = { "name", "position", "salary" };
        String table = "employee";
        String select = buildSelectSql(table, fields);
        System.out.println(select);
        System.out.println("SELECT name, position, salary FROM employee".equals(select) ? "测试成功" : "测试失败");
    }
    static String buildSelectSql(String table, String[] fields) {
        // TODO:
        // 新建一个StringBuilder对象
    	var sb = new StringBuilder();
    	sb.append("SELECT ");
    	for (String field : fields)
    		sb.append(field + ", ");
        // 使用delete方法去掉多加的,和空格
    	sb.delete(sb.length()-2,sb.length());
    	sb.append(" FROM "+table);
        // 转换成字符串形式
        return sb.toString();
    }
}

最终输入效果为

SELECT name, position, salary FROM employee
测试成功

考虑到这种操作非常频繁,Java中还有一种更快的方式,即使用StringJoiner

在新建StringJoiner对象的时候,可以设置3个参数,连接符,首字符串,尾字符串。

import java.util.StringJoiner;

public class Main {
    public static void main(String[] args) {
        String[] fields = { "name", "position", "salary" };
        String table = "employee";
        String select = buildSelectSql(table, fields);
        System.out.println(select);
        System.out.println("SELECT name, position, salary FROM employee".equals(select) ? "测试成功" : "测试失败");
    }
    static String buildSelectSql(String table, String[] fields) {
        // TODO:
    	var sj = new StringJoiner(", ","SELECT "," FROM "+table);
    	for (String field : fields)
    		sj.add(field); 	
        return sj.toString();
    }
}

最终效果和上面一样,但是看起来更加简洁,需要注意的是,开头需要添加import java.util.StringJoiner语句,猜测StringJoiner是对StringBuilder的一种封装。

包装类型是什么意思?

Java的数据类型主要有两种:

  1. 基本类型,例如byte,boolean,char,int,long,float,double
  2. 引用类型,例如class,interface,即所有的类和接口。

如何把基本类型转换成引用类型呢?

利用包装,或者叫装箱(Auto Boxing),将基本类型装到类里面。

这个操作在Java中已经定义好了,直接调用即可。

反过来,把类还原成基本类型,又叫拆箱(Auto Unboxing)。

在创建例如Integer的时候,使用Integer.valueOf(100),这个非常类似于String.valueOf(),不要去新建,因为在使用.valueOf()时系统会自动调用缓存进行优化。

另外需要注意的是,由于包装生成的都是引用类型,所以必须使用equals()方法比较是否相等。

JavaBean快速生成读写代码

例如这样的一段代码,可以通过JavaBean快速生成读写代码

public class Person {
    private String name;
    private int age;
}

在项目文件夹中找到对应的class,然后选择source - generate getters and setters

Java核心类笔记(字符串方法、StringBuilder(Joiner)、包装、JavaBean、枚举、Math、随机数)_第1张图片

这样就能快速得到两个字段的读写方法。

public class Person {
    private String name;
    private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
}

使用Introspector.getBeanInfo()可以获取属性列表。

enum枚举类

enum枚举类本质上是一个public final类型的class,不能被继承,常量不能改变。

public final class Color extends Enum { // 继承自Enum,标记为final class
    // 每个实例均为全局唯一:
    public static final Color RED = new Color();
    public static final Color GREEN = new Color();
    public static final Color BLUE = new Color();
    // private构造方法,确保外部无法调用new操作符:
    private Color() {}
}

通过name()获取字符串,不是使用toString()

适合放在switch语句中。

Math和Random类

Math类有哪些方法?

常见的Math类有如下方法,类似于MATLAB或python的一些操作,Math不需要手动import

Math.abs(-100); // 100
Math.max(100, 99); // 100
Math.min(1.2, 2.3); // 1.2
Math.pow(2, 10); // 2的10次方=1024
Math.sqrt(2); // 1.414...
Math.exp(2); // 7.389...
Math.log(4); // e为底,1.386...
Math.log10(100); // 2
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
Math.random(); // 0.53907... 每次都不一样,在[0,1)之间

可以结合random()和max,min来生成区间范围内的随机数。

StrictMath也可以提供和Math一模一样的方法,前者保证全平台计算结果一直,后者会针对计算平台进行速度优化。

Random类怎么使用?

Random类用来创建伪随机数,首先需要播下一个种子,然后开始产生随机序列。

为什么Random叫伪随机?

默认的种子是系统时间,如果每次种子一样,那么随机数序列也一样,所以称为伪随机数。

// 利用系统时间来播下随机数种子
Random r = new Random();
r.nextInt(); // 2071575453,每次都不一样
r.nextInt(10); // 5,生成一个[0,10)之间的int
r.nextLong(); // 8811649292570369305,每次都不一样
r.nextFloat(); // 0.54335...生成一个[0,1)之间的float
r.nextDouble(); // 0.3716...生成一个[0,1)之间的double
// 指定一个随机数种子
Random r = new Random(12345);
for (int i = 0; i < 10; i++) {
    System.out.println(r.nextInt(100));
}
// 51, 80, 41, 28, 55...

前面的Math.random()本质上是调用了这个Random类。

SecureRandom才是真正的安全随机数!

SecureRandom是通过CPU的热噪声,磁盘字节,网络流量等随机时间产生的“熵”,因此是安全的。

SecureRandom sr = new SecureRandom();		// 无法指定种子
System.out.println(sr.nextInt(100));

你可能感兴趣的:(JAVA学习笔记)