創建對象:
1、使用Class對象的newInstance()方法創建該Class對象的實例,此時該Class對象必須要有無參數的構造方法。
2、使用Class對象獲取指定的Constructor對象,再調用Constructor的newInstance()方法創建對象類的實例,此時可以選擇使用某個構造方法。如果這個構造方法被私有化起來,那么必須先申請訪問,將可以訪問設置為true;
Eg:
最簡單的:
package junereflect624;
class User{
/*private User(){//將默認的構造方法私有化的話就不可以再創建對象,兩種方法都是這樣
}*/
public String toString() {
return "User對象創建成功!";
}
}
public class NewInstanceDemo6 {
public static void main(String[] args) throws Exception {
//傳統方式創建對象
System.out.println(new User());
//使用反射的方式
Class<User> c = User.class;
User u = c.newInstance();(直接newInstance的話必須保證默認的構造方法正常存在,也就是沒有被私有化!這是前提條件)
System.out.println(u);
}
}
復雜點的:更強大的第二種:
使用指定構造方法來創建對象:
獲取該類的Class對象。
利用Class對象的getConstructor()方法來獲取指定的構造方法。
調用Constructor的newInstance()方法創建對象。
AccessibleObject對象的setAccessible(boolean flag)方法,當flag為true的時候,就會忽略訪問權限(可訪問私有的成員)。
其子類有Field, Method, Constructor;
若要訪問對象private的成員?
在調用之前使用setAccessible(true),
Xxx x = getDeclaredXxxx();//才能得到私有的類字段.
總結步驟:
- 1. 獲取該類的Class對象。
- 2. 利用Class對象的getConstructor()方法來獲取指定的構造方法。
- 3. 申請訪問(設置為可訪問)
- 4. 調用Constructor(構造方法)的newInstance()方法創建對象。
例子
package junereflect624;
import java.lang.reflect.Constructor;
class Per{
private String name;
private int age;
private Per(){
}
private Per(String name){
}
public String toString() {
return "對象!!!";
}
}
public class NewInstanceDemo7 {
public static void main(String[] args) throws Exception {
Class<Per> c = Per.class;
//System.out.println(c.newInstance());;//證明利用無參的可以
////先獲得需要被調用的構造器(private 修飾的構造方法)
Constructor<Per> con = c.getDeclaredConstructor();//調用默認的,什么都不要寫
System.out.println(con);//private junereflect624.Per()
/*con = c.getDeclaredConstructor(String.class);獲取指定的構造方法
System.out.println(con);//private junereflect624.Per(java.lang.String)*/
//現在只需要執行這個構造器,
/**
* T newInstance(Object... initargs)
使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,並用指定的初始化參數初始化該實例。
*/
//私有的成員是受保護的,不能直接訪問
//若要訪問私有的成員,得先申請一下
con.setAccessible(true);//允許訪問
Per p = con.newInstance();//成功,通過私有的受保護的構造方法創建了對象
System.out.println("無參構造方法"+p);
con = c.getDeclaredConstructor(String.class);
System.out.println(con);//private junereflect624.Per(java.lang.String)
con.setAccessible(true);//允許訪問
p = con.newInstance("liuzhao");//成功,通過私有的受保護的構造方法創建了對象
System.out.println("String構造方法"+p);
}
}
備注:對於此時的話,單例模式就不再安全了!反射可破之!!
驗證:對於枚舉而言,反射依然沒有辦法重新創建對象
對於枚舉,安全!
package junereflect624;
import java.lang.reflect.Constructor;
enum Color{
RED,BLUE,GREEN;
private Color(){
}
}
public class EnumDemo8 {
public static void main(String[] args) throws Exception {
Class<Color> c = Color.class;
Constructor<Color> con = c.getDeclaredConstructor();//(錯誤在這一行發生,就是說對枚舉而言這種方法連構造器都獲得不了,)編譯可以通過,但是運行就通不過了!
Color co = (Color) con.newInstance();
System.out.println(co);//失敗,證明對枚舉而言不行,所以枚舉的單例模式更加安全
System.out.println(c.isEnum());//true是枚舉
}
}