用Java创建对象的几种方法

本文概述

  • 1)Java新操作员
  • 2)Java Class.newInstance()方法
  • 3)构造器类的Java newInstance()方法
  • 4)Java Object.clone()方法
  • 5)Java对象序列化和反序列化
  • Java克隆的概念
用Java创建对象有五种不同的方法:
  • Java新运算符
  • Java Class.newInstance()方法
  • 构造函数的Java newInstance()方法
  • Java Object.clone()方法
  • Java对象序列化和反序列化
1)Java新操作员 这是用Java创建对象的最流行的方法。在新运算符之后, 还会调用构造函数, 以初始化新对象。创建对象时, 它会占用堆中的空间。
句法
class_name object_name = new class_name()

Java new运算符示例
public class A{String str="hello"; public static void main(String args[]){A obj=new A(); //creating object using new keywordSystem.out.println(obj.str); }}

输出:
用Java创建对象的几种方法

文章图片
2)Java Class.newInstance()方法 Java Class.newInstance()是Class类的方法。 Class类属于java.lang包。它创建此Class对象表示的类的新实例。它返回新创建的类实例。
句法
public T newInstance() throws IllegalAcccessException, InstantiationException

如果无法访问该类或其无效构造函数, 则抛出IllegalAccessException。如果Class表示抽象类, 接口, 数组类或原始类型, 则还会引发InstantiationException。
【用Java创建对象的几种方法】
public class NewInstanceExample{String str="hello"; public static void main(String args[]){try{//creating object of classNewInstanceExample obj= NewInstanceExample.class.newInstance(); System.out.println(obj.str); }catch(Exception e){e.printStackTrace(); }}}

输出:
用Java创建对象的几种方法

文章图片
3)构造器类的Java newInstance()方法 Java Constructor类还具有类似于Class类的newInstance()方法的newInstance()方法。 newInstance()方法属于java.lang.reflect.Constructor类。这两种newInstance()方法都被称为创建对象的反射方式。实际上, Class类的newInstance()方法在内部使用了Constructor类的newInstance()方法。该方法返回通过调用构造函数创建的新对象。
句法
public T newInstance(Objects...initargs)

newInstance()方法引发以下异常:
  • IllegalAccessException:如果构造函数不可访问。
  • IllegalArgumentException:如果实际参数和形式参数的数量不同。
  • InstantiationException:如果类构造函数表示一个抽象类。
  • InvocationTargetException:如果基础构造函数引发异常。
  • ExceptionInInitializerError:如果此方法引发的初始化失败。

import java.lang.reflect.Constructor; public class NewInstanceExample1{String str="hello"; public static void main(String args[]){try{Constructor< NewInstanceExample1> obj =NewInstanceExample1.class.getConstructor(); NewInstanceExample1 obj1 = obj.newInstance(); System.out.println(obj1.str); }catch(Exception e){e.printStackTrace(); }}}

输出:
用Java创建对象的几种方法

文章图片
4)Java Object.clone()方法 Java clone()方法创建一个现有对象的副本。它在Object类中定义。它返回此实例的克隆。有关clone()方法的两个最重要的点是:
  • 使用clone()方法时, 必须实现Cloneable接口。它在java.lang包中定义。
  • clone()方法必须被其他类覆盖。
当我们在类中使用clone()方法时, 该类必须调用super.clone()以获得克隆的对象引用。
句法
protected Object clone() throws CloneNotSupportedException

如果Object类不支持Cloneable接口, 则此方法将引发CloneNotSupportedException。当覆盖clone()方法的子类指示无法克隆实例时, 也会引发此异常。

public class CloneExample implements Cloneable { //creates and returns a copy of this objectprotected Object clone() throws CloneNotSupportedException { return super.clone(); } String name = "Microprocessor"; public static void main(String[] args) { CloneExample obj1 = new CloneExample(); //creating object of classtry{ CloneExample obj2 = (CloneExample) obj1.clone(); System.out.println(obj1.name); } catch (Exception e) { e.printStackTrace(); } } }

输出:
用Java创建对象的几种方法

文章图片
5)Java对象序列化和反序列化 一个类必须实现属于java.io包的Serializable接口。 Serializable接口没有任何方法和字段。它们为班级增加了特殊的行为。 Marker接口在Java 8中不使用。它被Annotations取代。
每当我们序列化和反序列化对象时, JVM都会创建一个单独的空间。它不使用任何构造函数来创建对象。
对象序列化
ObjectOutputStream类用于序列化对象。序列化是将对象转换为字节序列的过程。
ObjectOutputStream类的writeObject()方法序列化对象, 然后将指定的对象写入ObjectOutputStram类。该方法的签名是:
public final void writeObject(Object obj) throws IOException

该方法接受一个对象作为参数。
对象反序列化
根据字节序列创建对象的过程称为对象反序列化。 ObjectInputStream类的readObject()方法从ObjectInputStram类读取一个对象并将其反序列化。该方法的签名是:
public final Object readObject() throws IOException

该方法不接受任何参数。它返回从流中读取的对象。该方法引发以下异常:
  • ClassNotFoundException:如果找不到序列化的类。
  • InvalidClassException:序列化使用的类出了点问题。
  • IOException:任何与输入/输出相关的常规异常。
  • OptionalDataException:如果在流而不是对象中找到原始数据。

在下面的示例中, 我们首先序列化了对象, 然后反序列化了对象。
import java.io.*; class Demo implements Serializable { public int i; public String s; public Demo(int i, String s) //default constructor{ this.i = i; this.s = s; }} public class DeserializationExample { public static void main(String[] args) {Demo object = new Demo(8, "srcmini"); String filename = "Demofile.ser"; //specified file name (must have extension .ser)/*-----------------Serialization----------*/try{FileOutputStream file = new FileOutputStream(filename); //Saving of object in the file ObjectOutputStream out = new ObjectOutputStream(file); out.writeObject(object); //serialize objectout.close(); //closes the ObjectOutputStreamfile.close(); //closes the fileSystem.out.println("Object serialized"); } catch(IOException e) { e.printStackTrace(); } Demo obj = null; /*-----------------Deserialization--------*/try{FileInputStream file = new FileInputStream(filename); // reading an object from a file ObjectInputStream is = new ObjectInputStream(file); obj = (Demo)is.readObject(); //deserialize objectis.close(); //closes the ObjectInputStreamfile.close(); //closes the fileSystem.out.println("Object deserialized "); System.out.println("number = " + obj.i); System.out.println("string = " + obj.s); } catch(IOException e) { System.out.println("IOException is caught"); } catch(ClassNotFoundException e) { System.out.println("ClassNotFoundException is caught"); }} }

输出:
用Java创建对象的几种方法

文章图片
Java克隆的概念 在OOP中, 复制对象意味着创建现有对象的克隆。复制对象有很多方法。其中两个是-复制构造函数和克隆。 Java有两种类型的克隆:
  • 浅克隆
  • 深克隆
深拷贝和浅拷贝都是对象克隆的类型。当谈论一个对象时, 我们将其视为一个无法进一步细分的单元。
假设我们有一个Student对象。学生对象包含其他对象, 如下图所示。学生对象包含名称和地址对象。 Name包含FirstName和LastName对象, Address对象由Street和city对象组成。当我们谈论学生时, 我们所谈论的是整个对象网络。
用Java创建对象的几种方法

文章图片
当我们想要修改或移动对象同时仍保留原始对象时, 将创建对象的克隆。
浅克隆
  • 每当我们使用clone()方法的默认实现时, Java都会使用浅层克隆。
  • 浅层克隆对象会创建主要对象的克隆, 但不会复制内部对象。
  • 内部对象在原始对象及其副本之间共享。
例如, 如果要创建学生的浅表副本, 则应创建学生的第二个对象。但是两个对象共享相同的名称和地址。考虑以下示例:
public class Student{private Name name ; private Address address; public Student(Student orgStudent){this.name=orgStudent.name; this.address=orgStudent.address; }}

浅表副本的缺点是两个对象不是独立的。当我们修改一个Student的Name对象时, 它也会同时修改另一个Student对象。
在下面的示例中, 我们有一个带有参考变量mba的Student对象;然后我们制作MBA的副本, 创建第二个Student对象mca。如果mca尝试通过修改其Address对象来移动moveOut(), 则mba随之移动。
Student mba=new Student(new Name(...), new Address(...)); Student mca=new Student(mba); mca.moveOut(new Street(...), new City(...));

这是因为mba和mca对象共享相同的Address对象。如果我们更改一个对象中的地址, 它将同时修改两个对象。
深克隆
  • 深克隆是对象的完全独立的副本。
  • 因此, 对于深层复制, 我们需要确保所有成员类也都实现Cloneable接口, 并重写Object类的clone()方法。
当我们修改一个Student对象的Address对象时, 它不会修改另一个Student对象。在下面的代码中, 我们可以看到, 我们不仅在Student对象上使用了复制构造函数, 而且还在内部对象上使用了复制构造函数。
public class Student{private Name name ; private Address address; public Student(Student otherStudent){this.name=new Name(otherStudent.name); this.address=new Address(otherStudent.address); }}

要创建深度克隆, 我们需要继续复制所有Student对象的嵌套元素, 直到只有基本类型和Immutable为止。
public class Street{private String name; //instance variableprivate int number; public Street(Street otherStreet){this.name=otherStreet.name; this.number=otherStreet.number; }}

Street对象具有两个实例变量名称和编号。该数字是原始整数值, 而不是对象。无法共享。创建第二个实例变量时, 我们将自动创建一个独立副本。在上面的代码中, 字符串是一个不可变的对象, 即一旦创建, 就无法再更改。因此, 我们可以共享它而无需创建它的深层副本。

    推荐阅读