Java 创建对象的四种方式

Java 创建对象的四种方式

一、使用new创建对象

**使用new关键字创建对象应该是最常见的一种方式,但我们应该知道,使用new创建对象会增加耦合度。无论使用什么框架,都要减少new的使用以降低耦合度。 **

package jwx;

/**
 * @ Author     :jwx
 * @ Date       :16:45 2020/5/25
 * @ Description:测试
 * @ Modified By:
 * @Version:1.0
 */
public class Hello {
    public void say(){
        System.out.printf("Hello World!");
    }
}

import jwx.Hello;

/**
 * @ Author     :jwx
 * @ Date       :16:42 2020/5/25
 * @ Description:主类
 * @ Modified By:
 * @Version:1.0
 */
public class Main {
    public static void main(String[] args) {
        Hello hello = new Hello();
        hello.say();
    }
}

在这里插入图片描述

运行结果放出来,这应该每位java选手都会的操作,下面来的不常用的

二、使用反射的机制创建对象

.使用反射机制创建对象的步骤如下:

1、先声明你要创建的对象的类全称;使用Class类的静态方法forName(String.className)加载这个类的字节码(注意,加载字节码不等于实例化对象) ,返回 一个Class对象,这个对象代表的是一个字节码文件。

2、调用这个类对象(字节码)的方法newInstance()方法(注意:这里的这个newInstance方法默认调用默认的构造方法即调用无参的构造方法, 一旦构造方法有参数时,此方法行不通,需要使用构造方法的对象的相关方法来 实例化)实例化类,返回的是Object类型
3、强制转换Object成你所需类型

Hello类不变,修改Main方法下面代码

package jwx;

/**
 * @ Author     :jwx
 * @ Date       :16:56 2020/5/25
 * @ Description:反射机制
 * @ Modified By:
 * @Version:1.0
 */
public class RefelectDemo {
    public static void main(String[] args) {
        try
        {
            Class heroClass = Class.forName("jwx.Hello");
            Hello h =(Hello) heroClass.newInstance();
            h.say();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IllegalAccessException e)
        {
            e.printStackTrace();
        }
        catch (InstantiationException e)
        {
            e.printStackTrace();
        }
    }
}

使用Constructor类的newInstance方法

package jwx;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @ Author     :jwx
 * @ Date       :16:58 2020/5/25
 * @ Description:
 * @ Modified By:
 * @Version:1.0
 */
public class ConsturctorDemo {
    public static void main(String[] args) {
        try
        {
            //获取类对象
            Class heroClass = Class.forName("jwx.Hello");

            //获取构造器
            Constructor constructor = heroClass.getConstructor();
            Hello h =(Hello) constructor.newInstance();
            h.say();
        }
        catch (NoSuchMethodException e)
        {
            e.printStackTrace();
        }
        catch (InvocationTargetException e)
        {
            e.printStackTrace();
        }
        catch (IllegalAccessException e)
        {
            e.printStackTrace();
        }
        catch (InstantiationException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
    }
}

三、采用clone

clone时,需要已经有一个分配了内存的源对象,创建新对象时,首先应该分配一个和源对象一样大的内存空间。要调用clone方法需要实现Cloneable接口

下面我们具体看看Clone方法

Cloneable接口其实就是一个标记接口,只有实现这个接口后,然后在类中重写Object中的clone方法,然后通过类调用clone方法才能克隆成功,如果不实现这个接口,则会抛出CloneNotSupportedException(克隆不被支持)异常。Object中clone方法:

img

这个方法有一个native关键字,没有方法体,但是他与abstract关键字不同,他的方法内容在jvm内存中右具体的实现,java是通过jvm判断是否实现了Cloneable接口。

**clone是首先分配内存,这里分配的内存与调用clone方法对象的内存相同,然后将源对象中各个变量的值,填充到新的对象中,填充完成后,clone方法返回一个新的地址,这个新地址的对象与源对象相同,只是地址不同。 **

克隆分为深度克隆和浅度克隆

下面通过例子来看

创建Dog对象

package jwx;

import jdk.nashorn.internal.objects.annotations.Constructor;
import jdk.nashorn.internal.objects.annotations.Getter;

/**
 * @ Author     :jwx
 * @ Date       :17:06 2020/5/25
 * @ Description:
 * @ Modified By:
 * @Version:1.0
 */

public class Dog {
    private String name;   //姓名
    private int age;       //年龄
    private StringBuffer sex;  //性别

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public StringBuffer getSex() {
        return sex;
    }

    public void setSex(StringBuffer sex) {
        this.sex = sex;
    }
}

然后我们再创建Person对象

package jwx;

/**
 * @ Author     :jwx
 * @ Date       :17:09 2020/5/25
 * @ Description:
 * @ Modified By:
 * @Version:1.0
 */
public class Person implements Cloneable {
    private String name;   //姓名
    private int age;         //年龄
    private Dog dog;         //宠物狗

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", dog=" + dog +
                '}';
    }
    @Override
    public Person clone() throws CloneNotSupportedException {
        Person person = null;
        try {
            person = (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return person;
    }
}

写个测试类来康康

package jwx;

/**
 * @ Author     :jwx
 * @ Date       :17:11 2020/5/25
 * @ Description:克隆测试
 * @ Modified By:
 * @Version:1.0
 */
public class ColneDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1=new Person();
        person1.setAge(20);
        person1.setName("黑哥");
        Dog dog1 = new Dog();
        dog1.setAge(5);
        dog1.setName("小花");
        dog1.setSex(new StringBuffer("男"));
        person1.setDog(dog1);
        System.out.println("person1: "+person1+" person1的hashcode:"+person1.hashCode()+" person1中dog1的hashcode:"+person1.getDog().hashCode());
        Person person2 = person1.clone();  //调用重写的clone方法,clone出一个新的Person ---person2
        System.out.println("person2: "+person2+" person2的hashcode:"+person2.hashCode()+" person2中dog1的hashcode:"+person2.getDog().hashCode());
    }
}

测试结果:

在这里插入图片描述

可以看出person1与person2的hashcode不同,也就是说clone方法并不是把person1的引用赋予person2,而是在堆中重新开辟了一块空间,将person1复制过去,将新的地址返回给person2。

  但是person中dog的hashcode与perosn中dog的hashcode相同,也就是这两个指向了同一个对象,修改person2中的dog会造成person中dog数据的改变。但是修改person2中的基本数据类型与Stirng类型时,不会造成person1中数据的改变.基本数据类型例如int,在clone的时候会重新开辟一个四个字节的大小的空间,将其赋值。而String则由于String变量的唯一性,如果在person2中改变了String类型的值,则会生成一个新的String对象,对之前的没有影响。这就是浅度克隆。

如何实现深度clone? 这里介绍第一种方法,另一种方法是用流的拷贝,我把它放到文章最后面

首先需要让dog重写clone方法,实现cloneable接口

  @Override
    protected Dog clone() throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return (Dog)super.clone();
    }

然后,在Person的clone方法中将Person中的dog对象手动clone一下。

@Override
    public Person clone() throws CloneNotSupportedException {
        Person person = null;
        person = (Person) super.clone();
        person.dog = dog.clone();
        return person;
    }

执行结果:在这里插入图片描述
这里可以看到两个dog的hashcode已经不同了,说明这已经是两个对象了

这就是深度克隆,哈哈,就是这么easy!

四、采用序列化机制

使用序列化时,要实现实现Serializable接口,将一个对象序列化到磁盘上,而采用反序列化可以将磁盘上的对象信息转化到内存中。

package jwx;

import java.io.Serializable;

/**
 * @ Author     :jwx
 * @ Date       :16:45 2020/5/25
 * @ Description:测试
 * @ Modified By:
 * @Version:1.0
 */
//实现Serializable接口
public class Hello implements Serializable {
    public void say(){
        System.out.printf("Hello World!");
    }
}

下面来看测试主函数

package jwx;

/**
 * @ Author     :jwx
 * @ Date       :8:04 2020/5/26
 * @ Description:
 * @ Modified By:
 * @Version:1.0
 */

import java.io.*;
public class Serialize
{
    public static void main(String[] args)
    {
        Hello h = new Hello();

        //准备一个文件用于存储该对象的信息
        File f = new File("hello.obj");

        try(FileOutputStream fos = new FileOutputStream(f);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            FileInputStream fis = new FileInputStream(f);
            ObjectInputStream ois = new ObjectInputStream(fis)
        )
        {
            //序列化对象,写入到磁盘中
            oos.writeObject(h);
            //反序列化对象
            Hello newHello = (Hello)ois.readObject();

            //测试方法
            newHello.say();
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
        }
    }
}

运行结果:输出Hello World!

最后再总结一下:

  • 1.使用new创建对象
    使用new关键字创建对象应该是最常见的一种方式,但我们应该知道,使用new创建对象会增加耦合度。无论使用什么框架,都要减少new的使用以降低耦合度。

  • 2.使用反射的机制创建对象
    使用Class类的newInstance方法

  • 3.采用clone
    clone时,需要已经有一个分配了内存的源对象,创建新对象时,首先应该分配一个和源对象一样大的内存空间。要调用clone方法需要实现Cloneable接口

  • 4.采用序列化机制
    使用序列化时,要实现实现Serializable接口,将一个对象序列化到磁盘上,而采用反序列化可以将磁盘上的对象信息转化到内存中。

    哈哈,现在创建对象,不会只用new了吧,我个人比较推荐反射机制创建对象

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值