首页 > 编程知识 正文

创建对象的那些事英文,创建对象用什么方法

时间:2023-05-05 17:47:07 阅读:273314 作者:1026

文章目录 要不要在for循环内部new第一种情况 对于new的调用只存在于for循环以内第二种情况 对于new的调用不止存在于for循环以内外部也有调用 new 和 clone的区别 哪个更快new一个对象的过程clone 对象

要不要在for循环内部new 第一种情况 对于new的调用只存在于for循环以内

对象的保存位置是在堆内存中, p只是一个记录了堆地址的4个字节的引用 p存在的位置是栈内存
基与这个点我们可以画图表示下面的内存情况

public void demo() { Persion p = null; for (int i = 0; i < 1000; i++) { p = new Persion(); p.setAge(i); } }

public void demo() { for (int i = 0; i < 1000; i++) { Persion p = new Persion(); p.setAge(i); } }

对象new了1000次

public void demo1() { Persion p = new Persion(); for (int i = 0; i < 10; i++) { p.setAge(i); } }

对象new了1次

通过比对就可以很明显的发现第三种方法是最节省jvm内存的.第一种和第二种的区别在于栈空间内变量引用的数据,第一种只有一个变量,第二种有1000个变量.

第二种情况 对于new的调用不止存在于for循环以内外部也有调用

对于这种情况上面的第三种写法就不可以 只能是前两种写法

public void demo() { List list= new ArrayList(); Persion p = null; for (int i = 0; i < 10; i++) { p = new Persion(); p.setAge(i); list.add(p); } list.stream().forEach(per -> { // 业务处理 System.out.println(per.toString()); }); }

p只是一个引用,每次循环保存到集合里面的都是一个新的地址值

public void demo() { List list= new ArrayList(); for (int i = 0; i < 10; i++) { Persion p = new Persion(); p.setAge(i); list.add(p); } list.stream().forEach(p -> { // 业务处理 System.out.println(p.toString()); }); }

基与java gc的考虑
第一 堆的角度 因为堆内存中必定要分配1000个对象大小的空间,两者的是没有区别的
第二 生命周期角度 第一个对象的作用域是整个方法 第二个对象的作用域是在for循环以内
他们不可达阶段是一致的,(不可达的对象才会被gc)
对象的生命周期 创建 -> 应用 -> 不可见 -> 不可达 -> 收集 ->终结 ->对象内存空间重新分配
基与栈的考虑
栈的管理是jvm自己管理的,没有gc的参与,一个线程对应一个栈,一个方法对应一个栈帧,方法执行完成之后自动出站,栈是先进后出,栈内存的大小可以通过jvm配置的参数来设定 -Xss256k,栈内存的溢出一般都是因为递归调用太深,或者递归调用使用不当.一个方法里面定义的变量再这个方法出站的时候,就一起跟着消失了.
所以我认为上面的两种写法几乎是没有差别的.

new 和 clone的区别 哪个更快 new一个对象的过程

默认这个类第一次被加载 之前没有加过,new对象的时候首先会检查class是否被加载到方法区,如果加载过了就不会在加载,如果没有加载过回重新加载
1.加载:类加载器把类加载到jvm内并将类的信息保存到方法区
2.验证 准备 解析 这三个过程也叫做链接
3.初始化:初始化的时候为static 变量 static{代码块}赋值 先父类初始化赋值 再后子类初始化赋值
1->3是类加载的过程
4.给对象分配堆内存 有两种方式 指针碰撞 空闲列表
5.给变量赋默认值 从方法区内拷贝变量的引用 给堆内的对象赋默认值
6.最后执行构造方法 先执行父类的构造方法再执行子类的构造方法,如果继承关系比较负载父类还有父父父父类的话,要从顶级的父类开始执行,这种情况是比较耗时的.

clone 对象

Java 中的clone 需要对象实现 Cloneable
clone 默认是浅拷贝 对于基本数据类型拷贝的是值,对于引用数据类型拷贝的是引用,两个clone的对象内部还是存在联系的.

String 是引用数据类型 但是String很特别是不能被修改的,"zhangsan"是不能被修改的,所以这个例子中不会有什么问题.
如果name属性换成一个Car对象 car里面有color 如果p1修改了自己的car的颜色,p2的car颜色也会被修改所以存在一定的隐患

public class Persion implements Cloneable { private String name; private int age; private Car car; @Override protected Persion clone() throws CloneNotSupportedException { return (Persion)super.clone(); } public class Car { private String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; } public static void main(String[] args) throws Exception{ Persion p1= new Persion(); Car car= new Car(); car.setColor("yellow"); p1.setCar(car); p1.setName("zhangsan"); Persion p2 = p1.clone(); System.out.println(p1==p2); System.out.println(p2.toString()); p1.getCar().setColor("red"); System.out.println(p2.toString()); }

执行结果

falsePersion{name='zhangsan', age=0,car.color=yellow}Persion{name='zhangsan', age=0,car.color=red}

clone与new的区别在于clone不用执行对象的构造方法,当对象的继承关系复杂 父类和自己的构造方法内操作比较多(比如初始化了好多的对象);这种情况clone的效率会明显高于new,如果是一个简单的对象简单的构造方法,初始化的是时间基本一样(亲自测过 clone 不见得一定快);

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。