本文概述
- 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 keyword
System.out.println(obj.str);
}
}
输出:
2)Java Class.newInstance()方法
Java Class.newInstance()是Class类的方法。 Class类属于java.lang包。它创建此Class对象表示的类的新实例。它返回新创建的类实例。
句法
public T newInstance() throws IllegalAcccessException, InstantiationException
如果无法访问该类或其无效构造函数, 则抛出IllegalAccessException。如果Class表示抽象类, 接口, 数组类或原始类型, 则还会引发InstantiationException。
例
public class NewInstanceExample
{
String str="hello";
public static void main(String args[])
{
try
{
//creating object of class
NewInstanceExample obj= NewInstanceExample.class.newInstance();
System.out.println(obj.str);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
输出:
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();
}
}
}
输出:
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 object
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
String name = "Microprocessor";
public static void main(String[] args)
{
CloneExample obj1 = new CloneExample(); //creating object of class
try
{
CloneExample obj2 = (CloneExample) obj1.clone();
System.out.println(obj1.name);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
输出:
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 object
out.close(); //closes the ObjectOutputStream
file.close(); //closes the file
System.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 object
is.close(); //closes the ObjectInputStream
file.close(); //closes the file
System.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克隆的概念
在OOP中, 复制对象意味着创建现有对象的克隆。复制对象有很多方法。其中两个是-复制构造函数和克隆。 Java有两种类型的克隆:
- 浅克隆
- 深克隆
深拷贝和浅拷贝都是对象克隆的类型。当谈论一个对象时, 我们将其视为一个无法进一步细分的单元。
假设我们有一个Student对象。学生对象包含其他对象, 如下图所示。学生对象包含名称和地址对象。 Name包含FirstName和LastName对象, Address对象由Street和city对象组成。当我们谈论学生时, 我们所谈论的是整个对象网络。
当我们想要修改或移动对象同时仍保留原始对象时, 将创建对象的克隆。
浅克隆
- 每当我们使用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 variable
private int number;
public Street(Street otherStreet)
{
this.name=otherStreet.name;
this.number=otherStreet.number;
}
}
Street对象具有两个实例变量名称和编号。该数字是原始整数值, 而不是对象。无法共享。创建第二个实例变量时, 我们将自动创建一个独立副本。在上面的代码中, 字符串是一个不可变的对象, 即一旦创建, 就无法再更改。因此, 我们可以共享它而无需创建它的深层副本。
评论前必须登录!
注册