java中新建对象的五种方式

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/luoyanglizi/article/details/50791907

前言

面试的时候被问到Java中新建对象的方式有哪些,一阵语噎。脑子里只想起一个new的方式创建对象,这真是个悲剧。

正文

new关键字创建对象

这一种自然是不必多说了,大家都非常的熟悉。

MyClass myClass = new MyClass();

通过实现Cloneable接口调用clone()方法

这种方式相对就用的比较的少了,不知道也无可厚非。
实现步骤:

  • 将想要克隆的对象实现Cloneable接口
  • 根据当前对象clone新的对象
public class MyClass implements Cloneable{
    /**
     *getter和setter省略
     */
    public String mName; 

    /**
     *getter和setter省略,为了下一个栗子
     */
    public MyFriendClass mMyFriend;  

    private MyClass mClass;  
    public MyClass cloneSomething() {  
        try {  
            mClass= (Something)this.clone();  
        } catch (CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return mClass;
    }  
}  
  • 此处我们实现了没有使用new关键字也创建了对象。
  • clone()方法在Object类中是protected的,所以它只能在object的子类中或相同包名下调用,所在在这里它在MyClass类中被相当于重写了。
  • MyClass类必须实现Cloneable接口,不然会报CloneNotSupportedException的错误。
  • clone()方法进行的克隆是浅克隆,意思是在克隆的时候仅仅只考虑要克隆的目标对象,而不考虑其引用的对象。举个栗子:
//MyFriendClass就不写出来了,里面就只有一个private String mName和它的getter和setter

MyFriendClass myFriend = new MyFriendClass();
myFriend.setName = "lumia";

MyClass myClass = new MyClass();
myClass.setName("lypeer");
myClass.setMyFriend(myFriend);

MyClass myClassCopy = myClass.cloneSomething();

Log.d("MyClassTest" , myClassCopy.getName());//输出为lypeer
Log.d("MyClassTest" , myClassCopy.getMyFriend().getName);//输出为lumia

//在克隆过来的对象里面修改其引用的对象的值,会发现原对象所引用的值也发生了改变
myClassCopy.getMyFriend().setName("Toxni");
Log.d("MyClassTest" , myClass .getName());//输出为lypeer
Log.d("MyClassTest" , myClass .getMyFriend().getName);//输出为Toxni

也就是说如果clone的原本对象里面有应用其他的对象的话,由于clone是浅克隆的,clone得到的对象将与原对象共享引用的对象,但是非引用的对象使相互独立的。
那么如何实现深克隆呢?

  • 使被引用的对象也实现Cloneable接口,并且重写clone方法,使得被引用的对象也可被clone,然后在clone原对象的时候将被引用的对象也clone一遍,将clone得到的被引用对象设置成为clone得到的目标对象的属性值,相当于是原本clone是不会考虑应用对象的,那要考虑的话我们就手动把它clone一遍。(好像说的有点绕……)
  • 使用序列化与反序列化来做深克隆。

使用Class.forName()

MyClass myClass = (MyClass)class.forName("com.lypeer.blog.myclass").newInstance();
  • 调用Class.forName()方法的时候实际上已经load了MyClass,并且对它进行了初始化(也就是类中的static变量或方法已经run过了),但是还没有产生任何对象。
  • 方法底层还是使用了ClassLoader,但是是使用的调用此方法的类的ClassLoader。
  • 这种方式只能获得non-primitive class。
  • 由于是采用newInstance()方法生成新的类,目标类必须有public default constructor。如果目标类没有public default constructor,就会抛出一个InstantiationException。

使用ClassLoader.loadClass()

MyClass myClass = MyClass.class.getClassLoader().loadClass("com.lypeer.blog.myclass").newInstance();
  • ClassLoader.loadClass()与Class.forName()一个很大的区别就是loadClass()执行完毕之后虽然已经load了MyClass,但是并没有对它进行初始化。同样方法结束的时候还没有产生任何对象。
  • 使用的是系统的class loader。
  • 由于是采用newInstance()方法生成新的类,目标类必须有public default constructor。如果目标类没有public default constructor,就会抛出一个InstantiationException。

通过Object deserialization

MyClass myClass = new MyClass();
myClass.setName("lypeer");

//生成ObjectOutputStream对象
FileOutputStream out = new FileOutputStream("lypeer.txt");
ObjectOutputStream oout = new ObjectOutputStream(out);

//将要复制的对象写入ObjectOutputStream里面
oout.writeObject(myClass);
oout.flush();

//将写入的对象从流里面读出
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("lypeer.txt"));
MyClass myClassCopy = (MyClass) ois.readObject();

这种拷贝就是深拷贝。

结语

综上,Java中共有五种方式来新建对象,其中大致可以分为两类

  • 克隆类
    • 这种方式新建对象需要有原有的对象,然后新的对象使根据原有对象进行克隆得到的。
    • 又分为浅克隆和深克隆,浅克隆为实现Cloneable接口然后使用clone方法,深克隆为deserialization得到对象。
    • 浅克隆也可手动改为深克隆。
  • 非克隆类
    • 这种方式新建对象不需要原有对象。
    • 通过new关键字或者通过类名直接生成。
    • 通过类名生成的两种方式也有细微的区别和局限性。

That’s all.

Ps : 如果大家知道有别的方式新建对象的话欢迎指出。

猜你喜欢

转载自blog.csdn.net/luoyanglizi/article/details/50791907
今日推荐