Java集合面试题_java是什么

Java集合面试题_java是什么Java中的浅拷贝与深拷贝很多时候,我们期望去拷贝某个对象的副本。在Java中如果使用=赋值操作,其实际上会让两个引用变量指向同一个对象;而如果重新new一个新对象,再对各字段进行赋值操作时,将十分繁琐。为此在Java的Object类中,提供了一个clone方法,其可拷贝对象副本clone方法与Cloneable接口Cloneable接口的源码如下publicinterfaceCloneable{}注释第一段一个类实现了Cloneable接口,以向Object.c

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

Java 中的拷贝

由于java中只有值传递,u2 = u1,拿到的是u1的地址,u2和u1指向的是同一个内存区域,u1改变值,u2也会改变。

        UseCloneable u1 = new UseCloneable();
        UseCloneable u2 = u1;
        u1.a = 10;

在这里插入图片描述

那么我们怎么构造一个新的对象呢

        u2 = new UseCloneable();
        u2.a = u1.a;

但是如果有20个30个字段,这么写就比较臃肿。

clone 方法 与 Cloneable 接口

在这里插入图片描述


通俗理解

实现该接口并重写方法来实现拷贝。没实现该接口调用clone方法会报错。

Ojbect类中的clone方法

访问修饰符为protected ,只能由子类或者同包的类调用。

protected native Object clone() throws CloneNotSupportedException;

我们尝试调用clone方法,会提示CloneNotSupportedException

public static void main(String[] args) throws CloneNotSupportedException{ 
   
        UseCloneable u1 = new UseCloneable();
        u1.clone();
-------
Exception in thread "main" java.lang.CloneNotSupportedException: com.example.miccommon.collection.UseCloneable
	at java.lang.Object.clone(Native Method)
	at com.example.miccommon.collection.UseCloneable.main(UseCloneable.java:16)

实现接口实现拷贝过程

@Data
public class UseCloneable implements Cloneable { 
   

    private int a;
    private int b;
    private int c;
    private int d;
    private int e;
    private int f;
    private int g;

    public static void main(String[] args) throws CloneNotSupportedException { 
   

        UseCloneable vvvv = new UseCloneable();
        vvvv.setA(10);
        vvvv.setB(12);
        vvvv.setC(14);
        vvvv.setD(16);
        vvvv.setE(18);
        vvvv.setF(20);
        vvvv.setG(22);
        UseCloneable clone = (UseCloneable) vvvv.clone();
        System.out.println(clone);
    }

    @Override
    public String toString() { 
   
        return "UseCloneable{" +
                "a=" + a +
                ", b=" + b +
                ", c=" + c +
                ", d=" + d +
                ", e=" + e +
                ", f=" + f +
                ", g=" + g +
                '}';
    }
}
-------
UseCloneable{ 
   a=10, b=12, c=14, d=16, e=18, f=20, g=22}

可以看到是两个不同的对象

在这里插入图片描述

重写clone方法,来自定义克隆内容。

  @Override
    protected Object clone() throws CloneNotSupportedException { 
   
        UseCloneable clone = (UseCloneable) super.clone();
        clone.setA(999);
        return clone;
    }
-------
UseCloneable{ 
   a=999, b=12, c=14, d=16, e=18, f=20, g=22}

ArrayList 中相关的实现

public Object clone() { 
   
        try { 
   
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) { 
   
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
        ArrayList<Object> objects = new ArrayList<>();
        objects.add("123");
        Object o = objects.clone();
        System.out.println(o);

在这里插入图片描述

深拷贝

构造一个类Deep,通过clone拷贝。

@Data
public class UseCloneable implements Cloneable { 
   

    Deep deep;


    public static void main(String[] args) throws CloneNotSupportedException { 
   
        UseCloneable source = new UseCloneable();
        source.deep = new Deep();
        UseCloneable target = (UseCloneable) source.clone();
        System.out.println(target);
    }

}

class Deep { 
   

}

虽然source和target已经不是同一个对象,但是两个对象中的deep都是同一个指向。

在这里插入图片描述

我们稍作改造来看看有什么影响,在Deep类中加入属性A。

@Data
public class UseCloneable implements Cloneable { 
   

    Deep deep;

    public static void main(String[] args) throws CloneNotSupportedException { 
   
        UseCloneable source = new UseCloneable();
        source.deep = new Deep();
        source.deep.setA(10);
        UseCloneable target = (UseCloneable) source.clone();
        System.out.println(target);
        source.deep.setA(5);
        System.out.println(target);
    }

}

@Data
class Deep { 
   

    private int a ;

}
--------
UseCloneable(deep=Deep(a=10))
UseCloneable(deep=Deep(a=5))

对source的改动会影响到target中deep的字段,这样肯定是不合理的于是我们。

我们对代码进行改动

@Data
public class UseCloneable implements Cloneable { 
   

    Deep deep;

    public static void main(String[] args) throws CloneNotSupportedException { 
   
        UseCloneable source = new UseCloneable();
        source.deep = new Deep();
        source.deep.setA(10);
        UseCloneable target = (UseCloneable) source.clone();
        System.out.println(target);
        source.deep.setA(5);
        System.out.println(target);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException { 
   
        UseCloneable target = (UseCloneable) super.clone();
        Deep deep = target.getDeep();
        if (deep != null){ 
   
            Deep targetDeep = (Deep) target.getDeep().clone();
            target.setDeep(targetDeep);
        }
        return target;
    }
}

@Data
class Deep implements Cloneable { 
   

    private int a;

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

可以看到两个对象的deep的指向已经改变。

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/182246.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • navicat mac激活码-激活码分享

    (navicat mac激活码)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容https://javaforall.net/100143.htmlIntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,上面是详细链接哦~23LNPMIJZT-eyJsaWNlb…

    2022年3月29日
    97
  • linux下杀死全部进程,linux下批量杀死进程[通俗易懂]

    linux下杀死全部进程,linux下批量杀死进程[通俗易懂]psaux|greppython|grep-vgrep|cut-c9-15|xargskill-15管道符“|”用来隔开两个命令,管道符左边命令的输出会作为管道符右边命令的输入。下面说说用管道符联接起来的几个命令:“psaux”是linux里查看所有进程的命令。这时检索出的进程将作为下一条命令“greppython”的输入。“greppython”的输出结果是,所有含有关键…

    2022年9月21日
    2
  • String与StringBuffer的区别

    String与StringBuffer的区别String与StringBuffer的区别简单地说,就是一个变量和常量的关系。StringBuffer对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。StringBuffer的内部实现方式和String不同,StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。所以在实际使用时,如果经常需要对一个字符串进行修改,例如插入、删除等操作,使用StringBuffer要更加适合一些。String:在String类中没有用来改变已有字

    2022年9月21日
    2
  • pycharm运行py文件_Pycharm运行

    pycharm运行py文件_Pycharm运行当我们在pycharm上完成我们的项目之后,我们应该如何运行这个项目的呢?方法一:点击三角线绿色按钮,运行run(运行程序)方法二:使用快捷键Ctrl+shift+10,效果一样,同样也能在屏幕打印helloworld。方法三:使用cmd命令,打开cmd终端,进入工程所在目录,执行命令:python<py文件>。方法四:切换到Terminal窗口…

    2022年8月26日
    5
  • 智能小车设计规划_智能循迹避障小车设计

    智能小车设计规划_智能循迹避障小车设计摘要该课题主要基于单片机的循迹、避障、WiFi、蓝牙等功能的智能小车,在一些特殊环境下有着特殊的意义。硬件控制以arduino为控制核心。采用超声波避障和红外避障传感器共同完成寻迹、避障功能,并将相关信号传送给单片机,经单片机控制系统分析判断后控制驱动芯片驱动直流电机实现小车前进、后退、左转、右转,停止。软件采用移植性较好的c语言编写,通过手机蓝牙App实现对智能小车的控制。通过TCP/UD协…

    2022年10月18日
    2
  • datagrip安装教程与激活_激活

    datagrip安装教程与激活_激活Datagrip激活码最新破解教程,Mac版激活至2299年,Datagrip激活码2021.3.3

    2022年4月20日
    760

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号