day44-反射03

Java反射03

3.通過反射獲取類的結構信息

3.1java.lang.Class類

  1. getName:獲取全類名
  2. getSimpleName:獲取簡單類名
  3. getFields:獲取所有public修飾的屬性,包含本類以及父類的
  4. getDeclaredFields:獲取本類中所有屬性
  5. getMethods:獲取所有public修飾的方法,包含本類以及父類的
  6. getDeclaredMethods:獲取本類中所有方法
  7. getConstructors:獲取本類中所有public修飾的構造器
  8. getDeclaredConstructors:獲取本類中所有構造器
  9. getPackage:以Package形式返回包信息
  10. getSuperClass:以Class形式返回父類信息
  11. getInterfaces:以Class形式返回接口信息
  12. getAnnotations:以Annotation形式返回註解信息

例子1:

package li.reflection;

import org.junit.jupiter.api.Test;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//演示如何通過反射獲取類的結構信息
public class ReflectionUtils {
    public static void main(String[] args) {
    }

    //第一組方法 API
    @Test
    public void api_01() throws ClassNotFoundException {
        //得到Class對象
        Class<?> personCls = Class.forName("li.reflection.Person");

        //1. getName:獲取全類名
        System.out.println(personCls.getName());//li.reflection.Person

        //2. getSimpleName:獲取簡單類名
        System.out.println(personCls.getSimpleName());//Person

        //3. getFields:獲取所有public修飾的屬性,包含本類以及父類的
        Field[] fields = personCls.getFields();
        for (Field field : fields) {//增強for
            System.out.println("本類以及父類的屬性=" + field.getName());
            //本類以及父類的屬性=name
            //本類以及父類的屬性=hobby

        }

        //4. getDeclaredFields:獲取本類中所有屬性
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本類中所有屬性=" + declaredField.getName());
        }

        //5. getMethods:獲取所有public修飾的方法,包含本類以及父類的
        //這裡的父類包括的不只是直接父類,包括object的共有方法也會獲取
        Method[] methods = personCls.getMethods();
        for (Method method : methods) {
            System.out.println("獲取包含本類以及父類的所有public修飾的方法=" + method.getName());
        }

        //6. getDeclaredMethods:獲取本類中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("獲取本類中所有方法" + declaredMethod.getName());
        }

        //7. getConstructors:獲取本類中所有public修飾的構造器
        Constructor<?>[] constructors = personCls.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("本類的public構造器=" + constructor.getName());

        }

        //8. getDeclaredConstructors:獲取本類中所有構造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("獲取本類中所有構造器=" + declaredConstructor.getName());//這裡只是輸出名字
        }

        //9. getPackage:以Package形式返回包信息
        System.out.println(personCls.getPackage());//package li.reflection

        //10. getSuperClass:以Class形式返回父類信息
        Class<?> superclass = personCls.getSuperclass();
        System.out.println("父類的Class對象=" + superclass);//class li.reflection.A

        //11. getInterfaces:以Class形式返回接口信息
        Class<?>[] interfaces = personCls.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            System.out.println("接口信息" + anInterface);
            //接口信息interface li.reflection.IA
            //接口信息interface li.reflection.IB
        }

        //12. getAnnotations:以Annotation形式返回註解信息
        Annotation[] annotations = personCls.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("註解信息" +annotation);//註解信息@java.lang.Deprecated()
        }
    }
}

class A {
    public String hobby;

    public void hi() {
    }

    public A() {
    }

}

interface IA {
}

interface IB {
}

@Deprecated
class Person extends A implements IA, IB {
    //屬性
    public String name;
    protected int age;
    String job;
    private double sal;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    //私有
    private Person(String name, int age) {
    }

    //方法
    public void m1() {
    }

    protected void m2() {
    }

    void m3() {
    }

    private void m4() {
    }

}

image-20220929180038787 image-20220929180103387

3.2java.lang.reflect.Field類

  1. getModifiers:以int形式返回修飾符

    [說明:默認修飾符default是0,public 是1 ,private是2,protected是4,static是8,final是16]

    如果有疊加的修飾符,如 public static …,那麼返回的int值就是相加的結果,public(1)+static(8)=9

  2. getType:以Class形式返回類型,即返回該屬性對應的類的Class對象

  3. getName:返回屬性名

3.3java.lang.reflect.Method類

  1. getModifiers:以int形式返回修飾符

    [說明:默認修飾符default是0,public 是1 ,private是2,protected是4,static是8,final是16]

    如果有疊加的修飾符,如 public static …,那麼返回的int值就是相加的結果,public(1)+static(8)=9

  2. getReturnType:以Class形式獲取返回值的類型的Class對象

  3. getName:返回方法名

  4. getParameteTypes:以Class[]返回參數類型數組

3.4java.lang.reflect.Constructor類

  1. getModifiers:以int形式返回修飾符
  2. getName:返回構造器名(全類名)
  3. getParameteTypes:以Class[]返回參數類型數組

例子2:使用Field類、Method類、Constructor類

package li.reflection;

import org.junit.jupiter.api.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

//演示如何通過反射獲取類的結構信息
public class ReflectionUtils {
    public static void main(String[] args) {
    }

    //第二組方法 API
    @Test
    public void api_02() throws ClassNotFoundException {
        //得到Class對象
        Class<?> personCls = Class.forName("li.reflection.Person");

        //getDeclaredFields:獲取本類中所有屬性
        //[說明:默認修飾符default是0,public 是1 ,private是2,protected是4,static是8,final是16]
        Field[] declaredFields = personCls.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println("本類中所有屬性=" + declaredField.getName()
                    + " 該屬性的修飾符值=" + declaredField.getModifiers()
                    + " 該屬性的類型=" + declaredField.getType());
        }

        //getDeclaredMethods:獲取本類中所有方法
        Method[] declaredMethods = personCls.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println("本類中的所有方法=" + declaredMethod.getName()
                    + " 該方法的訪問修飾符=" + declaredMethod.getModifiers()
                    + " 該方法返回類型=" + declaredMethod.getReturnType());

            //輸出當前這個方法的形參數組情況
            Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("該方法的形參類型=" + parameterType);
            }
        }

        //getDeclaredConstructors:獲取本類中所有構造器
        Constructor<?>[] declaredConstructors = personCls.getDeclaredConstructors();
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println("=================");
            System.out.println("本類中所有構造器=" + declaredConstructor);
            Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("該構造器的形參類型=" + parameterType);
            }
        }
    }
}

class A {
    public String hobby;

    public void hi() {
    }

    public A() {
    }

}

interface IA {
}

interface IB {
}

@Deprecated
class Person extends A implements IA, IB {
    //屬性
    public String name;
    protected static int age;
    String job;
    private double sal;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    //私有
    private Person(String name, int age) {
    }

    //方法
    public void m1(String name, int age, double sal) {
    }

    protected String m2() {
        return null;
    }

    void m3() {
    }

    private void m4() {
    }
}

image-20220929185203838
image-20220929185234966

4.通過反射創建對象

  1. 方式一:調用類中的public修飾的無參構造器
  2. 方式二:調用類中的指定構造器
  3. Class類的相關方法
    • newInstance:調用類中的無參構造器,獲取對應類的對象
    • getConstructor(Class…clazz):根據參數列表,獲取對應的public構造器對象
    • getDecalaredConstructor(Class…clazz):根據參數列表,獲取對應的所有構造器對象
  4. Constructor類相關方法
    • setAccessible:暴破
    • newInstance(Object…obj):調用構造器

例子:

package li.reflection;

import java.lang.reflect.Constructor;

//演示通過反射機制創建實例
public class ReflectCreatInstance {
    public static void main(String[] args) throws Exception {
        //1.先獲取到User類的Class對象
        Class<?> userClass = Class.forName("li.reflection.User");

        //2.通過public的無參構造器創建實例
        Object o = userClass.newInstance();
        System.out.println(o);

        //3.通過public的有參構造器創建實例
        /**
         *  此時的 constructor 對象 就是
         *   public User(String name) {//public有參構造器
         *      this.name = name;
         *     }
         */
        //3.1先得到對應的構造器
        Constructor<?> constructor = userClass.getConstructor(String.class);
        //3.2再去創建實例,並傳入實參
        Object bob = constructor.newInstance("bob");
        System.out.println(bob);

        //4.通過非public的有參構造器創建實例

        //4.1得到private的構造器對象
        Constructor<?> declaredConstructor =
                userClass.getDeclaredConstructor(int.class, String.class);
        //4.2創建實例
        //暴破(暴力破解),使用反射可以訪問 私有的構造器/私有的屬性/私有的方法
        declaredConstructor.setAccessible(true);
        Object user2 = declaredConstructor.newInstance(99, "張三丰");
        System.out.println(user2);
    }
}

class User {//User類
    private int age = 10;
    private String name = "jack";

    public User() {//public無參構造器
    }

    public User(String name) {//public有參構造器
        this.name = name;
    }

    private User(int age, String name) {//private有參構造器
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "User [age=" + age + ", name=" + name + "]";
    }
}

image-20220929194206872

5.通過反射訪問類中的成員

  • 訪問屬性

    1. 根據屬性名獲取Field對象

      Field f = class對象.getDeclaredField(屬性名);

    2. 爆破:f.setAccessible(true);//f是Field

    3. 訪問

      f.set(o,值);//o表示對象

      syso(f.get(o)); //o表示對象

    4. 注意:如果是靜態屬性,則set和get中的參數o,可以寫為null

例子:

package li.reflection;

import java.lang.reflect.Field;

//演示反射操作屬性Field
public class ReflectAccessProperty {
    public static void main(String[] args) throws Exception {
        //1.得到Student類對應的Class對象
        Class<?> stuClass = Class.forName("li.reflection.Student");
        
        //2.創建對象
        Object o = stuClass.newInstance();//o的運行類型就是Student
        System.out.println(o.getClass());//Student

        //3.使用反射得到age屬性對象(公有)
        Field age = stuClass.getField("age");
        age.set(o,88);//通過反射來操作屬性
        System.out.println(o);//Student [age=88, name = null]
        //或者
        System.out.println(age.get(o));//返回age屬性的值 88

        //4.使用反射操作name屬性(私有靜態的屬性)
        Field name = stuClass.getDeclaredField("name");
        //因為name是私有的屬性,需要對 name進行爆破
        name.setAccessible(true);
        name.set(o,"jack");//也可以寫name.set(null,"jack");因為name是靜態屬性,與類有關,與對象無關
        System.out.println(o);
        System.out.println(name.get(o));//jack
    }
}

class Student {
    public int age;
    private static String name;

    public Student() {
    }

    @Override
    public String toString() {
        return "Student [age=" + age + ", name = " + name + "]";
    }
}

image-20220929201419942

  • 訪問方法

    1. 根據方法名和參數列表獲取Method方法對象:

      Method m = 類的Class對象.getDeclaredMethod(方法名,XX.class);//得到本類的所有方法

      XX.class指方法的參數對應的class

    2. 獲取對象:Object o = 類的Class對象.newInstance();

    3. 爆破:m.setAccessible(true);

    4. 訪問:Object returnValue = m.invoke(o,實參列表);

    5. 注意:如果過是靜態方法,則invoke的參數o可以寫為null

例子:

package li.reflection;

import java.lang.reflect.Method;

//演示通過反射操作方法
public class ReflectAccessMethod {
    public static void main(String[] args) throws Exception {
        //1.得到Boss類對應的Class對象
        Class<?> bossCls = Class.forName("li.reflection.Boss");

        //2.創建對象
        Object o = bossCls.newInstance();

        //3.調用普通的public的hi方法
        //3.1得到hi方法對應的方法對象
        Method hi = bossCls.getMethod("hi", String.class);
        //3.2調用
        hi.invoke(o, "孫悟空");

        //4.調用private static 方法
        //注意點:1.private:要使用爆破;2.static:在invoke時的參數可以寫null
        //4.1得到 say 方法對象
        Method say = bossCls.getDeclaredMethod("say", int.class, String.class, char.class);
        //4.2爆破
        say.setAccessible(true);
        //4.3invoke的null
        System.out.println(say.invoke(o, 100, "張三", '男'));
        System.out.println(say.invoke(null, 999, "李四", '女'));//因為是靜態的方法,所以o可以寫為null

        //5.在反射中,如果方法有返回值,統一返回Object,但其運行類型和方法定義的返回類型一致
        Object reVal = say.invoke(null, 300, "jack", '男');
        System.out.println("reVal的運行類型=" + reVal.getClass());//String

    }
}

class Boss {
    public int age;
    private static String name;

    public Boss() {
    }

    private static String say(int n, String s, char c) {//靜態方法
        return n + " " + s + " " + c;
    }

    public void hi(String s) {//普通的public方法
        System.out.println("hi " + s);
    }
}

image-20220929205451785

6.本章作業

6.1練習1:通過反射修改私有成員變量

  1. 定義privateTest類,有私有屬性name,並且屬性值為”hellokitty”
  2. 提供getName的公有方法
  3. 創建PrivateTest的類,利用Class類的到私有屬性name,修改其屬性值,並調用getName()的方法打印name屬性值
package li.reflection.homework;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class homework01 {
    public static void main(String[] args) throws Exception {
        //1.得到PrivateTest對應的Class對象
        Class<?> privateTestCls = Class.forName("li.reflection.homework.PrivateTest");
        //2.創建對象
        Object o = privateTestCls.newInstance();
        //3.得到name屬性對象
        Field name = privateTestCls.getDeclaredField("name");
        //4.爆破
        name.setAccessible(true);
        name.set(o,"天龍八部");
        //5.得到getName方法的對象
        Method method = privateTestCls.getMethod("getName");
        //6.因為getName是public方法,直接調用即可
        Object invoke = method.invoke(o);
        System.out.println("name屬性的值="+invoke);
    }
}
class PrivateTest{
    private String name = "HelloKitty";
    public String getName(){
        return name;
    }
}

image-20220929211441091

6.2練習:利用反射和File完成以下功能

  1. 利用Class類的forName方法得到File類的class對象
  2. 在控制台打印File類的所有構造器
  3. 通過newInstance方法創建File對象,並創建d:\mynew.txt文件

提示:創建文件的正確寫法如下:

File file = new File(“d:\mynew.txt”);

file.creatNewFile();

package li.reflection.homework;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class homework02 {
    public static void main(String[] args) throws Exception {
        //得到File類對應的class類對象
        Class<?> fileCls = Class.forName("java.io.File");
        //得到所有的構造器
        Constructor<?>[] declaredConstructors = fileCls.getDeclaredConstructors();
        System.out.println("=====File的所有構造器=====");
        //遍歷輸出構造器
        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor);
        }
        //指定得到 public java.io.File(java.lang.String)
        Constructor<?> constructor = fileCls.getConstructor(String.class);
        //創建File類對象
        Object file = constructor.newInstance("d:\\mynew.txt");
        //獲取createNewFile方法的對象
        Method createNewFile = fileCls.getDeclaredMethod("createNewFile");
        //調用
        createNewFile.invoke(file);
    }
}

image-20220929213900651
image-20220929213828260

Tags: