4.javaSE --- 常用API --- Object(观b站黑马程序员,笔记)

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);
    }
}

由此可见,并未改变克隆对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值