Java 反射

  • Post author:
  • Post category:java



目录


一、获取 Class 实例


1.1 、直接通过一个 class 的静态变量class获取


1.2、如果有一个实例变量,通过该实例变量提供的 getClasss() 方法获取


1.3、知道一个 class 的完整类名,通过Class.forName()获取


二、访问字段


三、调用方法


3.1、 普通方法调用


3.2、 静态方法调用


3.3、 非 public 方法调用


3.4、 多态方法调用


四、调用构造方法


通过 Class 实例获取 class 信息的方法称为反射(Reflection)。

由于 JVM 为每个加载的类创建了对应的类实例,并在实例中保存了该类的所有信息,包括类名、包名、父类、实现的接口、所有方法、字段等。因此,如果获得了某个类实例,就可以通过这个类实例取到实例对应的类的所有信息。

一、获取 Class 实例

获取一个 class 的 Class 实例三种方法:

1.1 、直接通过一个 class 的静态变量class获取

Class clazz = String.class;

1.2、如果有一个实例变量,通过该实例变量提供的 getClasss() 方法获取

如果有一个实例变量,可以通过该实例变量提供的 getClass() 方法获取

String str = "hello world";
Class clazz = str.getClass();    

1.3、知道一个 class 的完整类名,通过

Class.forName()

获取

 Class clazz =  Class.forName("java.lang.String");

因为Class实例在JVM中是唯一的,所以,上述方法获取的Class实例是同一个实例。可以用==比较两个Class实例:

public class Main {

    public static void main(String[] args) throws Exception {

        Class clazz1 = String.class;

        String str = "Hello world";
        Class clazz2 = str.getClass();

        Class clazz3 = Class.forName("java.lang.String");

        System.out.println(clazz1 == clazz2); //true
        System.out.println(clazz1 == clazz3); //true
        System.out.println(clazz2 == clazz3);//true
    }

}

class 实例比较和 instanceof 的差别:

public class Main {

    public static void main(String[] args) throws Exception {

        Integer n = new Integer(123);

        boolean b1 = n instanceof Integer; // true,因为n是Integer类型
        boolean b2 = n instanceof Number; // true,因为n是Number类型的子类

        boolean b3 = n.getClass() == Integer.class; // true,因为n.getClass()返回Integer.class
        boolean b4 = n.getClass() == Number.class; // false,因为Integer.class!=Number.class
    }

}

用 instanceof 不但匹配指定类型,还匹配指定类型的子类,而用 == 判断class 实例可以精确地判断数据类型,但不能作为比较子类型比较。

通常情况,用 instanceof 判断数据类型,应为面向抽象编程地时候,不关心具体地子类型。只有在需要精确判断一个类型是不是某个 class 的时候,才使用 == 判断 class 实例。

反射的目的是为了获取某个实例的信息,因为当拿到某个 object 实例时,可以通过反射获取 object 的 class 信息。

例如获取到一个 Class 实例 ,就可以通过该 Class 实例来创建对应类型的实例:

public class Main {
    public static void main(String[] args) throws Exception{
        // 获取String的Class实例:
        Class cls = String.class;
        // 创建一个String实例:
        String s = (String) cls.newInstance();
    }
}

上述代码相当于 new String()。 通过 Class.newInstance 可以创建实例,它的局限性是只能调用 public 的无参构造方法。带参数的构造方法或者非 public 的构造方法都无法通过 Class.newInstance() 被调用。


动态加载



JVM 在执行 Java 程序的时候,并不是一次性把所有用到的 class 全部加载到内存,而是第一次需要用到 class 时才加载。例如:

// Main.java
public class Main {
        public static void main(String[] args) {
            if (args.length > 0) {
                create(args[0]);
            }
        }

        static void create(String name) {
            Person p = new Person(name);
        }
}

当执行Main.java 时,由于用到 Main, JVM会把 Main.class 加载到内存。然后,并不会加载 Person.class ,除非程序执行到 create() 方法, JVM 发现需要加载 Person 类时,才会首次加载 Person.class 。如果没有加载 create() 方法,那么 Person.class 就不会被加载。这就是 JVM 动态加载 class 的特性。

Class 类扩展方法


方法

描述
String toGenericString() 返回一个描述这个类的字符串信息,包含修饰符和类型参数的信息
forName(String className) 根据类的完整路径返回Class对象
forName(String name, boolean initialize,ClassLoader loader) 根据类的完整路径返回Class对象
T newInstance() 创建类的实例
boolean isInstance(Object obj) 判断是否是类的实例
boolean isAssignableFrom(Class<?> cls) 判断当前的Class对象所表示的类,是不是参数中传递的Class对象所表示的类的父类
boolean isInterface() 判断是否接口
boolean isPrimitive() 判断是否为原始基本类型(例如int、char、long..)
boolean isAnnotation() 判断是否注解类型
boolean isSynthetic()

判断是的合成类


Java冷门基础知识isSynthetic方法的详细解析_看着不像程序猿的程序员_新浪博客

String getName() 获取类名称
getClassLoader() 获取加载器
Class<? super T> getSuperclass() 获取父类
Type getGenericSuperclass() 获取直接父类,并且父类的泛型类型也会返回
Package getPackage() 获取包名
Class<?>[] getInterfaces() 获得这个对象所实现的所有接口
Type[] getGenericInterfaces() 获得这个对象所实现的所有接口并且返回接口泛型
Class<?> getComponentType() 获取一个数组的Class对象
int getModifiers() 获取修饰符
Object[] getSigners() 返回类的签名者
Method getEnclosingMethod() 当此Class对象表示方法内部的本地或匿名类时,使用getEnclosingMethod()方法返回基础类的最新封闭方法
Constructor<?> getEnclosingConstructor() 如果此类是在该构造函数中声明的本地类或匿名类,则方法返回此类的封闭构造函数
Class<?> getDeclaringClass() 返回表示在它被声明的类的Class对象,如果此Class对象所表示的类或接口是另一个类成员
Class<?> getEnclosingClass() 返回底层的直接外围类。如果底层类是顶级类(Object)则返回null
String getSimpleName() 获取简单类名
String getCanonicalName() 获取规范名称
boolean isAnonymousClass() 判断是否匿名内部类
boolean isLocalClass() 判断是否为本地类
boolean isMemberClass() 判断是否成员类
Class<?>[] getClasses() 返回Class 对象数组(不包含private修饰)
Field[] getFields() 返回公共字段(public 修饰)
Method[] getMethods() 返回公共方法(public 修饰)
Constructor<?>[] getConstructors() 获取构造方法(public 修饰)
Field getField(String name) 根据参数获取字段信息(public 修饰)
Method getMethod(String name, Class<?>… parameterTypes) 返回Method对象匹配指定名称和parameterTypes(public 修饰)
Constructor<T> getConstructor(Class<?>… parameterTypes) 返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类的指定公共构造函数
Class<?>[] getDeclaredClasses() 返回Class 对象数组
Field[] getDeclaredFields() 获取类字段信息
Method[] getDeclaredMethods() 获取类方法
Constructor<?>[] getDeclaredConstructors() 获取构造方法
Field getDeclaredField(String name) 根据参数获取字段信息
Method getDeclaredMethod(String name, Class<?>… parameterTypes) 返回Method对象匹配指定名称和parameterTypes
Constructor<T> getDeclaredConstructor(Class<?>… parameterTypes) 根据参数获取对应构造方法
InputStream getResourceAsStream(String name) 查找具有给定名称的资源
java.net.URL getResource(String name) 查找具有给定名称的资源,返回URL
java.security.ProtectionDomain getProtectionDomain() 返回类的 ProtectionDomain 对象
boolean desiredAssertionStatus() 该方法以布尔值的形式返回该类的指定断言状态
boolean isEnum() 判断是否枚举
T[] getEnumConstants() 获取枚举元素
T cast(Object obj) 将对象强制转换为所表示的类或接口
<U> Class<? extends U> asSubclass(Class<U> clazz) 强制把Class对象转化成参数类的子类
AnnotatedType getAnnotatedSuperclass() 获取当前类的父类,可以用 AnnotatedType 来描述,也就是说它们申明了泛型并且被注解标注
AnnotatedType[] getAnnotatedInterfaces() 获取当前类的接口,可以用 AnnotatedType[] 来描述,也就是说它们申明了泛型并且被注解标

示例

import com.sun.javafx.geom.transform.Identity;

import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.security.ProtectionDomain;
import java.util.HashMap;

public class Main {
    public Integer age;
    private String userName;

    public Main() {
    }

    private Main(Integer age, String userName) {
        this.age = age;
        this.userName = userName;
    }

    public void showLong(Long l) {

    }
    private void say(Long l) {

    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Main{" +
                "userName='" + userName + '\'' +
                '}';
    }

    public static void main(String[] args) {
        printClassInfo();

    }

    static void printClassInfo() {

        //返回一个描述这个类的字符串信息,包含修饰符和类型参数的信息
        toGenericString();
        //根据类的完整路径,加载类,返回Class对象
        clssForName();
        //创建类的实例
        newInstance();
        // 判断是否是类的实例
        isInstance();
        //判断当前的Class对象所表示的类,是不是参数中传递的Class对象所表示的类的父类
        isAssignableFrom();
        // 判断是否接口
        isInterface();
        // 判断是否数组
        isArray();
        //判断是否为原始基本类型(例如int、char、long..)
        isPrimitive();
        // 判断是否注解类型
        isAnnotation();
        /**
         * 判断是的合成类
         * https://blog.sina.com.cn/s/blog_1534f339a0102y88n.html
         *
         */

        // 获取类名称
        getName();

        // 获取加载器
        getClassLoader();

        // 获取父类(public 修饰)
        getSuperclass();

        // 获取直接父类,并且父类的泛型类型也会返回
        getGenericSuperclass();

        // 获取包名
        getPackage();

        // 获得这个对象所实现的所有接口
        getInterfaces();

        // 获得这个对象所实现的所有接口并且返回接口泛型
        getGenericInterfaces();

        // 获取一个数组的Class对象
        getComponentType();

        // 获取修饰符
        getModifiers();

        // 返回类的签名者
        getSigners();

        // 当此Class对象表示方法内部的本地或匿名类时,使用getEnclosingMethod()方法返回基础类的最新封闭方法
        getEnclosingMethod();

        // 如果此类是在该构造函数中声明的本地类或匿名类,则方法返回此类的封闭构造函数
        getEnclosingConstructor();

        //返回表示在它被声明的类的Class对象,如果此Class对象所表示的类或接口是另一个类成员
        getDeclaringClass();

        // 返回底层的直接外围类。如果底层类是顶级类(Object)则返回null
        getEnclosingClass();

        // 获取简单类名
        getSimpleName();

        // 获取规范名称
        getCanonicalName();

        // 判断是否匿名内部类
        isAnonymousClass();

        // 判断是否为本地类
        isLocalClass();

        // 判断是否成员类
        isMemberClass();
        // 返回Class 对象数组(不包含private修饰)
        getClasses();
        //返回公共字段(public 修饰)
        getFields();
        //返回公共方法(public 修饰)
        getMethods();
        // 获取构造方法(public 修饰)
        getConstructors();
        // 根据参数获取字段信息(public 修饰)
        getField();
        //返回Method对象匹配指定名称和parameterTypes(public 修饰)
        getMethod();
        //返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类的指定公共构造函数
        getConstructor();
        //返回Class 对象数组
        getDeclaredClasses();

        // 获取类字段信息
        getDeclaredFields();

        //获取类方法
        getDeclaredMethods();

        // 获取构造方法
        getDeclaredConstructors();
        // 根据参数获取字段信息
        getDeclaredField();
        // 返回Method对象匹配指定名称和parameterTypes
        getDeclaredMethod();
        // 根据参数获取对应构造方法
        getDeclaredConstructor();
        // 查找具有给定名称的资源
        getResourceAsStream();
        // 查找具有给定名称的资源,URL
        getResource();
        //返回类的 ProtectionDomain 对象
        getProtectionDomain();
        //该方法以布尔值的形式返回该类的指定断言状态
        desiredAssertionStatus();

        // 判断是否枚举
        isEnum();
        // 获取枚举元素
        getEnumConstants();
        //将对象强制转换为所表示的类或接口
        cast();
        //强制把Class对象转化成参数类的子类
        asSubclass();
        // 获取当前类的父类,可以用 AnnotatedType 来描述,也就是说它们申明了泛型并且被注解标注
        getAnnotatedSuperclass();
        //获取当前类的接口,可以用 AnnotatedType[] 来描述,也就是说它们申明了泛型并且被注解标注
        getAnnotatedInterfaces();

    }


    //返回一个描述这个类的字符串信息,包含修饰符和类型参数的信息
    static void toGenericString() {
        Class clazz = Runnable.class;
        System.out.println("toGenericString: " + clazz);
    }

    // 根据类的完整路径返回与类或关联的Class对象
    static void clssForName() {
        try {

            // 参数:类的完整路
            Class clazz1 = Class.forName("Main");

            ClassLoader cLoader = clazz1.getClassLoader();

            /**
             * 参数一:类的完整路
             * 参数二 类是否初始化  true:初始化  false 不初始化
             * 参数三:加载器
             */

            Class clazz2 = Class.forName("java.lang.String", true, cLoader);

            System.out.println("Class.forName():" + clazz1);
            System.out.println("Class.forName(...):" + clazz2);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    // 创建类的实例
    static void newInstance() {
        try {
            Class clazz = Main.class;
            // 创建Main类的实例
            Main main = (Main) clazz.newInstance();
            main.setUserName("张三");
            System.out.println("newInstance: " + main.toString());
        } catch (Exception e) {

        }

    }

    // 判断是否属于类的实例
    static void isInstance() {
        try {
            Class clazz = Class.forName("Main");
            Class clazz1 = Class.forName("java.lang.String");
            // 创建Main类的实例
            Main main = (Main) clazz.newInstance();

            // 判断是否是类的实例
            boolean result = clazz.isInstance(main); // true
            boolean result1 = clazz1.isInstance(main); // false
            System.out.println("isInstance: result = " + result + " result1=" + result1);
        } catch (Exception e) {

        }

    }

    // 判断当前的Class对象所表示的类,是不是参数中传递的Class对象所表示的类的父类
    static void isAssignableFrom() {
        try {
            Class parent = Class.forName("Parent");
            Class Son = Class.forName("Son");

            //
            Boolean result = parent.isAssignableFrom(Son); // true

            System.out.println("isAssignableFrom: result = " + result);
        } catch (Exception e) {

        }

    }

    // 判断是否接口
    static void isInterface() {
        try {
            Class demoService = Class.forName("DemoService");

            Boolean result = demoService.isInterface();

            System.out.println("isInterface: result = " + result);// true
        } catch (Exception e) {

        }

    }

    // 判断是否数组
    static void isArray() {
        Class clazz = String[].class;

        Boolean result = clazz.isArray();

        System.out.println("isInterface: result = " + result); // true


    }

    // 判断是否为原始基本类型(例如int、char、long..)
    static void isPrimitive() {
        String str = new String();
        Class cl1 = str.getClass();


        //创建并返回short-
        // short sh = 10;
        Class cl2 = short.class; // true
        // Class cl2 = Integer.class; // false

        Boolean result = cl1.isPrimitive(); //false
        Boolean result1 = cl2.isPrimitive(); //true
        System.out.println("isPrimitive: result = " + result + "   result1 = " + result1);


    }

    // 判断是否注解类型
    static void isAnnotation() {
        Class ann1 = Identity.class;
        Class ann2 = Deprecated.class;
        System.out.println("isAnnotation  ann1= " + ann1.isAnnotation() + "    ann2=" + ann2.isAnnotation());

    }

    //获取类名称
    static void getName() {
        Class clazz = Main.class;
        System.out.println("getName = " + clazz.getName());

    }

    // 获取类加载器
    static void getClassLoader() {
        Class clazz = Main.class;
        System.out.println("getClassLoader = " + clazz.getClassLoader());

    }

    // 获取父类
    static void getSuperclass() {
        Class clazz = Son.class;
        System.out.println("getSuperclass = " + clazz.getSuperclass());

    }

    // 获取直接父类
    static void getGenericSuperclass() {
        Class clazz = Son.class;
        System.out.println("getGenericSuperclass = " + clazz.getGenericSuperclass());

    }

    // 获取包名
    static void getPackage() {
        Class clazz = String.class;
        System.out.println("getPackage = " + clazz.getPackage());

    }

    // 获得这个对象所实现的所有接口
    static void getInterfaces() {
        Class clazz = DemoServiceImpl.class;
        Class[] arr = clazz.getInterfaces();

        if (null != arr && arr.length > 0) {
            System.out.println("getInterfaces arr = " + arr[0]);
        }


    }

    // 获得这个对象所实现的所有接口并且返回接口泛型
    static void getGenericInterfaces() {
        Class clazz = DemoServiceImpl.class;
        Type[] arr = clazz.getGenericInterfaces();

        if (null != arr && arr.length > 0) {
            System.out.println("getGenericInterfaces arr = " + arr[0]);
        }


    }

    // 获取一个数组的Class对象
    static void getComponentType() {
        Class clazz = String[].class;
        Class componentType = clazz.getComponentType();

        Class clazz1 = String.class;
        Class componentType1 = clazz1.getComponentType();

        System.out.println("getComponentType   = " + componentType + " getComponentType=" + componentType1);

    }


    // 获取修饰符
    static void getModifiers() {
        Class clazz = Main.class;
        int modifiers = clazz.getModifiers();

        System.out.println("getModifiers  = " + modifiers);

    }


    // 返回类的签名者
    static void getSigners() {
        try {
            Class cls = Main.class;
            Object[] obj = cls.getSigners();
            System.out.println("getSigners  = " + obj);
        } catch (Exception ex) {
            System.out.println(ex.toString());
        }

    }

    // 当此Class对象表示方法内部的本地或匿名类时,使用getEnclosingMethod()方法返回基础类的最新封闭方法
    static void getEnclosingMethod() {
        try {
            Class c = (new Out()).ClassAObject().getClass();
            System.out.println("getEnclosingMethod() = " + c.getEnclosingMethod());
        } catch (Exception ex) {
            System.out.println(ex.toString());
        }

    }

    // 如果此类是在该构造函数中声明的本地类或匿名类,则方法返回此类的封闭构造函数
    static void getEnclosingConstructor() {
        try {
            Class c = (new Out()).c.getClass();
            System.out.println("getEnclosingConstructor() = " + c.getEnclosingConstructor());
        } catch (Exception ex) {
            System.out.println(ex.toString());
        }

    }

    // 返回这个类的声明类。
    static void getDeclaringClass() {

        Class cl = Integer.class;

        // It returns an array of Methods
        // that denotes the private, protected, public and default
        // Methods of the class Integer
        Method[] methods = cl.getMethods();


        // Traverse Integer class
        // for (int i = 0; i < methods.length; ++i) {
        Class declare_classes = methods[0].getDeclaringClass();
        System.out.println(" getDeclaringClass= " + declare_classes.toString());
        // }


    }

    /**
     * 返回底层直接外围类
     */
    static void getEnclosingClass() {

        Class clazz = new Out().c.getClass();
        Class clazz1 = Object.class;

        System.out.println(" getEnclosingClass= " + clazz.getEnclosingClass());
        System.out.println(" getEnclosingClass= " + clazz1.getEnclosingClass());

    }

    // 获取简单类名
    static void getSimpleName() {

        Class clazz = String.class;

        System.out.println(" getSimpleName= " + clazz.getSimpleName());

    }

    // 获取规范名称
    static void getCanonicalName() {

        Class clazz = String.class;

        System.out.println(" getCanonicalName= " + clazz.getCanonicalName());

    }

    // 判断是否匿名类
    static void isAnonymousClass() {

        Class clazz = new HashMap<String, String>() {
            // 匿名类
        }.getClass();
        System.out.println(" isAnonymousClass= " + clazz.isAnonymousClass());
    }


    // 判断是否为本地类
    static void isLocalClass() {

        class A {
        }


        Class clazz = A.class;
        Class clazz1 = Out.class;
        System.out.println(" isLocalClass= " + clazz.isLocalClass() + "  isLocalClass=" + clazz1.isLocalClass());
    }

    // 判断是否成员类
    static void isMemberClass() {

        class A {
        }

        Class clazz = A.class;
        Class clazz1 = Out.class;
        System.out.println(" isMemberClass= " + clazz.isLocalClass() + "  isMemberClass=" + clazz1.isLocalClass());
    }


    // 返回Class 对象数组
    static void getClasses() {
        Class clazz = Main.class;
        Class[] clazzArr = clazz.getClasses();
        for (int i = 0; i < clazzArr.length; i++) {
            System.out.println("getClasses = " + clazzArr[i].getName());
        }
    }

    // 返回公共字段(public 修饰)
    static void getFields() {
        Class clazz = Main.class;
        Field[] clazzArr = clazz.getFields();
        for (int i = 0; i < clazzArr.length; i++) {
            System.out.println("getFields = " + clazzArr[i]);
        }
    }

    // 返回公共方法(public 修饰)
    static void getMethods() {
        Class clazz = Main.class;
        Method[] clazzArr = clazz.getMethods();
        for (int i = 0; i < clazzArr.length; i++) {
            System.out.println("getMethods = " + clazzArr[i]);
        }
    }

    // 获取构造方法
    static void getConstructors() {
        Class clazz = Main.class;
        Constructor[] clazzArr = clazz.getConstructors();
        for (int i = 0; i < clazzArr.length; i++) {
            System.out.println("getConstructors = " + clazzArr[i]);
        }
    }

    // 根据参数获取字段信息,不包含(private 修饰)
    static void getField() {
        try {
            Class clazz = Main.class;
            Field field = clazz.getField("age");
            System.out.println("getField=" + field);
        } catch (Exception e) {

        }
    }

    // 返回Method对象匹配指定名称和parameterTypes
    static void getMethod() {
        try {
            Class clazz = Main.class;
            Class[] cArg = new Class[1];
            cArg[0] = Long.class;

            Method method = clazz.getMethod("showLong", cArg);
            System.out.println("getMethod=" + method.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //返回一个 Constructor 对象,该对象反映了此 Class 对象表示的类的指定公共构造函数
    static void getConstructor() {
        try {
            Class cls[] = new Class[]{String.class};
            Constructor c = String.class.getConstructor(cls);
            System.out.println("getConstructor=" + c);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 返回Class 对象数组
    static void getDeclaredClasses() {
        Class clazz = Main.class;
        Class[] clazzArr = clazz.getDeclaredClasses();
        for (int i = 0; i < clazzArr.length; i++) {
            System.out.println("getDeclaredClasses = " + clazzArr[i].getName());
        }
    }

    //获取类字段信息
    static void getDeclaredFields() {
        try {
            Class clazz = Main.class;
            Field[] fieldArr = clazz.getDeclaredFields();
            for(Field f : fieldArr){
                System.out.println("getDeclaredFields=" + f);
            }

        } catch (Exception e) {

        }

    }


    // 获取类方法
    static void getDeclaredMethods() {
        try {
            Class clazz = Main.class;
            Method[] methodArr = clazz.getDeclaredMethods();
            for(Method m : methodArr){
                System.out.println("getDeclaredMethods=" + m);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 获取构造方法
    static void getDeclaredConstructors() {
        try {
            Constructor[] cArr= Main.class.getDeclaredConstructors();
            for(Constructor c : cArr){
                System.out.println("getDeclaredConstructors=" + c);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //根据参数获取字段信息
    static void getDeclaredField() {
        try {
            Class clazz = Main.class;
            Field field = clazz.getDeclaredField("userName");
            System.out.println("getDeclaredField=" + field);
        } catch (Exception e) {

        }
    }

    // 返回Method对象匹配指定名称和parameterTypes
    static void getDeclaredMethod() {
        try {
            Class clazz = Main.class;
            Class[] cArg = new Class[1];
            cArg[0] = Long.class;

            Method method = clazz.getDeclaredMethod("say", cArg);
            System.out.println("getDeclaredMethod=" + method.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 根据参数获取对应构造方法
    static void getDeclaredConstructor() {
        try {
            Class parameterTypes[] = {Integer.class,String.class};
            Constructor c = Main.class.getDeclaredConstructor(parameterTypes);
            System.out.println("getDeclaredConstructor=" + c);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 查找具有给定名称的资源,返回InputStream
    static void getResourceAsStream() {
        InputStream in = Main.class.getResourceAsStream("application.properties");
        byte[] buf = new byte[1024];
        int len;
        try {
            while ((len = in.read(buf)) != -1) {
                String s = new String(buf, 0,len,"GBK");
                System.out.println(s);
            }

            in.close();
        }catch (Exception E){

        }

    }

    // 查找具有给定名称的资源,返回URL
    static void getResource() {
        java.net.URL url = Main.class.getResource("application.properties");
        System.out.println("getResource = "+url);

    }
    // 返回类的 ProtectionDomain 对象
    static void getProtectionDomain() {
        ProtectionDomain protectionDomain = Main.class.getProtectionDomain();
        System.out.println("getProtectionDomain = "+protectionDomain);

    }

    // 该方法以布尔值的形式返回该类的指定断言状态
    static void desiredAssertionStatus() {
        boolean result  = Main.class.desiredAssertionStatus();
        System.out.println("desiredAssertionStatus = "+result);

    }

    // 判断是否枚举
    static void isEnum() {
        boolean result  = Main.class.isEnum();
        boolean result1  = EnumDemo.class.isEnum();
        System.out.println("isEnum = "+result +" isEnum="+result1);

    }


    // 获取枚举元素
    static void getEnumConstants() {
        EnumDemo[] enumDemoArr  = EnumDemo.class.getEnumConstants();
        for(EnumDemo e:enumDemoArr){
            System.out.println("getEnumConstants = "+e );
        }
    }


    //将对象强制转换为所表示的类或接口
    static void cast() {
        Class clazz = Main.class;
        try {
            Object obj =new Main(23,"张三");
            if(obj instanceof  Main){
                Main m = (Main) clazz.cast(obj);
                System.out.println("cast = "+m.toString() );
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 强制把Class对象转化成参数类的子类
    static void asSubclass() {
        Class son = Son.class;
        Class parent = Parent.class;
        try {

            Class p =  son.asSubclass(parent);
            System.out.println("asSubclass ="+p);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    // 获取Class 类的父类注解
    static void getAnnotatedSuperclass() {
        try {

            Annotation[] anns = B.class.getAnnotatedSuperclass().getAnnotations();
            for (Annotation a : anns){
                System.out.println("getAnnotatedSuperclass = "+a.annotationType().getName());
            }

        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    //返回一个AnnotatedType对象数组,表示使用类型来指定此Class对象表示的实体的超接口
    static void getAnnotatedInterfaces() {
        try {

            AnnotatedType[] anns = First.class.getAnnotatedInterfaces();
            for (AnnotatedType a : anns){
                System.out.println("getAnnotatedInterfaces = "+ a);
            }

        }catch (Exception e) {
            e.printStackTrace();
        }

    }





    public class a {
    }

    public class b {
    }

    private class c {
    }

}

class Out {
    public Object c;

    public Out() {
        class ClassA {
        }
        ;
        c = new ClassA();
    }

    public Object ClassAObject() {

        class ClassA {

        }
        return new ClassA();
    }
}

enum EnumDemo {
    PAY_WX(),
    PAY_ALI();
}
class Grandfather {

}

class Parent<T> extends Grandfather {


}

class Son extends Parent<Integer> {

}

interface DemoService<T> {

}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface First  { }

@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface Second { }

class A { }

class B extends @First @Second A { }

class DemoServiceImpl implements DemoService<Integer> {

}




二、访问字段

Class 类提供了以下几个方法获取字段:

  • Field getField(name):根据字段名获取某个public的field(包括父类)
  • Field getDeclaredField(name):根据字段名获取当前类的某个field(不包括父类)
  • Field[] getFields():获取所有public的field(包括父类)
  • Field[] getDeclaredFields():获取当前类的所有field(不包括父类)

示例

public class Main {
    public static void main(String[] args) throws Exception {
        Class stdClass = Student.class;
        // 获取public字段"score":
        System.out.println(stdClass.getField("score"));
        // 获取继承的public字段"name":
        System.out.println(stdClass.getField("name"));
        // 获取private字段"grade":
        System.out.println(stdClass.getDeclaredField("grade"));
    }
}

class Student extends Person {
    public int score;
    private int grade;
}

class Person {
    public String name;
}

控制台显示

public int Student.score
public java.lang.String Person.name
private int Student.grade

一个 Field 对象包含了一个字段的所有信息:

getName() : 返回字段名称 。例如 “name”。

getType(): 返回字段类型,也是一个 Class 示例。  例如 String.class。

getModifiers():返回字段修饰符,它是一个 int值,不同 bit 表示不同含义。

例如 String类的value字段为例,它的定义是:

public final class String {
    private final byte[] value;
}

用反射获取该字段的信息,代码如下:

import java.lang.reflect.Modifier;

public class Main {
    public static <Field> void main(String[] args) throws Exception {
        java.lang.reflect.Field f = String.class.getDeclaredField("value");//   private final char value[];
        f.getName(); // "value"
        f.getType(); // class [B 表示byte[]类型
        int m = f.getModifiers();
        Modifier.isFinal(m); // true
        Modifier.isPublic(m); // false
        Modifier.isProtected(m); // false
        Modifier.isPrivate(m); // true
        Modifier.isStatic(m); // false
        
    }
}

获取/设置字段值

import java.lang.reflect.Field;

public class Main {

    public static void main(String[] args) throws Exception {
        Person p = new Person("Xiao Ming");
        Class c = p.getClass();
        Field f = c.getDeclaredField("name");
        f.setAccessible(true);  //  别管这个字段是不是public,一律允许访问
        Object value = f.get(p);  // 获取值
        System.out.println(value); // "Xiao Ming"'

        f.set(p, "Xiao Zhang"); // 设置值
        System.out.println(p.getName()); // "Xiao Hong"
    }
}

class Person {
    private String name;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。

Field 类扩展方法


方法

描述
boolean isEnumConstant() 判断是否枚举常量
Class<?> getType() 获取字段类型,不包含泛型类型
Type getGenericType() 获取字段类型
String toGenericString() 返回描述这个字段的字符串
Object get(Object obj) 获取字段值
boolean getBoolean(Object obj) 获取 boolean 类型字段值
byte getByte(Object obj) 获取 byte 类型字段值
char getChar(Object obj) 获取 char 类型字段值
short getShort(Object obj) 获取 short 类型字段值
int getInt(Object obj) 获取 int类型字段值
long getLong(Object obj) 获取 long类型字段值
float getFloat(Object obj) 获取float类型字段值
double getDouble(Object obj) 获取 double类型字段值
void set(Object obj, Object value) 设置字段值
void setBoolean(Object obj, boolean z) 设置boolean 类型字段值
void setByte(Object obj, byte b) 设置 byte 类型字段值
void setChar(Object obj, char c) 设置char 类型字段值
void setShort(Object obj, short s) 设置short 类型字段值
void setInt(Object obj, int i) 设置int类型字段值
void setLong(Object obj, long l) 设置long类型字段值
void setFloat(Object obj, float f) 设置float类型字段值
void setDouble(Object obj, double d) 设置double类型字段值
AnnotatedType getAnnotatedType() 返回一个AnnotatedType对象,该对象包含类型等信息

示例

import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field;
import java.lang.reflect.Type;

public class Main {

    public static void main(String[] args) throws Exception {

        // 判断是否枚举常量
        isEnumConstant();
        // 获取字段类型,不包含泛型类型
        getType();
        // 获取字段类型
        getGenericType();
        // 返回描述这个字段的字符串
        toGenericString();
        // 获取/设置字段值
        get$set();
        // 获取/设置boolean 类型字段值
        getBoolean$setBoolean();
        // 获取/设置 byte 类型字段值
        getByte$setByte();
        // 获取/设置char 类型字段值
        getChar$setChar();
        // 获取/设置short 类型字段值
        getShort$setShort();
        // 获取/设置int类型字段值
        getInt$setInt();
        // 获取/设置long类型字段值
        getLong$setLong();
        // 获取/设置float类型字段值
        getFloat$setFloat();
        // 获取/设置double类型字段值
        getDouble$setDouble();
        //返回一个AnnotatedType对象,该对象包含类型等信息
        getAnnotatedType();

    }


    // 判断是否枚举常量
    static void isEnumConstant() {
        Class clazz = Pay.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("PAY");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        boolean isEnumConstant = field.isEnumConstant();
        System.out.println("isEnumConstant = " + isEnumConstant);
    }

    //  获取字段类型,不包含泛型类型
    static void getType() {
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("name");
            //field =  clazz.getDeclaredField("address"); // 获取不到
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        Class c = field.getType();
        System.out.println("getType = " + c);
    }

    static void getGenericType() {
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("address");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        Type c = field.getGenericType();
        System.out.println("getGenericType = " + c);
    }


    /**
     * *返回描述这个{@code字段}的字符串,包括
     * 其泛型类型。的访问修饰符
     * 字段(如果有的话),然后是泛型字段类型,然后是
     * 一个空格,后跟类的全限定名
     * 声明字段,后面跟着句号,后面跟着名称
     */
    static void toGenericString() {
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("address");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        String str = field.toGenericString();
        System.out.println("toGenericString = " + str);
    }


    // 获取/设置 字段值
    static void get$set() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("name");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            //设置字段的值
            field.set(p, "kevin");
            // 获取字段的值
            Object obj = field.get(p);
            System.out.println("get$set = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取/设置boolean 类型字段值
    static void getBoolean$setBoolean() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("deleteFlag");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问

            // 设置字段的值
            field.setBoolean(p, Boolean.TRUE);
            // 获取字段的值
            boolean obj = field.getBoolean(p);
            System.out.println("getBoolean$setBoolean = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取/设置 byte 类型字段值
    static void getByte$setByte() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("byteField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            // 设置字段的值
            field.setByte(p, Byte.parseByte("3"));
            // 获取字段的值
            byte obj = field.getByte(p);
            System.out.println("getByte$setByte = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取/设置char 类型字段值
    static void getChar$setChar() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("charField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            // 设置字段的值
            field.setChar(p, '2');
            // 获取字段的值
            char obj = field.getChar(p);
            System.out.println("getChar$setChar = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取/设置short 类型字段值

    static void getShort$setShort() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("shortField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            // 设置字段的值
            field.setShort(p, Short.parseShort("2"));
            // 获取字段的值
            short obj = field.getShort(p);
            System.out.println("getShort$setShort = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取/设置int 类型字段值
    static void getInt$setInt() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("intField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            // 设置字段的值
            field.setInt(p, 2);
            // 获取字段的值
            int obj = field.getInt(p);
            System.out.println("getInt$setInt = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取/设置 long 类型字段值
    static void getLong$setLong() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("longField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            // 设置字段值
            field.setLong(p, 4L);
            // 获取字段值
            long obj = field.getLong(p);
            System.out.println("getLong$setLong = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取/设置 float 类型字段值
    static void getFloat$setFloat() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("floatField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            // 设置字段的值
            field.setFloat(p, 3.0F);
            // 获取字段的值
            float obj = field.getFloat(p);
            System.out.println("getFloat$setFloat = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 获取/设置 double 类型字段值
    static void getDouble$setDouble() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("doubleField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问
            // 设置字段的值
            field.setDouble(p, 6.01);
            // 获取字段的值
            double obj = field.getDouble(p);
            System.out.println("getDouble$setDouble = " + obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 返回一个AnnotatedType对象,该对象包含类型等信息
    static void getAnnotatedType() {
        Person p = new Person();
        Class clazz = Person.class;
        Field field = null;
        try {
            field = clazz.getDeclaredField("doubleField");
            field.setAccessible(true); // 调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问

            // 获取字段的值
            AnnotatedType obj = field.getAnnotatedType();
            System.out.println("getAnnotatedType = " + obj.getType());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

class Person<T> {

    private Pay pay;
    private String name;
    private T address;
    private boolean deleteFlag;
    private byte byteField;
    private char charField;
    private short shortField;
    private int intField;
    private long longField;
    private float floatField;
    private double doubleField;

    public double getDoubleField() {
        return doubleField;
    }

    public void setDoubleField(double doubleField) {
        this.doubleField = doubleField;
    }

    public float getFloatField() {
        return floatField;
    }

    public void setFloatField(float floatField) {
        this.floatField = floatField;
    }

    public long getLongField() {
        return longField;
    }

    public void setLongField(long longField) {
        this.longField = longField;
    }

    public int getIntField() {
        return intField;
    }

    public void setIntField(int intField) {
        this.intField = intField;
    }

    public short getShortField() {
        return shortField;
    }

    public void setShortField(short shortField) {
        this.shortField = shortField;
    }

    public char getCharField() {
        return charField;
    }

    public void setCharField(char charField) {
        this.charField = charField;
    }

    public Person() {
    }

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

    public Person(boolean deleteFlag) {
        this.deleteFlag = deleteFlag;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public byte getByteField() {
        return byteField;
    }

    public void setByteField(byte byteField) {
        this.byteField = byteField;
    }

    public Pay getPay() {
        return pay;
    }

    public void setPay(Pay pay) {
        this.pay = pay;
    }

    public T getAddress() {
        return address;
    }

    public void setAddress(T address) {
        this.address = address;
    }

    public boolean isDeleteFlag() {
        return deleteFlag;
    }

    public void setDeleteFlag(boolean deleteFlag) {
        this.deleteFlag = deleteFlag;
    }
}

enum Pay {
    PAY
}

三、调用方法

Class类提供了以下几个方法来获取Method

  • Method getMethod(name, Class…):获取某个public的Method(包括父类)
  • Method getDeclaredMethod(name, Class…):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有public的Method(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)

示例

public class Main {
    public static void main(String[] args) throws Exception {
        Class stdClass = Student.class;
        // 获取public方法getScore,参数为String:
        System.out.println(stdClass.getMethod("getScore", String.class));
        // 获取继承的public方法getName,无参数:
        System.out.println(stdClass.getMethod("getName"));
        // 获取private方法getGrade,参数为int:
        System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));
    }
}

class Student extends Person {
    public int getScore(String type) {
        return 99;
    }
    private int getGrade(int year) {
        return 1;
    }
}

class Person {
    public String getName() {
        return "Person";
    }
}

控制台显示

public int Student.getScore(java.lang.String)
public java.lang.String Person.getName()
private int Student.getGrade(int)

一个 Method 对象包含一个方法的所有信息:

  • getName() 返回方法名称
  • getReturnType() 返回方法返回值类型
  • getParamMeterTypers() 返回方法的参数类型,是一个 Class 数组
  • getModifiers() 返回方法修饰符,它是一个 int,不同int表示不同含义

3.1、 普通方法调用

获取到一个Method对象时,就可以对它进行调用。代码为例:

String s = "Hello world";
String r = s.substring(6); // "world"

反射来调用substring方法,需要以下代码:

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        // String对象:
        String s = "Hello world";
        // 获取String substring(int)方法,参数为int:
        Method m = String.class.getMethod("substring", int.class);
        // 在s对象上调用该方法并获取结果:
        String r = (String) m.invoke(s, 6);
        // 打印调用结果:
        System.out.println(r);
    }
}

Method实例调用invoke就相当于调用该方法,invoke的第一个参数是对象实例,即在哪个实例上调用该方法,后面的可变参数要与方法参数一致,否则将报错。

3.2、 静态方法调用

获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null。以Integer.parseInt(String)为例:

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        // 获取Integer.parseInt(String)方法,参数为String:
            Method m = Integer.class.getMethod("parseInt", String.class);
        // 调用该静态方法并获取结果:
        Integer n = (Integer) m.invoke(null, "12345");
        // 打印调用结果:
        System.out.println(n);// 12345
    }
}

3.3、 非 public 方法调用

对于非public方法,虽然可以通过Class.getDeclaredMethod()获取该方法实例,但直接对其调用将得到一个IllegalAccessException。为了调用非public方法,我们通过Method.setAccessible(true)允许其调用:

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        Person p = new Person();
        Method m = p.getClass().getDeclaredMethod("setName", String.class);
        m.setAccessible(true);
        m.invoke(p, "Bob");
        System.out.println(p.name); // Bob
    }
}

class Person {
    String name;
    private void setName(String name) {
        this.name = name;
    }
}

需要注意的话,setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager,那么它会根据规则进行检查,有可能阻止setAccessible(true)。例如,某个SecurityManager可能不允许对java和javax开头的package的类调用setAccessible(true),这样可以保证JVM核心库的安全。

3.4、 多态方法调用

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        // 获取Person的hello方法:
        Method h = Person.class.getMethod("hello");
        // 对Student实例调用hello方法:
        h.invoke(new Student());
    }
}

class Person {
    public void hello() {
        System.out.println("Person:hello");
    }
}

class Student extends Person {
    public void hello() {
        System.out.println("Student:hello");
    }
}

控制台显示

Student:hello

使用反射调用方法时,仍然遵循多态原则:即总是调用实际类型的覆写方法(如果存在)。上述的反射代码:

Method m = Person.class.getMethod("hello");
m.invoke(new Student());

相当于:

Person p = new Student();
p.hello();

Method扩展方法


方法

描述
Class<?> getReturnType() 获取方法返回类型
Type getGenericReturnType() 获取方法返回类型,返回类型是参数化类型
Object invoke(Object obj, Object… args) 调用该方法并获取结果
boolean isBridge() 判断是否桥接方法
boolean isDefault() 判断是否isDefault方法
Object getDefaultValue() 获取默认值

示例

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Comparator;

public class Main {
    public static void main(String[] args) throws Exception {
        // 获取方法返回类型
        getReturnType();
        // 获取方法返回类型,返回类型是参数化类型
        getGenericReturnType();
        //调用该方法并获取结果
        invoke();
        // 判断是否桥接方法
        isBridge();
        // 判断是否isDefault方法
        isDefault();
        // 获取默认值
        getDefaultValue();
    }

    // 获取方法返回类型
    static void getReturnType() {
        Person p = new Person();
        Method m = null;
        try {
            m = p.getClass().getDeclaredMethod("getName");
            m.setAccessible(true);
            Class clazz = m.getReturnType();
            System.out.println("getReturnType= " + clazz);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    // 获取方法返回类型,返回类型是参数化类型
    static void getGenericReturnType() {
        Person p = new Person();
        Method m = null;
        try {
            m = p.getClass().getDeclaredMethod("say");
            m.setAccessible(true);
            Type clazz = m.getGenericReturnType();
            System.out.println("getGenericReturnType= " + clazz);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    //调用该方法并获取结果:
    static void invoke() {
        Student p = new Student();
        Method m = null;
        try {
            m = p.getClass().getDeclaredMethod("setName", String.class);
            m.setAccessible(true);
            m.invoke(p, "Kevin");
            System.out.println("invoke= " + p.name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 判断是桥接方法
    static void isBridge() {
        Class<B> classB = B.class;
        Method[] methods = classB.getDeclaredMethods();

        System.out.println("方法总数量:" + methods.length);
        for (Method method : methods) {
            System.out.println(method.getReturnType().getSimpleName() + " "
                    + method.getName() +
                    "(" + method.getParameters()[0].getType().getSimpleName() + ")"
                    + " is " + (method.isBridge() ? "bridge" : "common") + " method"
            );
        }
    }

    // 判断是否isDefault方法
    static void isDefault() {
        Class c = Comparator.class;
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            // check whether method is Default Method or not
            if (method.isDefault()) {
                // print Method name
                System.out.println("isDefault = " + method.getName() + "  " + method.isDefault());
            }

        }
    }

    // 获取默认值
    static void getDefaultValue() {
        try {
            Method method = AnnotationDemo.class.getDeclaredMethod("fauvMovie");
            System.out.println("getDefaultValue =" + method.getDefaultValue());
        } catch (Exception e) {

        }

    }


}

@interface AnnotationDemo {
    public String fauvMovie() default "Inception";

    public double fauvMovieRating() default 9.6;

    public int fauvMovieReleaseYear();
}

class Person<T> {
    String name;

    private void setName(String name) {
        this.name = name;
    }

    public T say() {
        return null;
    }

    public String getName() {
        return name;
    }


}

class Student {
    String name;

    private void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}


// 声明一个泛型接口
interface A<T> {
    void test(T t);
}

//泛型本身是语言级别的,经过编译后,泛型就会被擦除,所以接口 A 在编译后,test 方法的入参会被转换为 Object
//编译器编译
//public interface A {
//    void test(Object t);
//}

// 使用 String 类型实现一个具体的实现类
class B implements A<String> {
    public void test(String s) {
        System.out.println(s);
    }
}

//实现类 B 中的实现方法是 void test(String s),其实根本就没有实现 void test(Object t) 方法。但是这个代码是正确的,可以正常运行,因为 JVM 在编译过程中对我们的实现类做了一点手脚
//编译器编译
//public class B implements A {
//    public void test(String s) {
//        System.out.println(s);
//    }
//    public void test(Object s) {
//        this.test((String) s);
//    }
//}



四、调用构造方法

通过创建对象实例:

Person p = new Person();

调用Class提供的newInstance()方法

Person p = Person.class.newInstance();

调用Class.newInstance()的局限是,它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。

为了调用任意的构造方法,Java的反射API提供了Constructor对象,它包含一个构造方法的所有信息,可以创建一个实例。Constructor对象和Method非常类似,不同之处仅在于它是一个构造方法,并且,调用结果总是返回实例:

import java.lang.reflect.Constructor;

public class Main {
    public static void main(String[] args) throws Exception {
        // 获取构造方法Integer(int):
        Constructor cons1 = Integer.class.getConstructor(int.class);
        // 调用构造方法:
        Integer n1 = (Integer) cons1.newInstance(123);
        System.out.println(n1);

        // 获取构造方法Integer(String)
        Constructor cons2 = Integer.class.getConstructor(String.class);
        Integer n2 = (Integer) cons2.newInstance("456");
        System.out.println(n2);
    }
}

Class实例获取Constructor的方法如下

  • getConstructor(Class…):获取某个public的Constructor
  • getDeclaredConstructor(Class…):获取某个Constructor
  • getConstructors():获取所有public的Constructor
  • getDeclaredConstructors():获取所有Constructor

注意Constructor总是当前类定义的构造方法,和父类无关,因此不存在多态的问题。

调用非public的Constructor时,必须首先通过setAccessible(true)设置允许访问,setAccessible(true)可能会失败。



版权声明:本文为u012965203原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。