1. 程式人生 > 實用技巧 >Java反射機制記錄

Java反射機制記錄

Class物件獲取的三種方式

Java反射操作都需要首先獲取Class物件。獲取Class物件的方式有三種:

  1. 公有屬性class
  2. 方法getClass()
  3. Class.forName()

示例:

public class ReflectClassDemo {
    /** log4j */
    private static final Logger LOGGER = Logger.getLogger(ReflectClassDemo.class);
    /**
    * <p>獲取Class物件的三種方式</p>
    * @author*/
    public
static void main(String[] args) throws ClassNotFoundException { LOGGER.info("獲取Class物件方式01:類的public屬性class"); Class clazz1 = User.class; LOGGER.info(clazz1); System.out.println(); LOGGER.info("獲取Class物件方式02:類的public方法getClass()"); User user = new User(); Class clazz2
= user.getClass(); LOGGER.info(clazz2); System.out.println(); LOGGER.info("獲取Class物件方法03:Class.forName(需要丟擲異常)"); Class clazz3 = Class.forName("pers.hanchao.reflect.common.User"); LOGGER.info(clazz3); } }

執行結果:

2018-02-24 13:59:06 INFO  ReflectClassDemo:18 - 獲取Class物件方式01:類的public屬性class
2018-02-24 13:59:06 INFO ReflectClassDemo:20 - class pers.hanchao.reflect.common.User 2018-02-24 13:59:06 INFO ReflectClassDemo:23 - 獲取Class物件方式02:類的public方法getClass() 2018-02-24 13:59:06 INFO ReflectClassDemo:26 - class pers.hanchao.reflect.common.User 2018-02-24 13:59:06 INFO ReflectClassDemo:29 - 獲取Class物件方法03:Class.forName(需要丟擲異常) 2018-02-24 13:59:06 INFO ReflectClassDemo:31 - class pers.hanchao.reflect.common.User

總結:

  1. 通過公有屬性class獲取Class物件:通過類獲取,無需建立類物件。
  2. 通過方法getClass()獲取Class物件:需要類的物件。常用於不知道類名但是能獲取物件的情況下。
  3. 通過方法Class.forName()獲取Class物件:需要類的全名,需丟擲異常。常用於載入配置。

通過反射例項化物件的兩種方式

除了通過new例項化物件,我們還可以通過反射例項化物件物件,有兩種方式:

  1. Class.newInstance()
  2. Constructor.newInstance()

示例:

public class CreateObjectDemo {
    private final static Logger LOGGER = Logger.getLogger(CreateObjectDemo.class);

    /**
     * <p>Title: 通過反射建立物件的兩種方式</p>
     * @author*/
    public static void main(String[] args) throws Exception {
        //通過new例項化物件
        User user = new User();
        LOGGER.info("通過new例項化物件:" + user.toString());

        //通過反射例項化物件
        Class userClass = User.class;
        //通過反射例項化物件01-Class.newInstance()(需要強制型別轉換[無參構造])
        User user1 = (User) userClass.newInstance();
        LOGGER.info("通過反射例項化物件01-Class.newInstance()(需要強制型別轉換[無參構造]):" + user1.toString());
//通過反射例項化物件02-Constructor.newInstance()(需要強制型別轉換[可帶引數]) Constructor constructor = userClass.getDeclaredConstructor(); User user2 = (User) constructor.newInstance(); LOGGER.info("通過反射例項化物件02-Constructor.newInstance()(需要強制型別轉換[無參構造]):" + user2.toString());
Constructor constructor1
= userClass.getDeclaredConstructor(String.class,String.class); User user3 = (User) constructor1.newInstance("李四","000000"); LOGGER.info("通過反射例項化物件02-Constructor.newInstance()(需要強制型別轉換[有參構造]):" + user3.toString()); } }

補充:通過建構函式去建立,呼叫Constructor物件的newInstance()方法建立物件。

Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
Chinese chinese=(Chinese) c1.getConstructor().newInstance();
chinese.say();

執行結果:

2018-02-24 14:23:29 INFO  CreateObjectDemo:22 - 通過new例項化物件:User{username='張三', password='123456'}
2018-02-24 14:23:29 INFO  CreateObjectDemo:27 - 通過反射例項化物件01-Class.newInstance()(需要強制型別轉換[無參構造]):User{username='張三', password='123456'}
2018-02-24 14:23:29 INFO  CreateObjectDemo:31 - 通過反射例項化物件02-Constructor.newInstance()(需要強制型別轉換[無參構造]):User{username='張三', password='123456'}
2018-02-24 14:23:29 INFO  CreateObjectDemo:34 - 通過反射例項化物件02-Constructor.newInstance()(需要強制型別轉換[有參構造]):User{username='李四', password='000000'}

總結:

  1. 通過Class.newInstance()進行物件例項化:實際呼叫的是無引數的建構函式進行例項化。
  2. 通過Constructor.newInstance()進行物件例項化:可以選擇呼叫哪個建構函式進行例項化。

獲取某個類的所有構造方法

public class ReflectTest1 {
    public static void main(String[] args) {
        Date date = new Date();
        Class cc = date.getClass();
        String className = cc.getName();
        System.out.println(className);
        Constructor[] declaredConstructors = cc.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            int modifiers = constructor.getModifiers();
            System.out.print(Modifier.toString(modifiers) + " ");
            System.out.print(constructor.getName() + "(");
            Class[] paramTypes = constructor.getParameterTypes();
            for (Class paramType : paramTypes) {
                System.out.print(paramType.getName() + " ");
            }
            System.out.println(")");
        }
    }
}

輸出結果:

java.util.Date
public java.util.Date(java.lang.String )
public java.util.Date(int int int int int int )
public java.util.Date(int int int int int )
public java.util.Date()
public java.util.Date(long )
public java.util.Date(int int int )

獲取某個類的所有屬性資訊

public class ReflectTest2 {
    public static void main(String[] args) {
        Date date = new Date();
        Class cc = date.getClass();
        String className = cc.getName();
        System.out.println(className);
        Field[] fields = cc.getDeclaredFields();
        for (Field field : fields) {
            String modifiers = Modifier.toString(field.getModifiers());
            Class type = field.getType();
            String name = field.getName();
            System.out.println(modifiers + " " + type.getName() + " " + name);
        }
    }
}

輸出結果:

java.util.Date
private static final sun.util.calendar.BaseCalendar gcal
private static sun.util.calendar.BaseCalendar jcal
private transient long fastTime
private transient sun.util.calendar.BaseCalendar$Date cdate
private static int defaultCenturyStart
private static final long serialVersionUID
private static final [Ljava.lang.String; wtb
private static final [I ttb

補充:

1、獲取所有非private型別的欄位,包括父類的
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object=    c1.getConstructor().newInstance();
     Field [] fields=  c1.getFields();//或者所有的非private型別的欄位,包括父類的
     for(int i=0;i<fields.length;i++)
     {
         System.out.println(fields[i].getName());
     }
     
2、獲取當前類所有欄位,包括私有的
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object=    c1.getConstructor().newInstance();
     Field [] fields=  c1.getDeclaredFields();//獲取當前類中所有的欄位
     for(int i=0;i<fields.length;i++)
     {
         System.out.println(fields[i].getName());
     }
     
3、獲取父類的所有欄位,包括私有的

        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Class c2=    c1.getSuperclass();
        //通過c2去獲取父類中的私有欄位
4、獲取指定的欄位
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object=    c1.getConstructor().newInstance();
     Field field=  c1.getDeclaredField("Age");

5、使用
     Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
     Object object1=    c1.getConstructor().newInstance();
     Field field=  c1.getDeclaredField("Age");
     field.setAccessible(true);//如果欄位是私有的,需要先這是允許訪問
     //取值
     Object  object2=field.get(object1);
     System.out.println(object2);
     //賦值
     field.set(object1, 21);
     //取值
     Object  object3=field.get(object1);
     System.out.println(object3);

獲取某個類的所有方法資訊

public class ReflectTest3 {
    public static void main(String[] args) {
        Date date = new Date();
        Class cc = date.getClass();
        Method[] methods = cc.getDeclaredMethods();
        for (Method method : methods) {
            String modifiers = Modifier.toString(method.getModifiers());
            Class returnType = method.getReturnType();
            String name = method.getName();
            Class[] parameterTypes = method.getParameterTypes();
            Class[] exceptions = method.getExceptionTypes();
            System.out.println(modifiers + " " + returnType + " " + name
                    + "(" + Arrays.asList(parameterTypes) + ")throws" + Arrays.asList(exceptions));
        }
    }
}

輸出結果:

public boolean after([class java.util.Date])throws[]
public boolean before([class java.util.Date])throws[]
public boolean equals([class java.lang.Object])throws[]
public class java.lang.String toString([])throws[]
public int hashCode([])throws[]
public class java.lang.Object clone([])throws[]
public volatile int compareTo([class java.lang.Object])throws[]
public int compareTo([class java.util.Date])throws[]
······

補充:獲取方法並執行

1、獲取所有的非private方法
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Object chinese= c1.getConstructor().newInstance();
        Method[] methods1= c1.getMethods();//獲取所有的非private方法,並且父類的方法也會獲取
        for(int i=0;i<methods1.length;i++)
        {
            Class[] parameters= methods1[i].getParameterTypes();
            if(parameters.length<=0)
            {
                 System.out.println(methods1[i].getName()+"()");
            }
            else
            {
                String [] typeName=new String[parameters.length];
                for(int j=0;j<parameters.length;j++)
                {
                    
                    typeName[j]=parameters[j].getSimpleName();
                }
                System.out.println(methods1[i].getName()+"("+String.join(",",typeName)+")");
            }

        }

2、獲取所有的當前類定義的所有方法,包括私有方法
        Method[] methods1= c1.getDeclaredMethods();//獲取當前類定義的所有,包括私有方法
3、獲取指定方法名的方法
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Object chinese= c1.getConstructor().newInstance();
        Method setNumber=    c1.getDeclaredMethod("setNumber", Integer.class);//如果方法沒有引數就可以不用寫,另外需要注意引數型別和定義方法的引數型別保持一致

4、獲取父類的私有方法
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Class c2=    c1.getSuperclass();
        //通過c2去獲取父類中的私有方法

5、執行方法
        Class c1=Class.forName("pers.pwz.cmdemo.Chinese");
        Object chinese= c1.getConstructor().newInstance();
        Method setNumber=    c1.getDeclaredMethod("setNumber", Integer.class);//如果方法沒有引數就可以不用寫,另外需要注意引數型別和定義方法的引數型別保持一致
        setNumber.invoke(chinese, 1);    //第一個引數是例項物件,後面的引數是呼叫方法所需的引數