【1】创建对象的5种方式
① 使用new关键字
这是最常见的创建对象的方法,并且也非常简单。通过使用这种方法我们可以调用任何我们需要调用的构造函数。
Employee emp1 = new Employee();
② 使用class类的newInstance方法
我们也可以使用class类的newInstance()方法来创建对象。
此newInstance()方法调用无参构造函数以创建对象。
我们可以通过newInstance() 用以下方式创建对象:
Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee").newInstance(); //或者 Employee emp2 = Employee.class.newInstance();
③ 使用构造函数类的 newInstance方法
与使用class类的newInstance()方法相似,java.lang.reflect.Constructor类中有一个可以用来创建对象的newInstance()函数方法。
通过使用这个newInstance()方法我们也可以调用参数化构造函数和私有构造函数。
Constructor<Employee> constructor = Employee.class.getConstructor(); Employee emp3 = constructor.newInstance();
这些 newInstance() 方法被认为是创建对象的反射手段。
实际上,内部类的newInstance()方法使用构造函数类的 newInstance() 方法。
这就是为什么后者是首选并且使用不同的框架如Spring, Hibernate, Struts等。
④ 使用clone方法
实际上无论何时我们调用clone() 方法,Java虚拟机都为我们创建了一个新的对象并且复制了之前对象的内容到这个新的对象中。
使用 clone()方法创建对象不会调用任何构造函数。为了在对象中使用clone()方法,我们需要在其中实现可克隆类型并定义clone()方法。
Employee emp4 = (Employee) emp3.clone();
⑤ 使用反序列化
无论何时我们对一个对象进行序列化和反序列化,Java虚拟机都会为我们创建一个单独的对象。在反序列化中,Java虚拟机不会使用任何构造函数来创建对象。
对一个对象进行序列化需要我们在类中实现可序列化的接口。
ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj")); Employee emp5 = (Employee) in.readObject();
正如我们在以上的字节代码片段中所看到的,除第一种被转换为一个新的函数和一个 invokespecial 指令以外,其它4种方法都被调用并转换为invoke virtual。
⑥ 代码示例
让我们来看看准备创建对象的 Employee 类:
class Employee implements Cloneable, Serializable { private static final long serialVersionUID = 1L; private String name; public Employee() { System.out.println("Employee Constructor Called..."); } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public String toString() { return "Employee [name=" + name + "]"; } @Override public Object clone() { Object obj = null; try { obj = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return obj; } }
在下面的Java程序中我们用5种方式来创建 Employee对象。
public class ObjectCreation { public static void main(String... args) throws Exception { // By using new keyword Employee emp1 = new Employee(); emp1.setName("Naresh"); System.out.println(emp1 + ", hashcode : " + emp1.hashCode()); // By using Class class's newInstance() method Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee") .newInstance(); // Or we can simply do this // Employee emp2 = Employee.class.newInstance(); emp2.setName("Rishi"); System.out.println(emp2 + ", hashcode : " + emp2.hashCode()); // By using Constructor class's newInstance() method Constructor<Employee> constructor = Employee.class.getConstructor(); Employee emp3 = constructor.newInstance(); emp3.setName("Yogesh"); System.out.println(emp3 + ", hashcode : " + emp3.hashCode()); // By using clone() method Employee emp4 = (Employee) emp3.clone(); emp4.setName("Atul"); System.out.println(emp4 + ", hashcode : " + emp4.hashCode()); // By using Deserialization // Serialization ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj")); out.writeObject(emp4); out.close(); //Deserialization ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj")); Employee emp5 = (Employee) in.readObject(); in.close(); emp5.setName("Akash"); System.out.println(emp5 + ", hashcode : " + emp5.hashCode()); } }
此程序输出结果如下:
Employee Constructor Called... Employee [name=Naresh], hashcode : -1968815046 Employee Constructor Called... Employee [name=Rishi], hashcode : 78970652 Employee Constructor Called... Employee [name=Yogesh], hashcode : -1641292792 Employee [name=Atul], hashcode : 2051657 Employee [name=Akash], hashcode : 63313419
【2】this与super
① this关键字的用法
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指
针。
this的用法在java中大体可以分为3种:
- 普通的直接引用,this相当于是指向当前对象本身。
- 形参与成员名字重名,用this来区分:
- 引用本类的构造函数
② super关键字的用法
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离
自己最近的一个父类。
super也有三种用法:
普通的直接引用
与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。
子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分
引用父类构造函数
super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
③ this与super的区别
super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
super()和this()均需放在构造方法内第一行。
尽管可以用this调用一个构造器,但却不能调用两个。
this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。