一、Object类:
Object类是java中所有类父类
java.lang.Object
native关键字
被它修饰的方法,叫做本地方法
都是没有实现体。
JVM在底层使用C/C++实现。
方法:
1. public final native Class<?> getClass(); // 获取类的字节码文件
2. public native int hashCode(); // 获取对象的hashcode(获取对象的内存地址的hashcode值)
对象都是有内存地址的。如int a = 10,是把10存在一个内存地址。在java中,为了方便,把内存地址做了哈希算法,最终获取一个hashcode值,这个值也是native的,是底层实现的
3. public boolean equals(Object obj) // 比较对象,默认使用== ,比较的是内存地址
字符串重写了该方法,因为字符串一般比较的是内容,而不是地址
4. public String toString() // 以字符串的形式展示对象信息,打印对象时调用
返回的是 对象的类名称 + @ + 十六进制数字(内存地址的16进制值)
getClass() 拿到字节码文件。getName()获取类的名称
getClass().getName() 获取类的名称。注意:是获取全路径,包名+类名
Integer.toHexString() 将int值转换成十六进制的字符串
hashCode() 获取内存地址的hashcode值
5. public final native void notify() //唤醒当前沉睡的线程
6. public final native void notifyAll() //唤醒当前所有沉睡的线程
7. public final void wait() // 让当前线程进行等待。存在三个重载
8. protected void finalize() // 该方法在GC(垃圾回收机制)触发前,会自动触发
// 在当前对象被GC前,会自动触发
// 适合于做一些垃圾回收前的各种工作、挽救工作
先重写该方法
@Override
protected void finalize() throws Throwable {
System.out.println("我觉得还可以挽救");
}
再进行测试
package com.openlab.day15;
import org.junit.jupiter.api.Test;
public class TestObject {
@Test
void testFinalize() {
User u = new User();
u = null;
//把u置空,对于gc而言,内存不一定已经变为空了
//java的垃圾回收机制是自动在维护的,不是程序员维护。c立刻回收,java不是
//标记为空相当于告诉垃圾回收机制,这个是垃圾,垃圾回收机制会过来回收,但是
//过来回收的时间不确定,有时候会立刻过来回收,有时候会等一会过来回收
System.gc();//手动调用gc,让立即回收
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
面试题,这三种的区别和联系:
final
finally
finalize() 在jdk9之后过时了
final和finally是java的关键字,finalize()是Object类提供一个方法
final关键字修饰变量、方法、类,...
finally是用在try语法块中的,写在finally中的代码是必须要执行的
9. protected native Object clone() throws CloneNotSupportedException //对象拷贝
二、引用传递和对象拷贝:
引用传递:将栈引用进行复制,堆中的对象始终是一个
对象拷贝:堆对象会进行复制。借助clone方法
在java中,如果需要拷贝对象,一定要去该类实现Cloneable接口
1.引用传递
package com.openlab.day15;
public class User {
private Integer id;
private String username;
private String password;
private String nickname;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public User() {
super();
}
public User(Integer id, String username, String password, String nickname, Integer age) {
super();
this.id = id;
this.username = username;
this.password = password;
this.nickname = nickname;
this.age = age;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", nickname=" + nickname
+ ", age=" + age + "]";
}
}
package com.openlab.day15;
import org.junit.jupiter.api.Test;
public class TestObject {
@Test
void testObjectClone() {
//创建一个对象
User u1 = new User(1, "张三", "123456", "法外狂徒", 20);
System.out.println(u1);
//引用传递
User u2 = u1;//u1存的是内存地址,把u1给u2就是把内存地址给u2
System.out.println(u1 == u2);
}
}
如果将u1置为空
u1 = null;
System.out.println(u2);
u2还在,虽然一条线没有了,但是另一条还在。
要是u1和u2都置空,内存就会被回收(在栈中已经没有引用指向堆了)。当没有人引用的时候,这块内存就会被认为是垃圾。java的GC是自动的,有自己的垃圾回收机制,根据特定的算法去回收。
2. 对象拷贝
可以重写clone(),也可以直接调用,习惯于重写该方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
在java中,如果需要拷贝对象(clone()),一定要去实现Cloneable接口,如果不实现,默认不能克隆。
public class User implements Cloneable{
}
package com.openlab.day15;
//在java中,如果需要拷贝对象,一定要去实现Cloneable接口
public class User implements Cloneable{
private Integer id;
private String username;
private String password;
private String nickname;
private Integer age;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public User() {
super();
}
public User(Integer id, String username, String password, String nickname, Integer age) {
super();
this.id = id;
this.username = username;
this.password = password;
this.nickname = nickname;
this.age = age;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + ", nickname=" + nickname
+ ", age=" + age + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package com.openlab.day15;
import org.junit.jupiter.api.Test;
public class TestObject {
@Test
void testObjectClone() {
//创建一个对象
User u1 = new User(1, "张三", "123456", "法外狂徒", 20);
System.out.println(u1);
User u2 = u1;
System.out.println(u1 == u2);
//u1 = null;
//System.out.println(u2);
try {
User u3 = (User) u1.clone();//要做强转(u1.clone()是Object)
System.out.println(u1 == u3);
System.out.println(u2 == u3);
System.out.println(u3);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
我们新克隆一个u3,发现u3和u1、u2都不想等,但是它们的值相等。这个拷贝相当于是把u1复制了一份对象放在堆内存,之后赋给u3的引用,叫对象拷贝。这种拷贝叫浅拷贝。
以下介绍浅拷贝。
我们再创建一个猫类,将猫的一个对象交给主人u1。执行这行代码,发现结果为true
System.out.println(u1.getCat() == u3.getCat());
package com.openlab.day15;
public class Cat {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat() {
super();
}
public Cat(int id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Cat [id=" + id + ", name=" + name + "]";
}
}
package com.openlab.day15;
import org.junit.jupiter.api.Test;
public class TestObject {
@Test
void testObjectClone() {
//创建一个对象
User u1 = new User(1, "张三", "123456", "法外狂徒", 20);
Cat cat = new Cat(2022, "小贝");
//将小贝交给了主人
u1.setCat(cat);
System.out.println(u1);
User u2 = u1;
System.out.println(u1 == u2);
//u1 = null;
//System.out.println(u2);
try {
User u3 = (User) u1.clone();//要做强转(u1.clone()是Object)
System.out.println(u1 == u3);
System.out.println(u2 == u3);
System.out.println(u3);
System.out.println(u1.getCat() == u3.getCat());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
红色的表示猫对象,u1存了猫的地址,复制时把红色的地址复制了过来 ,所以u3的猫地址和u1相同。
对象的深浅拷贝:
1. 浅拷贝:将对象的第一层完成拷贝,使得两个对象完成了基本的分离
有可能还存在着藕断丝连,因为有可能有多层对象,多层对象不会做深层次的拷贝
优点:内存占有较少
缺点:如果存在底对象,则子对象没有拷贝,还是指向同一个。
2. 深拷贝:
将两个对象完成分离,彼此之间将无任何关系。
递归拷贝
java实现深拷贝有两种方法:
1)、所有相关对象都实现浅拷贝。有几个实现几个,该方法用的不多
2)、通过序列化对象实现深拷贝
对象 <==> 字节数据
对象 <==> 字符串数据(如JSON)
1)、所有相关对象都实现浅拷贝
案例中猫实现Cloneable接口,重写clone()方法,最后再添加
//需要手动添加
u3.setCat((Cat)(u1.getCat().clone()));