一、Object类
常用方法
1.toString()
将对象转化为字符串,字符串组成为包名+类名+@+16进制的地址值
下面是底层源码:
public String toString() {
//包名+类名 @符号 通过一系列运算最后得到16进制的地址值
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
我们很多时候在输出对象的时候,不用调用toString方法也会输出该结果为什么呢?这个我们就要来探讨探讨输出语句了,具体用到的类、属性、方法源码如下所示:
public final class System {
...
//out为System中的静态属性,返回值为PrintStream输出流
public final static PrintStream out = null;
...
}
//用到的println方法
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
//用到的valueof方法
public static String valueOf(Object obj) {
//此处使用三目运算符,如果对象不为空则调用toString()方法进行输出
return (obj == null) ? "null" : obj.toString();
}
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
//用到的write方法,将要输出的打印到控制台
private void write(String s) {
try {
synchronized (this) {
ensureOpen();
textOut.write(s);
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush && (s.indexOf('\n') >= 0))
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
//用到的换行方法,主要就是换行
private void newLine() {
try {
synchronized (this) {
ensureOpen();
textOut.newLine();
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
总结一下:toString()方法调用是在println()方法中的第一步,使用String.valueOf(x)通过三目运算符,使对象调用toString()方法转化为字符串。
2.equals(Object obj)
比较两个对象是否相同,如果没有重写则调用父类Object中的方法,具体比较的是两个对象地址值,具体源码如下:
public boolean equals(Object obj) {
//this是调用该方法的对象,与传进来的对象进行==判断
//进行地址值的判断
return (this == obj);
}
如果想要比较对象中属性则需要重写equals(Object obj)方法,代码如下:
@Override
public boolean equals(Object o) {
//1.先比较两个对象地址
if (this == o) return true;
//2.对传入的对象进行非空,以及类型进行判断
if (o == null || getClass() != o.getClass()) return false;
//3.然后将传入的对象强转为当前对象类型
User user = (User) o;
//4.然后对里面的各个属性进行判断
return Objects.equals(id, user.id) && Objects.equals(username, user.username);
}
重写后的equals()方法可以总结为下面四步:
1.先比较两个对象地址
2.对传入的对象进行非空,类型进行判断
3.然后将传入的对象强转为当前对象类型
4.对里面涉及的属性进行判断
这里有一个题目,大家可以试着写一下(提示一下:这里涉及toString()方法重写)
String s = new String("123");
StringBuffer stringBuffer = new StringBuffer("123");
//思考一下这两个输出语句的值
System.out.println(s.equals(stringBuffer));
System.out.println(stringBuffer.equals(s));
3.clone(int a)对象克隆
这个方法有一个特殊的一点,该方法是由protected修饰的,只能在本包中(package java.lang),调用,所有在重写该方法时,应要用父类调用该方法。具体代码如下:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Cloneable{
private Integer id;//游戏角色
private String username;//用户名
private String password;//密码
private String path;//游戏图片
private int[] data;//游戏进度
@Override
public String toString() {
return "游戏角色:"+id+",用户名:"+username+",密码:"+password+",游戏图片:"+path+",游戏进度:"+arrToString();
}
private String arrToString(){
StringJoiner sj = new StringJoiner(",","[","]");
for (int i = 0; i < data.length; i++) {
sj.add(data[i]+"");
}
return sj.toString();
}
@Override
protected Object clone() throws CloneNotSupportedException {
//让父类帮我们调用clone方法,并将结果返回
return super.clone();
}
}
总结来说一共三步:
1.重写Object中的clone()方法
2.实现Cloneable接口,这个接口里面没有抽象方法,就是个标志,标志着可以进行对象克隆
3.创建对象调用clone()方法
然后就是在main方法中进行测试,具体代码如下所示:
public static void main(String[] args) throws CloneNotSupportedException, JsonProcessingException {
int[] data = {1,2,3,4,5,6,7,8,9,0};
//1.浅克隆
User user = new User(5,"lsh","929126","a.img",data);
//底层会帮我们创建一个新的对象,并将原来的数据拷贝过去
User user2 = (User) user.clone();
//验证Objec中克隆为浅克隆
int[] data1 = user.getData();
data1[0] = 100;
System.out.println(user);
System.out.println(user2);
}
只是重写父类中的方法,不做处理,这个只是克隆中的浅克隆。由此引出克隆的几种形式,分别是浅克隆与深克隆,下面分别以图的形式介绍两者,以及两者之间的区别。
1.浅克隆
2.深克隆
3.两者的区别
简单来说两者区别:
1.浅克隆:两个对象中的引用数据类型(String除外)共用同一个,其中一个改变,两个都改变。
2.深克隆:两个对象中的引用数据类型(String除外)不是同一个,两者独立操作互不影响。
接下来,对我们刚刚写的浅克隆进行修改,只需在重写的方法里面进行一些处理即可,具体代码如下所示:
@Override
protected Object clone() throws CloneNotSupportedException {
//1.创建新的数组
int[] newData = new int[data.length];
//2.赋值新数组的值
for (int i = 0; i < data.length; i++) {
newData[i] = data[i];
}
//3.调用父类中的clone()方法,获取浅克隆对象
User u = (User) super.clone();
//4.将该对象中的数组替换为新的数组
u.data = newData;
return u;
}
实现深克隆还可以引用第三方jar包Gson、ObjectMapper(Maven工程的话导入依赖即可,普通的需要在网上下载相应的jar包)具体代码如下:
int[] data = {1,2,3,4,5,6,7,8,9,0};
User user = new User(5,"lsh","929126","a.img",data);
//第三方jar包gson
Gson gson = new Gson();
String json = gson.toJson(user);
System.out.println("gson序列化"+json);
User user2 = gson.fromJson(json, User.class);
int[] data1 = user.getData();
data1[0] = 100;
System.out.println(user);
System.out.println(user2);
//ObjectMapper
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(user);
System.out.println(s);
User user3 = objectMapper.readValue(s, User.class);
int[] data1 = user.getData();
data1[0] = 100;
System.out.println(user);
System.out.println(user3);
具体操作步骤可以分为两步:
1.将user对象转化为JSON格式的字符串
2.将JSON格式的字符串转化为User类型的对象
二、Objects
常用方法
public static boolean equals(Object a, Object b) 先做非空判断比较两个对象
public static boolean isNull(Object obj) 判断对象是否为null,为null则为true,反之false
public static boolean nonNull(Object obj) 判断对象是否为null和isNull()方法相反
具体代码如下:
public static void main(String[] args) {
/*
public static boolean equals(Object a, Object b) 先做非空判断比较两个对象
public static boolean isNull(Object obj) 判断对象是否为null,为null则为true,反之
public static boolean nonNull(Object obj) 判断对象是否为null和isNull()方法相反
*/
Student student1 = null;
Student student2 = new Student("ls",20);
boolean equals = Objects.equals(student1, student2);
System.out.println(equals);
System.out.println("---------------------------------------");
System.out.println("student1:"+Objects.isNull(student1));//true
System.out.println("student2:"+Objects.isNull(student2));//false
System.out.println("----------------------------------------");
System.out.println("student1:"+Objects.nonNull(student1));//false
System.out.println("student2:"+Objects.nonNull(student2));//true
}
Objects这个就是就是个工具类,最常用的方法还是equals(),替我们做了非空判断,省略了一些代码。