最近在學習JAVA知識,通過網上翻看資料,發現原先有的理解不深的東西,漸漸明白了些。對象的使用,在編寫軟件過程中是必不可少的,不知道大家有沒和我一樣,幾乎都是使用new來創建。那么,問題來了,JAVA有幾種創建對象 的方式呢?
- 使用new關鍵字創建。
- 使用Class的newInstance()方法, 位於java.lang包,比如Person類,創建對象可以使用,但是下面的兩種方式不能調用private構造函數,且構造對象的類中必須包含無參構造函數(構造器需可見 visible),否則會報錯,對於捕獲或者未捕獲的異常均由構造器拋出;。
public class person { /** * */ private static final long serialVersionUID = 10L; String name = "Jack"; public person(){ this.name = name + " ma"; System.out.println("construct Person"); } private person(int a,int b) { System.out.println("a:"+a+ " b:" + b); } @Override public String toString() { return name; } } 方法一 //這里的testReflect為包名,Person類在此包下 Class clazz = Class.forName("testReflect.person "); person p = (person ) clazz.newInstance(); 方法二 person p =person .class.newInstance();
- 使用Constructor類的newInstance方法,此方法屬於反射,位於 java.lang.reflect 包,可以調用任何作用域的構造函數,private也可以,且創建對象的類構造函數可以任意。
//調用無參構造函數 ,方式一 person p = person.class.getDeclaredConstructor().newInstance(); //調用無參構造函數 ,方式二 Constructor c1=person.class.getDeclaredConstructor(); c1.setAccessible(true); person p=(person)c1.newInstance();
這里大家思考下,在調用無參構造函數時,方式一和方式二有什么區別? 大家應該看到了c1.setAccessible(true); 這句代碼吧,查看方法的定義包含如下:A value of true indicates that the reflected object should suppress Java language access checking when it is used,意思是為true的時候禁止驗證授權,換句話的理解就是,private的無參構造也可以調用。這就是方式一和方式二的區別,方式一若private作用域修飾,則會報錯。通常會把拋出的異常封裝成InvocationTargetException拋出。
因為以上差異,所以很多框架使用的都是構造器反射的方式獲取對象,像Spring, Guava, Zookeeper, Jackson, Servlet 等。
-
//調用有參構造函數 Constructor c1=person.class.getDeclaredConstructor(new Class[] {int.class,int.class}); 或 Constructor c1=person.class.getDeclaredConstructor(int.class,int.class);
-
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
-
-
- Parameters:
-
parameterTypes
- the parameter array - Returns:
-
The
Constructor
object for the constructor with the specified parameter list - 傳入參數為數組。
-
-
- 使用Clone的方法:無論何時我們調用一個對象的clone方法,JVM就會創建一個新的對象,將前面的對象的內容全部拷貝進去,用clone方法創建對象並不會調用任何構造函數。要使用clone方法,創建對象的類必須實現Cloneable接口並實現其定義的clone方法。關於clone可參考我轉載的JAVA深復制與淺復制。
- 使用反序列化:當我們序列化和反序列化一個對象,JVM會給我們創建一個單獨的對象,在反序列化時,JVM創建對象並不會調用任何構造函數。為了反序列化一個對象,對應類需實現Serializable接口,附上一段具體實現代碼。
import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; public class People implements Serializable{ private String name; public People(){ this.name = "6點A君"; System.out.println("construct people"); } @Override public String toString() { return this.name; } public static void main(String[] args) { People p = new People(); System.out.println(p); ObjectOutputStream oos = null; ObjectInputStream ois = null; try { FileOutputStream fos = new FileOutputStream("test.out"); oos = new ObjectOutputStream(fos); oos.writeObject(p); oos.close(); } catch (Exception e) { e.printStackTrace(); } People p1; try { FileInputStream fis = new FileInputStream("test.out"); ois = new ObjectInputStream(fis); p1 = (People)ois.readObject(); System.out.println(p1); } catch (Exception e) { e.printStackTrace(); } } }