博主:_LJaXi Or 東方幻想郷
专栏: Java | 从跨平台到跨行业
开发工具:IntelliJ IDEA
JAVA BASE API
- Object 类
- `clone` 对象克隆
- `toString()` 转换字符串
- `equals(Object obj)` 地址比较
- Objects 类
- `Objects.equals(Object obj1, Object obj2)` 非空比较
- `isNull(Object obj)` 判断null
- `nonNull(Object obj)` 判断非null
- 包装类
- 自动装箱
- 自动拆箱
- 字符串操作 | StringBuilder,StringBuffer,StringJoiner
- `StringBuilder` 字符串操作
- 基本使用
- 使用 `StringBuilder` 拼接数组
- `StringBuffer` 字符串操作
- `StringJoiner` 字符串拼接
- 基本使用
- `Math`,`System`,`Runtime`
- `Math` 数学类
- `System` 系统类
- `Runtime` 运行类
- 简单使用
- `BigDecimal` 解决小数失真运算
- Date 类
- `before Java 1.8 `
- 创建时间对象(部分过时)
- 获取日期和时间(过时的)
- 设置日期和时间(过时的)
- 格式化和解析时间对象(部分过时)
- `after Java 1.8`
Object 类
Object类是类层次结构的根。每个类都有 Object作为超类。所有对象,包括数组,实现这个类的方法
Object 常见的 API
API | 用法 |
---|---|
clone() | 创建并返回此对象的副本 |
toString() | 返回对象的字符串表现形式 |
equals(Object obj) | 指示是否有其他对象 “等于” 这一个 |
clone
对象克隆
public class Demo{
public static void main(String[] args) {
Person p = new Person(12, "zhangssan");
Person p1 = null;
{
try{
p1 = (Person)p.clone();
} catch(CloneNotSupportedException e) {
e.printStackTrace();
}
{
System.out.println(p); // Person@123456
System out.println(p1); // Person@114514
}
}
从这边代码可以看到
p1
使用clone
方法 克隆 对象p
地址却是不一样的, 说明我们开辟了一块新的栈内存
浅拷贝 与 深拷贝
- 浅拷贝
// Person 类
class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override // throws xxx 异常声明 或使用 try catch
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
// Main 程序入口类
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("Alice", 25);
Person person2 = (Person) person1.clone();
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
// 修改person1的字段
person1.setName("Bob");
person1.setAge(30);
// 验证浅拷贝的效果
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
}
}
- 只可以在子类中重写克隆方法, 因为
Main
函数不是类的实例方法, 它无法被继承或重写- 可以看到
Person
类实现了一个接口Cloneable
, 这个Cloneable
就称之为标记接口
, 它表示该类的实例可以被克隆, 看开看你会发现它只是一个 …{}
运行如下
person1: Person{name='Alice', age=25}
person2: Person{name='Alice', age=25}
person1: Person{name='Bob', age=30}
person2: Person{name='Alice', age=25}
- 深拷贝
// Person 类
class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
@Override // throws xxx 异常声明 或使用 try catch
public Object clone() throws CloneNotSupportedException {
// 创建新的Person对象
Person clonedPerson = (Person) super.clone();
// 修改为深拷贝
clonedPerson.name = new String(this.name);
// 对于基本类型,直接复制值
clonedPerson.age = this.age;
return clonedPerson;
}
@Override
public String toString() {
return "Person{name='" + name + "', age=" + age + "}";
}
}
// Main 程序入口类
public class Main {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person("Alice", 25);
Person person2 = (Person) person1.clone();
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
// 修改person1的字段
person1.setName("Bob");
person1.setAge(30);
// 验证深拷贝的效果
System.out.println("person1: " + person1);
System.out.println("person2: " + person2);
}
}
运行如下
person1: Person{name='Alice', age=25}
person2: Person{name='Alice', age=25}
person1: Person{name='Bob', age=30}
person2: Person{name='Alice', age=25}
首先,创建了一个名为
person1
的Person
对象,其姓名为"Alice"
,年龄为25
然后,通过调用clone()
方法创建了一个名为person2
的新对象,它与person1
具有相同的属性值。
在验证深拷贝效果之前,我们修改了person1
的姓名为"Bob"
,年龄为30
最后,输出了person1
和person2
的详细信息。
可以看到,person1
的改变没有影响到person2
,说明这是一个深拷贝。因此,person1
被成功拷贝到了person2
它们之间没有共享字段的引用。
toString()
转换字符串
toString() 方法源码
public String toString() {
return "Person{name='" + name + "', age=" + age + "}"; // 例如有name age字段
}
使用
// 入口函数 Main
public class Main {
public static void main(String[] args) {
Person person = new Person("John", 25);
System.out.println(person.toString());
}
}
输出:
Person{name=“John”, age=25}
equals(Object obj)
地址比较
简单比较两个对象的引用
Object obj1 = new Object();
Object obj2 = obj1;
if (obj1 == obj2) {
// 两个对象的引用相等
}
判断两个对象的地址是否相等
obj1.equals(obj2);
Objects 类
Objects是一个工具类,提供了很多操作对象的静态方法给我们使用
它与 Object
类有着相同的方法名,功能都是类似的
Objects.equals(Object obj1, Object obj2)
非空比较
Objects.equals 先做非空判断,再做对象比较
源码解析
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
isNull(Object obj)
判断null
判断对象是否为
null
若为null
返回true
nonNull(Object obj)
判断非null
判断对象是否不为
null
若不为null
返回true
包装类
基本数据类型对应的包装类列表
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
自动装箱
可以自动把基本类型的数据转换成对象
例如
Integer a1 = 12;
自动拆箱
可以自动把包装类型的对象转换成对应基本数据类型
例如
int a4 = a1;
字符串操作 | StringBuilder,StringBuffer,StringJoiner
StringBuilder
,StringBuffer
,StringJoiner
都是一些字符串的操作方法,它们有时比String
更适合做字符串的修改操作,效率也会更高,代码也会更简洁
StringBuilder
字符串操作
StringBuilder
在操作字符串的时候效率非常高(频繁拼接,修改建议使用StringBuilder
)
基本使用
StringBuilder s = new StringBuilder();
StringBuilder s = new StringBuilder("hello");
// 拼接内容
s.append(12);
s.append("hi");
s.append(true);
// 返回内容: “hello12hitrue”
// 支持链式编程
s.append(true).append("haha")
使用 StringBuilder
拼接数组
public static void main(String[] args) {
System.out.println(getArrayList(new int[] {
1, 123, 456
}));
}
// 实现方法
public static String getArrayList(int[] arr) {
if (arr == null) {
return null;
}
// 实例化字符串操作类 StringBuilder
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) { // 若拼接到最后一个不加 ,
sb.append(arr[i]);
} else {
sb.append(arr[i]).append(",");
}
}
sb.append("]");
return sb.toString(); // 返回 字符串表现形式
}
StringBuffer
字符串操作
与
StringBuilder
相似,但是StringBuilder
是线程不安全的,StringBuffer
是线程安全的
StringJoiner
字符串拼接
与
StringBuilder
相似,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的
好处:
不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁
基本使用
StringJoiner s = new StringJoiner(间隔符号);
StringJoiner s = new StringJoiner(间隔符号, 开始符号, 结束符号);
StringJoiner
相对于StringBuilder
来说还是比较简单, 一般只可以操作简单的字符拼接,如果需要频繁插入,删除字符,建议使用StringBuilder
操作
StringJoiner s = new StringJoiner(", ");
s.add("java1");
s.add("java2");
// java1, java2
// ----------------------------------
StringJoiner s = new StringJoiner(", ", "[", "]");
s.add("java1");
s.add("java2");
// [java1, java2]
使用
StringJoiner
拼接
public static void main(String[] args) {
System.out.println(getArrayData(new int[] {
1, 2, 3
}));
}
public static string getArrayData(int[] arr) {
// 判断 arr 非空
if (arr == null) {
return null;
}
// arr 数组存在
StringJoiner sj = new StringJoiner(", ", "[", "]");
for(int i = 0; i < arr.length; i++) {
sj.add(arr[i] + "");
}
return sj.toString();
}
Math
,System
,Runtime
Math
数学类
Math
代表数学,是一个工具类,里面提供的都是对数据进行操作的一些静态方法
System
系统类
System.currentTimeMillis(); // 获取当前系统的时间(毫秒值) long 类型
Runtime
运行类
小知识:
Runtime
是个单例设计模式的类
简单使用
Runtime r = Runtime.getRuntime(); // 返回与当前Java应用程序关联的运行时对象
BigDecimal
解决小数失真运算
在一些商业项目中,在进行一些小数运算时,必须要求精准,使用传统运算符时可能会出现小数运算失真的情况
System.out.println(0.2 + 0.1); // 0.30000000000000004
采用 java.util.math 中的 BigDecimal 类 来运算解决失真问题
// 转为 字符串 封装成 BigDecimal 对象来运算
BigDecimal a1 = new BigDecimal(Double.toString(a));
BigDecimal b1 = new BigDecimal(Double.toString(b));
// 优化
// 推荐用以下方式把小数转换为字符串再得到BigDecimal对象来使用(更简洁)
BigDecimal a1 = BiDecimal.valueOf(a);
BigDecimal b1 = BiDecimal.valueOf(b);
BigDecimal b = a1.add(b1);
BigDecimal b = a1.subtract(b1);
BigDecimal b = a1.multiply(b1);
BigDecimal b = a1.divide(b1);
Date 类
before Java 1.8
在 Java 1.8 之前,Date 对象是可变的,所以处理时间类需要谨慎
创建时间对象(部分过时)
Date currentDate = new Date(); // 使用当前日期和时间创建Date对象
Date specificDate = new Date(year, month, day); // 使用指定的年、月、日创建Date对象(过时的)
获取日期和时间(过时的)
int year = date.getYear(); // 获取年份(从1900年开始计算)
int month = date.getMonth(); // 获取月份(从0开始计算,0表示一月)
int day = date.getDate(); // 获取天数(月份中的日期)
int hours = date.getHours(); // 获取小时w
int minutes = date.getMinutes(); // 获取分钟
int seconds = date.getSeconds(); // 获取秒钟
设置日期和时间(过时的)
date.setYear(year); // 设置年份
date.setMonth(month); // 设置月份
date.setDate(day); // 设置天数
date.setHours(hours); // 设置小时
date.setMinutes(minutes); // 设置分钟
date.setSeconds(seconds); // 设置秒钟
格式化和解析时间对象(部分过时)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 生成规定格式的时间对象(过时的)
String formattedDate = formatter.format(date); // 格式化Date对象为指定格式的字符串
Date parsedDate = formatter.parse("2022-01-01 12:00:00"); // 将字符串解析为Date对象
after Java 1.8