Object类是类层次的根类,所有对象(包括数组)都实现这个类的方法
Object类的构造方法是无参构造,因为java中没有一个类带有所有属性
常用的成员方法:
1.toString() --- 返回对象的字符串形式
默认情况下toString打印的是object对象的地址值,但是地址值对我们来说没有实际意义,我们需要的对象的实际属性,所以我们要重写Object类中的toString方法(在JavaBean中重写就好,返回值为String),其实拥有ptg插件的话,当你使用ptg to javaBean的时候会自动为你重写
System. out.println()和这个功能一样的,System是一个类,out是System一个静态变量,System.out就可以获取打印的变量,println是一个打印方法,参数为打印内容
核心逻辑:在打印一个对象的时候,底层调用对象的toString方法,把对象变成字符串,然后再打印在控制台上,打印完毕换行处理
2.equals(object obj) --- 比较两个对象是否相等
默认比较的是地址值,所以当两个对象进行比较的时候,默认比较的就是两个对象的地址值,所以必然会返回false,我们需要比较的是两个对象的值是否相等,所以我们要重写equals,Java也会帮我们写,按下alt+insert快捷键,选择equals() and hashCode(),之后一直enter下去就行(上面 的都是JavaBean,关于这点的在最后)
package com.Target.Goods1;
import java.util.Objects;
public class Goods {
private String id;
private String name;
private double price;
private int count;
public Goods() {
}
public Goods(String id, String name, double price, int count) {
this.id = id;
this.name = name;
this.price = price;
this.count = count;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public String toString() {
return "Goods{id = " + id + ", name = " + name + ", price = " + price + ", count = " + count + "}";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Goods goods = (Goods) o;
return Double.compare(goods.price, price) == 0 && count == goods.count && Objects.equals(id, goods.id) && Objects.equals(name, goods.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name, price, count);
}
}
可以看到,首先进行的还是地址判断,假如地址值都一样了,那么后面的就不用继续进行判断,接着我们进行非空判断或类型判断,如果满足其中一条,则直接返回false,如果上一个if条件不满足,我们对Object类型的对象进行向下强转,强转为当前类型,接着返回值是否相等,并且也用了Object的equals的方法进行比较。
扩展:String类的equals方法,先判断参数是否为字符串,如果是则比较内部属性,如果不是直接返回false,StringBuild类没有equals方法,所以使用的是Object类的equals方法,比较的还是地址值
3.clone(int a) --- 对象克隆
clone方法是java.lang包下的,并且是protected修饰,只能用于本类和其他子类中,不能在lang包下重写代码,要在使用的JavaBean类中重写clone方法,并且让该JavaBean类实现一个叫Cloneable的标记型接口,相当于让java帮我们克隆对象,并且把克隆对象返回出去。
(源对象类型)克隆对象名 = (源对象类型)源对象名.clone()
克隆分为浅克隆和深克隆,无论深克隆还是浅克隆,创建对象方法都是一样的
package com.test.Clone;
import java.util.StringJoiner;
public class CloneJavaBean implements Cloneable{
private int[] data;
private String name;
private int age;
public CloneJavaBean() {
}
public CloneJavaBean(int[] data, String name, int age) {
this.data = data;
this.name = name;
this.age = age;
}
/**
* 获取
* @return data
*/
public int[] getData() {
return data;
}
/**
* 设置
* @param data
*/
public void setData(int[] data) {
this.data = data;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public String toString() {
return "CloneJavaBean{data = " + DataToString(data) + ", name = " + name + ", age = " + age + "}";
}
public String DataToString(int[] data){
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 {
return super.clone();
}
}
1.浅克隆:
克隆对象如果为基本数据类型,那么直接拷贝,如果是引用数据类型,那么拷贝的就是地址值,那么也就是说,当我改变其中一个对象的数据时候,另一个对象再次访问时里面的数据也会跟着改变。而Object的克隆方法就是浅克隆
package com.test.Clone;
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
int[] data = {1,2,3,4,5,6,7,8,9,0};
CloneJavaBean t1 = new CloneJavaBean(data,"张三",20);
CloneJavaBean t2 = (CloneJavaBean) t1.clone();
System.out.println(t1);
System.out.println(t2);
}
}
克隆运行结果
修改data数组0下标的元素
package com.test.Clone;
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
int[] data = {1,2,3,4,5,6,7,8,9,0};
CloneJavaBean t1 = new CloneJavaBean(data,"张三",20);
CloneJavaBean t2 = (CloneJavaBean) t1.clone();
int[] arr = t1.getData();
arr[0] = 100;
System.out.println(t1);
System.out.println(t2);
}
}
修改效果
可以发现,任何一方的更改都会影响对方,因为数组是引用数据类型。
2.深克隆:
克隆对象如果为基本数据类型,那么直接拷贝,如果是引用数据类型,那么会重新再创建一个对象,也就是说,源对象和克隆对象之间是没有关系的,任何一方修改都不会对另一方产生影响,需要注意的是String类型的变量,这种变量虽然是引用数据类型,但是它很特殊,只要不是手动new的对象,那么会保存到StringTable(串池)当中,也就是说,当我们对String类型的对象进行拷贝时,会复用该对象的地址值,String源对象更改,克隆对象也会更改
方法:在javaBean中重写clone方法,不过代码有些不一样,这里不再是让java自动帮我们写,而是自己写
@Override
protected Object clone() throws CloneNotSupportedException {
//先把被克隆对象获取出来,这里是克隆数组
int[] data = this.data;
//我们自己创建新的数组对象
int[] newData = new int[data.length];
//拷贝数组中的数据
for (int i = 0; i < data.length; i++) {
newData[i] = data[i];
}
//调用父类中的方法克隆对象
CloneJavaBean t = (CloneJavaBean) super.clone();
//父类为浅克隆,替换克隆对象的地址值
t.data = newData;
return t;
}
main方法里面还是和之前一样,这里不再展示,直接上运行效果
修改data数组0下标的元素也和之前的代码一样,这里也不再展示代码,直接上运行效果
由此可见,数组是个引用数据类型,修改其数据,深克隆方式不会对任何一方造成影响
但是,这种重写clone方法的深克隆不仅麻烦而且还有缺陷,假设是二维数组,拷贝出来的数据还是地址值,还会出现两个对象指向同一个数组的隐患,想要一劳永逸的深克隆的话,我们可以使用第三方工具,这个第三方工具不是我们写的,也不是java写的,是个jar包,需要导入到项目中,我用的jar包叫gson-2.6.2.jar,这个在网上都找得到,而且免费的,关于如何导入到项目,也可以在网上找到教程,这里不多做赘述。接下来就来写第三方工具的使用代码了
package com.test.Clone;
import com.google.gson.Gson;
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
int[] data = {1,2,3,4,5,6,7,8,9,0};
CloneJavaBean t1 = new CloneJavaBean(data,"张三",20);
//首先创建第三方工具新的对象
Gson gson = new Gson();
//把对象变成字符串
String str = gson.toJson(t1);
//想进行对象克隆的时候再把字符串变回对象
CloneJavaBean clone = gson.fromJson(str,CloneJavaBean.class);
//先克隆,然后对源对象进行修改
int[] arr = t1.getData();
arr[0] = 100;
System.out.println(t1);
System.out.println(clone);
}
}
由此可见,并未改变克隆对象