一文带你认识Java中的Object类和深浅拷贝

目录
  • 前言
  • 一.初识Object类
    • 1.Object类接收所有子类实例
    • 2.Object类部分方法介绍
      • ①.Object内的toString方法
      • ②.Object内的equals和hashCode方法
      • ③.Object类的getClass方法
      • ④.Object类的clone方法
  • 二.认识深拷贝和浅拷贝
    • 1.什么是深浅拷贝?
    • 2.实现深拷贝
  • 三.Object类和深浅拷贝总结

前言

本文介绍了Object类以及Object类部分方法,toString方法,equals和hashCode方法(重写前和重写后的对比),getClass方法,clone方法,以及拷贝新对象时会出现的深浅拷贝,内容较长,耗时一天,建议收藏后观看~

一.初识Object类

Object类是Java默认提供的一个类。而这个类是Java里所有类的顶级父类,即在继承体系下,除了Object以外的所有类都可能有自己的父类,但Object类没有父类,
并且所有的类同时也都默认继承Object类…
Object类是在Java.lang 包中的,默认已经导入了此类

有了Object类,可以使方法的形参接受任何类的对象,也可以使返回类型返回任意类的对象,可以使所有类都继承一些Object共有的方法,故Object类是非常重要的类!!!

1.Object类接收所有子类实例

也就是说,不管是Java库里的类还是自己定义的类,不管它们是否有自己的父类,都默认继承着Object类…

Object类的存在,使所有类之间有了联系,根据向上转型的用法:父类引用可以接收子类对象地址…

那么就可以使用Object类型的引用接受所有类的实例对象

示例:

class Student{//自定义学生类
    String name;
    Student(String name){
        this.name=name;
    }
}
class Animal{//自定义动物类
    String name;
    Animal(String name){
        this.name=name;
    }
}
public class Text {

    public static void function(Object obj) {
        System.out.println(obj);
    }

    public static void main(String[] args) {
        function(new Animal("动物"));
        function(new Student("学生"));
    }
}

Person和Animal类都是自定义的类,其没有extends显示继承其他类,但也默认继承Object类,那么可以通过调用function方法形参用Object类型的引用obj接受每个对象,而此时发生向上转型,而通过输出方法println输出obj,最后输出了两个对象的内容!!

思考:

通过传递的对象不同,输出的内容也不同,那这种实现是否是多态呢?

多态即调用同一方法但不同对象会体现出不同的状态,这里看似是不同状态,但是多态实现条件没有满足,因为并没有发生重写和动态绑定

输出的内容本应是每个对象的名字,但为什么会是一堆字母串?

以demo6.Animal@1b6d3586为例 demo6.Animal即是类的全路径(包名+类名)
@是分隔符, 而1b6d3586是一串十六进制数的字符可以暂时理解为对象的地址

那println方法底层是怎么输出这些的呢?

下面是println的一些源码分析:

此方法是用Object 类型引用接受 即可以接收任意类的实例,即所有对象都能输出

可见最关键的是String.valueOf方法,即是将对象内容转换为字符串形式

再进入到此方法进行分析↓

valueOf方法 返回的即是对象的字符串形式,而当obj接受的是null时,直接返回null

当不为空时,即通过toString方法获取到对象的内容的字符串形式返回…

重点来了:

toString方法在定义Person,和Animal时并没有写此方法,而这两个类也没有显示继承任何的类,而obj指向的对象是Person或者Animal,说明toString方法只能是Object类里面的

故这两个类没有重写toString方法,也就没有发生动态绑定,调用和执行的一直是Object类的toString方法,故也没有发生多态

简单了解 在Object类里的toString方法

getClass()是获取到Person或者Animal的类示例,.然后getName()获取到其类所在的全路径的以字符串形式返回

@是分隔符
hashCode()得到的是Person或者Animal实例的hash值,是一个整数(主要用于区分不同的对象,但可能会存在不同的对象hash值相同的情况(哈希冲突) )

而Integer.toHexString方法即是将获取到的hash值转换为十六进制的字符串形式

以此最后得到类似于demo6.Animal@1b6d3586 这种输出格式

注意: hashCode 和getClass()底层都是native修饰的本地方法,底层由C或者C++代码实现,先明白此方法的大概用途即可

2.Object类部分方法介绍

Object是所有类的父类,其内部定义了一些成员方法,这些方法都会被子类继承,一些通常会被子类重写来使用,学会使用这些方法是很有必要的

以下是Object内的成员方法简单介绍,

简单介绍下被圈起来的成员方法,而其他的方法需要在线程方面用到…

①.Object内的toString方法

toString方法主要就是针对对象的内容,即将对象的内容转换成字符串形式返回

在上面介绍到,当想输出某个对象内容可以通过调用println输出方法,println方法的形参是Object类型接受,然后会调用String.valueOf方法 将对象内容转换为字符串,而此方法内会调用toString方法,最后输出的是:类的全路径@hashCode的十六进制形式

但是这并不符合我们想要输出的对象内容,当Person对象和Animal对象想要输出的内容是对象内的成员变量name要怎么做?

此时就要重写toString方法↓

1.可以根据Objec里的toString的方法在对应的子类里写同样的权限修饰符返回值类型 方法名(需满足重写的要求) 然后具体方法体根据自己实现

public String toString(){

  //重写的内容...
}

2.使用IDEA快捷键或者右击,选择Generate ->toString 自动生成重写的toString

@Override
    public String toString() {
        return "Animal{" +   //自动生成的内容  ,也可以根据需求自己修改
                "name='" + name + '\'' +
                '}';
    }

当在Person和Animal类里重写了toString方法后,再次调用上面function方法其内部输出obj接受的对象内容即能输出每个对象的指定内容

class Animal{
    String name;
    Animal(String name){
        this.name=name;
    }

    @Override
    public String toString() {
        return "Animal{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student {
    String name;

    Student(String name) {
        this.name = name;
    }

    @Override
    public String toString() {  //重写内容
        return "Student{" +
                "name='" + name + '\'' +
                '}';
    }

}
public class Text {

    public static void function(Object obj) {
        System.out.println(obj);
    }

    public static void main(String[] args) {
        function(new Animal("动物"));
        function(new Student("学生"));
    }
 }

obj接受Person或者Animal对象,调用println方法,而内部最后会调用Object类里的toString方法得到对象内容的字符串形式,但是因为发生了子类重写Object类的toString方法

此时调用Object类的toString方法执行的是子类自己重写的Object类的toString方法(多态)

而Person和Animal两个类都重写了toString,此时则发生了多态…

最后根据自己设置的对象内容输出了对应的对象…

总结:

toString没有重写时输出的是对象其类的全路径@十六进制形式的hashCode值
toString重写时输出的是自己重写的指定对象内容 (更常用)

②.Object内的equals和hashCode方法

equals是比较当前对象和指定对象是否相等,hashCode是获取当前对象的哈希值
二者通常是成对出现的!

1.Object内的equals方法和hashCode方法

Object内的equals方法:

this引用表示当前对象的引用存放的当前对象的地址,而obj引用接受的是要比较的对象的地址…

故Object内的equals方法比较两个对象时,比较的是两个对象的地址,而对象不同则对象地址一定是不相等,即绝大部分返回的值都是false

而我们大部分情况下判断对象是否相等并不是看对象地址,而是看对象的内容是否相等(成员变量内的值),

要实现这种要求,就要重写equals方法! (根据内容比较对象是否相等)

Object内的hashCode方法:

此方法是native修饰的本地方法,无法直接看到源码.但大致就是通过对象地址根据对应规则生成一个整数即哈希值

简单了解hashCode的用途:

hashCode方法在作用在哈希桶处体现,所谓哈希桶就是一个链表数组,用来动态的搜索数据的数据结构.,主要作用用来搜索 故哈希桶内相同的对象只会存放一份!

当你要存放对象在哈希桶内时,即是对应到数组某个下标的空间内存放该对象,而对象怎么得到一个整形下标,即是通过了hashCode方法生成的一个整数,最后通过该整数与数组长度取余映射到数组的对应下标!

但是hashCode生成的整数跟对象地址有关,那么不同对象会生成不同的整数,但是实际情况判断一个对象是否相同不是看对象地址,而是看对象内容,当内容完全一样,而hashCode又不同,会发生在一个哈希桶内存放着两个内容一样的对象,

或者当又new了一个新对象其内容和之前对象完全相同,可是通过调用hashCode方法根据对象地址生成的哈希值不同映射到不同数组下标,而在此下标对应的空间内又没有找到和之前对象内容完全相同的,则会出现在哈希桶内查找对象时,找不到内容相同的对象但是哈希桶内又存在这样的对象,则达不到我们所实现的要求…

而要实现映射的数组下标即要使获得的hashCode相同,那么就要重写hashCode方法(根据对象内容生成哈希值)

===============================================================

2.重写equals方法和hashCode方法

上面介绍在Object内的equals方法和hashCode方法不满足实际需求,此时需要在子类里根据实际需求重写这两个方法,重写之后即会实现动态绑定 调用我们重写的方法

重写equals方法和hashCode方法可以根据其Object内的方法在子类里写满足重写要求的方法,方法体根据自己需求而改, 要考虑实际情况重写,hashCode也要自己定一套根据不同内容生成对应的整数的哈希方法

而在IDEA里提供了快捷生成的重写方法,右击 Generate 点击equals and hashCode 一路Next即可 自动根据对象内容生成 equals方法和hashCode方法

@Override
    public boolean equals(Object o) {
        if (this == o) return true;// 对象地址相等返回true
        if (o == null || getClass() != o.getClass())
        return false; 要比较的对象为null或者 两个对象是不同的类实例 返回false

        Animal animal = (Animal) o;
        return Objects.equals(name, animal.name);
        //根据Objects类的equals方法 传指定内容比较是否相等返回结果
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);//根据Objects类的hash方法传指定参数 即根据其参数内容生成hashCode
    }

自动生成的equals方法和hashCode方法底层都调用了Objects类的方法,而Objects类即是Object类的api,里面提供的都是静态方法,主要用于当重写Object类时,根据子类对象的内容调用Objects对应的方法,分化成子类内容之间进行操作

equals(name, animal.name);

接受当前对象的name和指定比较对象的name, 而此时的a.equals(b) 转换为了name之间的比较,而name是String类型,其类已经封装好了对equals的重写(即判断每个字符是否相等),通过此方法得出对应的内容是否相等,当有多个参数比较则会依次调用多个此方法

===============================================================

Objects.hash(name);

其内部的hash方法形参是Object…values

而这个语法叫做可变参数:

在 Java 5 中提供了变长参数,允许在调用方法时传入不定长度的参数。变长参数是 Java 的一个语法糖,本质上还是基于数组的实现:

在定义方法时,在最后一个形参后加上三点 …,就表示该形参可以接受多个参数值,多个参数值被当成数组传入。上述定义有几个要点需要注意:

可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数

由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数

Java的可变参数,会被编译器转型为一个数组

变长参数在编译为字节码后,在方法签名中就是以数组形态出现的。这两个方法的签名是一致的,不能作为方法的重载。如果同时出现,是不能编译通过的。可变参数可以兼容数组,反之则不成立

使用了可变参数说明hash()实参可以有多个,根据实际情况而定,最后都会被接受放在Object数组里,此时再调用其内部封装的hashCode , 按相应的规则,调用数组每一个元素的hashCode方法,因为每一个元素都是指定对象的内容 可能是字符串类型或者是Integer类型等, 其内部都封装了hashCode方法,有自己根据自身内容生成哈希值的方法,最后合并得到一个哈希值返回给Objects.hash方法调用方得到一个根据对象指定内容生成的哈希值

故使用编译器自动生成的重写equals和hashCode方法,会编写好相应的方法体,在我们使用的时候,根据需求对对象相应内容要比较的参数传上去,根据指定内容或者全部内容以此判断对象是否相等以及生成相应的hash值!

为什么equals和hashCode需要一起重写?

因为当只重写了equals表示会根据相应内容和指定对象进行比较是否相等,此时没有重写hashCode则在哈希桶里仍然会出现指定内容相同的对象出现多份或者有指定内容相等的对象但是没有找到此对象的情况

而只重写hashCode是没有意义的…哈希桶里即便出现了对象内容完全一样的,也会因为对象地址不同而判定为两个不同的对象…
所以二者一定要有关联,且要一起重写…

equals和hashCode的关系

equals判断两个对象相等其hashCode一定相等嘛?

equals判断两个对象完全相等,要么地址相等要么指定内容相等,对应的如果重写了equals也就会根据内容重写hashCode 那么hashCode一定会相等

hashCode相等 equals判断两个对象一定会相等嘛?

hashCode相等只能说明在指定的获取哈希的函数里两个对象的指定内容或者地址最后生成的哈希值是相同的,但是也有可能内容地址不同却出现相同的哈希值(哈希冲突),但是此时equals并不会相同!

总结:

equals相同,hashCode一定相同, hashCode相同 equals不一定相同,

equals不同,hashCode可能相同,hashCode不同则equals一定不相同

③.Object类的getClass方法

getClass方法是Java中获取类实例的一种方法,而类实例主要用于反射中使用

简单了解下反射机制:

Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件
,被编译后的Java文件.class也被JVM解析为一个对象,这个对象就是 java.lang.Class .
这样当程序在运行时,每个java文件就最终变成了Class类对象的一个实例。我们通过Java的反射机制应用到这个实例,就可以去获得甚至去添加改变这个类的属性和动作,使得这个类成为一个动态的类

而一个类文件 只有一个类实例,一个类实例化多个对象,通过这多个对象调用getClass获得的类实例都是同一个

在使用快捷命令重写equals方法生成的代码中使用了getClass方法,

即是获得当前对象的类实例,

和Object类型的o引用接受的对象调用getClass获得的类实例(即o指向的对象的类实例)判断是否相等,如果是同一个类实例化的对象则获取的类实例是同一个,如果是不同 的类的实例对象 则会返回false…此处即是为了判断两个对象是否是同一个类实例而来

也可以使用 if ( ! o instanceof Person) return false;判断 o指向的对象是否是Person的实例,从而判断两个对象是否是同一个类实例而来

④.Object类的clone方法

Object类里的clone方法是native修饰的本地方法底层由C/C++实现是直接供对象调用的方法,当对象调用clone方法会在堆区创建一份和原对象一模一样的对象返回(即属性和行为都一样)

虽然clone方法可以直接调用,但并不是字面意思上直接调用

class Person{
    String name;
    int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
}

当有了上面这个类,我们是否可以在main方法中直接创建一份Person对象,再直接调用clone方法再用一个Person引用接受克隆的新对象呢?

此时会编译报错, 在Java中clone被看成一种公共特性,即提供了一个Cloneable接口,其是一个空接口,表示一个标准规范,只有实现了此接口的类才能调用clone方法进行克隆,如果没有实现,则会报CloneNotSupportedException异常

class Person implements Cloneable{
    String name;
    int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
}

当Person实现了Cloneable具备了克隆特性 是否可以克隆了呢?

注意! clone方法在Object类是protected修饰的!!!

当被protected修饰的成员,在当前包里可以直接被访问,但是在不同包里,只能在其对应的子类内被访问!

即调用的是Person对象继承的Object类的clone方法,Person是Object的子类,那么就要在Person类内调用clone方法,Test类虽然也是Object的子类但是调用的是Person,所以在Test类里是不能调用到Person类对象的clone方法

为了实现接口方法统一使在Test类里能够调用到Person的clone方法,这里也要在Person类里重写clone方法,但这个重写只是给类外提供调用clone的方法,并没有重写clone本身的方法

通过 在Person 里重写 clone方法 方法体 是调用其父类Object类的clone方法,但是会抛出一个编译时异常,此异常为了提醒程序员需要处理此异常,即必须try-catch处理或者throws 声明异常抛给上层调用方

使用throws层层声明异常后↓

到这里最后一步,能够调用Person的clone方法 克隆一份一样的对象,但是clone方法的返回类型是Object类型的,不能直接用Person接受,向下转型需要这里强转

最终的写法↓

class Person implements Cloneable{//Person实现Cloneable 支持克隆
    String name;
    int age;
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class Text {//Cloneable是一个接口 空接口 是一个标记接口 标准规范 唯一作用 表示当前类实例化的对象是可以被克隆的,如果没有实现这个接口就不能被克隆
    //实现cloneable接口 当前对象可以克隆 但是需要重写object类的clone方法,但是这个重写只能为了调用父类clone方法!!! 没有实现这两种会报编译时异常!

    public static void main(String[] args) throws CloneNotSupportedException {
        Person person = new Person("张三", 18);
        Person clonePerson = (Person) person.clone();

    }

}

为什么clone返回类型是Object类型?

一个方法只有一个返回类型,而实现cloneable接口的对象一般都支持克隆,但是既然可以克隆很多对象,那么返回类型是不确定具体返回的对象类是哪个,而根据Object类的特性,其是所有类的父类,那么就可以达成通用, 借助向上转型返回对象,在外层由程序员自己进行向下转型 从而实现对应的类型接受对应的克隆对象

二.认识深拷贝和浅拷贝

在认识Object的clone方法后,我们能直接拷贝一份和对象一模一样的新对象出来,但是在拷贝对象时,因为引用变量存放的是对象地址,故在拷贝时还要区分深拷贝和浅拷贝!

1.什么是深浅拷贝?

浅拷贝即是当修改拷贝的对象内容时, 原被拷贝对象的内容也会随之被修改,即两个对象共用同一块内容,看似拷贝了一份全新的对象,但是这个对象的成员和原对象的成员仍然共用同一份空间
深拷贝即当修改拷贝对象内容时,原拷贝对象内容不会改变,即两个对象的所有内容也是独立被拷贝的!

class Money implements Cloneable{
    public double m=3.14;

    @Override
    public String toString() {
        return "Money{" +
                "m=" + m +
                '}';
    }
}
public class Student implements Cloneable {
    Money money=new Money();
    public String name;
    public int age=18;
    public Student(String name){
        this.name=name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
    return super.clone();
    }

    @Override
     public String toString() {
        return "Student{" +
                "money=" + money +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
public static void main(String[] args) throws CloneNotSupportedException{
        Student student=new Student("666");
        Student student1=(Student) student.clone();
        System.out.println(student);
        System.out.println(student1);
        student1.age=20;// 基本数据类型存放的是原对象的数据 此时修改基本数据类型, 原对象并不会受到影响
        student1.name="000";//name虽然指向的是同一个对象 但是后面直接是实例化另一个对象给克隆的引用变量本质上
        // 克隆对象的name一开始指向的和原对象的name指向的字符串对象一样
        student1.money.m=100.0;   //会克隆一份对象 里面成员变量值和方法是和原对象一样的
        //引用数据类型存放的是原对象的对象地址 这就造成 克隆后对象内的引用变量指向的是同一块对象地址
        //此时通过引用变量修改对象内容 原来的和克隆的占用的是同一份 浅拷贝!!! money指向的同一块对象里面的m成员 共用一块空间
        System.out.println("更改后===========");
        System.out.println(student);
        System.out.println(student1);
    }

}

通过上面代码运行后 发现 只对克隆的对象内容进行修改后,但有些内容原对象也跟着改变,这即是发生浅拷贝, 拷贝的程度浅,对象拷贝了一份但内容却没有真正拷贝.

age是基本数据类型,拷贝的对象内也存有一份age数据,修改这个age不会影响原对象的age值,name是引用类型数据 指向字符串对象, 而修改拷贝对象内的字符串对象本质是创建了一个新字符串,故也没有影响原对象,

但是Menoy引用指向的一份对象,经过拷贝后 新对象的Menoy引用同样存放着原Menoy对象的地址,此时通过新对象修改Menoy指向的对象内的值,原对象内的Menoy对象内的值也会发生改变

此时的拷贝形式正是浅拷贝,对象并没有完全被拷贝,而如何实现深拷贝呢?

2.实现深拷贝

浅拷贝即拷贝了新对象,但是新对象的内容可能和原对象共用一块空间,故要实现深拷贝,要在原来拷贝的基础上,对可能共用一块空间的内容进行再拷贝一份

在上面代码基础上,使Menoy引用指向不同对象则要对Menoy对象单独进行克隆

class Money implements Cloneable{
    public double m=3.14;

    @Override
    public String toString() {
        return "Money{" +
                "m=" + m +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();   //这里用于给 money克隆一份
    }
}
public class Student implements Cloneable {
    Money money=new Money();
    public String name;
    public int age=18;
    public Student(String name){
        this.name=name;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        student.money=(Money) this.money.clone(); //调用 money的clone方法为其克隆出一份
        return student; //自动向上转型
    }

    @Override
    public String toString() {
        return "Student{" +
                "money=" + money +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

对象内主要是Menoy对象是同一个空间,那么在克隆对象时,先克隆出新Student对象,再根据指定Menoy对象克隆出新的Menoy对象(Menoy也要支持clone)给克隆对象的Menoy引用,最后返回克隆的新对象, 最后实现了深拷贝,两个对象的内容是独立不互不影响的

注意: 除了clone能拷贝对象以外还有其他方法能对对象进行拷贝,如Arrays.copyOf方法能够对指定数组对象进行拷贝,对数组进行拷贝 也会出现深浅拷贝的现象,拷贝的新数组每个引用可能指向的原数组的每个引用指向的对象…

故在拷贝时要注意需要的是深拷贝还是浅拷贝…

三.Object类和深浅拷贝总结

本篇博客介绍了Object类 以及其内部的一些方法:toString(重写前:获取其类的全路径@对象地址,重写后将对象内容转换为字符串形式返回),
equals和hashCode(重写前:判断对象的地址是否相等和根据对象地址生成哈希值,重写后:判断对象指定内容是否相等和根据指定内容获取对象生成的哈希值),
getClass (获取类实例),clone(克隆对象需要注意权限和异常)
以及跟克隆相关的深浅拷贝(对新对象内容进行修改是否会影响原对象的内容)

到此这篇关于Java中的Object类和深浅拷贝的文章就介绍到这了,更多相关Java Object类和深浅拷贝内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java中的Object类详细介绍

    理论上Object类是所有类的父类,即直接或间接的继承java.lang.Object类.由于所有的类都继承在Object类,因此省略了extends Object关键字. 该类中主要有以下方法: toString(),getClass(),equals(),clone(),finalize(), 其中toString(),getClass(),equals是其中最重要的方法. 注意: Object类中的getClass(),notify(),notifyAll(),wait()等方法被定义为f

  • java之Object类用法实例

    本文实例讲述了java中Object类用法.分享给大家供大家参考.具体如下: 1.Object类是所有java类的基类 如果在类的声明中未使用extends关键字指明其基类,则默认基类为Object类,ex: public class Person{ ~~~~~ } 等价于 public class Person extends Object{ ~~~~~ } 2.Object类之equals方法 ①.Object类中定义有: public boolean equals(Object obj)方

  • Java Clone深拷贝与浅拷贝的两种实现方法

    1.首先,你要知道怎么实现克隆:实现Cloneable接口,在bean里面重写clone()方法,权限为public. 2.其次,你要大概知道什么是地址传递,什么是值传递. 3.最后,你要知道你为什么使用这个clone方法. 先看第一条,简单的克隆代码的实现.这个也就是我们在没了解清楚这个Java的clone的时候,会出现的问题. 看完代码,我再说明这个时候的问题. 先看我要克隆的学生bean的代码: package com.lxk.model; /** * 学生类:有2个属性:1,基本属性-S

  • JAVA 深层拷贝 DeepCopy的使用详解

    方法实现很简单,提供两种方式:一种是序列化成数据流,前提是所有对象(对象中包含的对象...)都需要继承Serializable接口,如果都继承了那很容易,如果没有继承,而且也不打算修改所有类,可以用第二种方式. 第二种是将对象序列化为json,通过json来实现拷贝,这种方式需要用到net.sf.json.JSONObject.具体代码如下: 复制代码 代码如下: public class DeepCopy {          /**          * 深层拷贝          *   

  • Java中的深拷贝和浅拷贝介绍

    一.引言   对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去.在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部 数据.Java中有三种类型的对象拷贝:浅拷贝(Shallow Copy).深拷贝(Deep Copy).延迟拷贝(Lazy Copy). 二.浅拷贝 1.什么是浅拷贝   浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝.如果属性是基本类型,拷贝的就是基本类型的值:如果属性是内存地

  • java中关于深拷贝的几种方式总结

    目录 前言 方式1:构造函数深拷贝 方式2:重载Clone()方法深拷贝 方式3:Apache Commons Lang序列化方式深拷贝 方式4:Gson序列化方式深拷贝 方式5:Jackson序列化方式 总结 前言 在java里,当我们需要拷贝一个对象时,有两种类型的拷贝:浅拷贝与深拷贝. 浅拷贝只是拷贝了源对象的地址,所以源对象的值发生变化时,拷贝对象的值也会发生变化. 深拷贝则是拷贝了源对象的所有值,所以即使源对象的值发生变化时,拷贝对象的值也不会改变. 方式1:构造函数深拷贝 我们可以调

  • Java的深拷贝与浅拷贝的几种实现方式

    1.介绍 关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象.可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的所谓值传递或者引用传递将会有更深的理解. 2.浅拷贝 浅拷贝就是获得拷贝对象的引用,而不是正真意义上的拷贝一个对象,例如 A a = new A(); A b = a; 此时引用变量a和b 同时指向了同一个堆中的内存空间,变量b只是复制了实例A的引用地址,并不是重新在堆中开辟了一个新的空间位置,来完整的复制

  • java 深拷贝与浅拷贝机制详解

     java 深拷贝与浅拷贝机制详解 概要: 在Java中,拷贝分为深拷贝和浅拷贝两种.java在公共超类Object中实现了一种叫做clone的方法,这种方法clone出来的新对象为浅拷贝,而通过自己定义的clone方法为深拷贝. (一)Object中clone方法 如果我们new出一个新对象,用一个声明去引用它,之后又用另一个声明去引用前一个声明,那么最后的结果是:这两个声明的变量将指向同一个对象,一处被改全部被改.如果我们想创建一个对象的copy,这个copy和对象的各种属性完全相同,而且修

  • 一文带你了解Java中的Object类及类中方法

    目录 1. Object类介绍 2. 重写toString方法打印对象 3. 对象比较equals方法 4. hashCode方法 1. Object类介绍 Object是Java默认提供的一个类.Java里面除了Object类,所有的类都是存在继承关系的.默认会继承Object父 类.即所有类的对象都可以使用Object的引用进行接收. 范例:使用Object接收所有类的对象 class Person{} class Student{} public class Test { public s

  • 一文带你认识java中的String类

    目录 什么是字符串 字符串常见的赋值方法 直接赋值法 字符串的比较相等 字符串常量池 字符串常量池的实例 字符串的不可变 字符串的常见操作 字符串的比较 字符串的查找 字符串替换 split(String regex) 字符串截取 总结 什么是字符串 字符串或串(String)是由数字.字母.下划线组成的一串字符.一般记为 s="a1a2···an"(n>=0).它是编程语言中表示文本的数据类型.在程序设计中,字符串(string)为符号或数值的一个连续序列,如符号串(一串字符)

  • 一文带你初识java中的String类

    目录 什么是字符串 字符串常见的赋值方法 直接赋值法 构造方法进行创建 字符串的比较相等 字符串常量池 字符串常量池的实例 字符串的不可变 字符串的常见操作 字符串的比较 字符串的查找 字符串替换 字符串拆分 字符串截取 总结 什么是字符串 字符串或串(String)是由数字.字母.下划线组成的一串字符.一般记为 s="a1a2···an"(n>=0).它是编程语言中表示文本的数据类型.在程序设计中,字符串(string)为符号或数值的一个连续序列,如符号串(一串字符)或二进制数

  • 一文带你了解Java中的ForkJoin

    目录 什么是ForkJoin? ForkJoinTask 任务 ForkJoinPool 线程池 工作窃取算法 构造方法 提交方法 创建工人(线程) 例:ForkJoinTask实现归并排序 ForkJoin计算流程 前言: ForkJoin是在Java7中新加入的特性,大家可能对其比较陌生,但是Java8中Stream的并行流parallelStream就是依赖于ForkJoin.在ForkJoin体系中最为关键的就是ForkJoinTask和ForkJoinPool,ForkJoin就是利用

  • 一文带你了解Java中IO流与Guava的使用

    目录 Guava IO 分类 常用的流 示例 Guava中的IO 其他 结束语 Guava IO 日常系统交互中,文件的上传下载都是常见的,一般我们会通过jdk提供的IO操作库帮助我们实现.IO指的是数据相对当前操作程序的入与出,将数据通过 输出流从程序输出,或者通过输入流将数据(从文件.网络.数据等)写入到程序,这里的IO指的是基于流作为载体进行数据传输.如果把数据比作合理的水,河就是IO流,也是数据的载体. Java为我们提供了非常多的操作IO的接口与类,帮助开发者实现不同源间的数据传输,比

  • 一文带你了解Java中的SPI机制

    目录 1: SPI机制简介 2: SPI原理 3: 使用场景 4: 源码论证 5: 实战 6: 优缺点 6.1 优点 6.2 缺点 1: SPI机制简介 SPI 全称是 Service Provider Interface,是一种 JDK 内置的动态加载实现扩展点的机制,通过 SPI 技术我们可以动态获取接口的实现类,不用自己来创建.这个不是什么特别的技术,只是 一种设计理念. 2: SPI原理 Java SPI 实际上是基于接口的编程+策略模式+配置文件组合实现的动态加载机制. 系统设计的各个

  • 你了解Java中的Object类吗

    任何一个类默认继承Object类,就算没有直接继承,最终也会间接继承. Object类,有两种方式找到: 第一种:在源码当中找到 第二种:查阅java类库的帮助文档 Object类中两个重要的方法: boolean equals (Object obj) //判断两个对象是否相等 String toString () //将对象转换成字符串形式 equals方法: 源代码: public boolean equals(Object obj) { return (this == obj); } 作

  • java中的Object类的toSpring()方法

    Object是类层次结构的根,每个类都可以将Object作为超类.所有类都直接或者间接的继承自该类 构造方法:public Object() 回想面向对象中,为什么说子类的构造方法默认访问的是父类的无参构造方法? 因为它们的顶级父类只有无参构造方法 package com.itheima_56; public class Student extends Object{ private String name; private int age; public Student(){ } public

  • 一文带你回顾Java中的垃圾回收机制

    目录 介绍 重要条款: 使对象符合 GC 条件的方法 请求JVM运行垃圾收集器的方式 定稿 让我们举一个真实的例子,在那里我们使用垃圾收集器的概念. 现在获得正确的输出: 总结 介绍 在 C/C++ 中,程序员负责对象的创建和销毁.通常程序员会忽略无用对象的销毁.由于这种疏忽,在某些时候,为了创建新对象,可能没有足够的内存可用,整个程序将异常终止,导致OutOfMemoryErrors. 但是在 Java 中,程序员不需要关心所有不再使用的对象.垃圾回收机制自动销毁这些对象. 垃圾回收机制是守护

随机推荐