Java反射

1 Java反射基础

1.1 获得 Class 对象的三种方法

Class.forName()

类.class

对象.getClass()

 

(1)使用 Class 类的 forName 静态方法:

public static Class<?> forName(String className)

比如在 JDBC 开发中常用此方法加载数据库驱动

Class.forName(driver);

 

(2)直接获取某一个对象的 class,比如:

Class<?> klass = int.class;

Class<?> classInt = Integer.TYPE;

 

(3)调用某个对象的 getClass() 方法,比如:

StringBuilder str = new StringBuilder("123");

Class<?> klass = str.getClass();

 

1.2 创建实例

(1)使用Class对象的newInstance()方法

Class<?> c = String.class;

Object str = c.newInstance();

 

(2)先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

//获取String所对应的Class对象

Class<?> c = String.class;

//获取String类带一个String参数的构造器

Constructor constructor = c.getConstructor(String.class);

//根据构造器创建实例

Object obj = constructor.newInstance("23333");

System.out.println(obj);

 

1.3 获取属性

getFiled:访问公有的成员变量

getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量

getFileds 和 getDeclaredFields 方法用法同上(参照 Method)。

 

1.4 获取方法

(1)getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

public Method[] getDeclaredMethods() throws SecurityException

(2)getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

public Method[] getMethods() throws SecurityException

(3)getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

public Method getMethod(String name, Class<?>... parameterTypes)

 

当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法

Class<?> klass = methodClass.class;

//创建methodClass的实例

Object obj = klass.newInstance();

//获取methodClass类的add方法

Method method = klass.getMethod("add",int.class,int.class);

//调用method对应的方法 => add(1,4)

Object result = method.invoke(obj,1,4);

 

1.5 获取构造器

通过Class类的getConstructor方法得到Constructor类的一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例

 

1.6 判断是否是某个类的实例

一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例

 

注意:

1.getFields和getDeclaredFields的区别:

getFields:获取当前类的public变量和父类public变量

getDeclaredFields:获取当前类的所有变量,但不会获取父类变量

 

2.getMethods和getDeclaredMethods的区别:

getMethods:获取当前类的public方法和父类public方法。注意所有类都继承自Object,所以也会获取Object类的public方法。

getDeclaredMethods:获取当前类的所有方法,但不会获取父类方法。

学一学,练一练

(代码来源:https://juejin.im/post/598ea9116fb9a03c335a99a4

public class FatherClass {
    public String mFatherName;
    public int mFatherAge;

    public void printFatherMsg(){}
}

 

public class SonClass extends FatherClass{

    private String mSonName;
    protected int mSonAge;
    public String mSonBirthday;

    public void printSonMsg(){
        System.out.println("Son Msg - name : "
                + mSonName + "; age : " + mSonAge);
    }

    private void setSonName(String name){
        mSonName = name;
    }

    private void setSonAge(int age){
        mSonAge = age;
    }

    private int getSonAge(){
        return mSonAge;
    }

    private String getSonName(){
        return mSonName;
    }
}
/**
 * @Description TODO
 * @Author lilong
 * @Date 2018-11-14 11:43
 */
public class Main {
    public static void main(String[] args) {
        printFields();
        System.out.println("###################################");
        printMethods();
    }

    /**
     * 通过反射获取类的所有变量
     */
    private static void printFields(){
        //1.获取并输出类的名称
        Class mClass = SonClass.class;
        System.out.println("类的名称:" + mClass.getName());

        //2.1 获取所有 public 访问权限的变量
        // 包括本类声明的和从父类继承的
        Field[] fields = mClass.getFields();

        //2.2 获取所有本类声明的变量(不问访问权限)
        //Field[] fields = mClass.getDeclaredFields();

        //3. 遍历变量并输出变量信息
        for (Field field : fields) {
            //获取访问权限并输出
            int modifiers = field.getModifiers();
            System.out.print(Modifier.toString(modifiers) + " ");
            //输出变量的类型及变量名
            System.out.println(field.getType().getName() + " " + field.getName());
        }
    }

    /**
     * 通过反射获取类的所有方法
     */
    private static void printMethods(){
        //1.获取并输出类的名称
        Class mClass = SonClass.class;
        System.out.println("类的名称:" + mClass.getName());

        //2.1 获取所有 public 访问权限的方法
        //包括自己声明和从父类继承的
        Method[] mMethods = mClass.getDeclaredMethods();

        //2.2 获取所有本类的的方法(不问访问权限)
        //Method[] mMethods = mClass.getDeclaredMethods();

        //3.遍历所有方法
        for (Method method : mMethods) {
            //获取并输出方法的访问权限(Modifiers:修饰符)
            int modifiers = method.getModifiers();
            System.out.print(Modifier.toString(modifiers) + " ");
            //获取并输出方法的返回值类型
            Class returnType = method.getReturnType();
            System.out.print(returnType.getName() + " " + method.getName() + "( ");
            //获取并输出方法的所有参数
            Parameter[] parameters = method.getParameters();
            for (Parameter parameter: parameters) {
                System.out.print(parameter.getType().getName() + " " + parameter.getName() + ",");
            }
            //获取并输出方法抛出的异常
            Class[] exceptionTypes = method.getExceptionTypes();
            if (exceptionTypes.length == 0) {
                System.out.println(" )");
            }
            else {
                for (Class c : exceptionTypes) {
                    System.out.println(" ) throws " + c.getName());
                }
            }
        }
    }
}

运行下看看:

2 ReflectionUtils

1)查找指定的属性

Field findField(Class<?> clazz, String name, Class<?> type)

name:字段名,type:字段类型。类型可以不带。

 

2)查找指定的方法

Method findMethod(Class<?> clazz, String name, Class<?>... paramTypes)

name:方法名,paramTypes:参数类型,可不带

 

3)调用目标方法

Object invokeMethod(Method method, Object target, Object... args)

args可不带

学一学,练一练

public class SuperClass {
    private String fatherPrivate = "privateField爹也不太懂";
    protected String fatherProtected = "protectedField爹也不太懂";
    public String fatherPublic = "publicField爹也不太懂";

    private void fatherPrivateMethod(){
        System.out.println("父类private方法");
    }

    private void fatherProtectedMethod(){
        System.out.println("父类protected方法");
    }

    private void fatherPublicMethod(){
        System.out.println("父类public方法");
    }
}
public class SubClass extends SuperClass{
    private String privateField = "privateField大头儿子";
    protected String protectedField = "protectedField大头儿子";
    public String publicField = "publicField大头儿子";

    private void privateMethod() {
        System.out.println("子类private方法");
    }

    protected void protectedMethod() {
        System.out.println("子类protected方法");
    }

    public void publicMethod() {
        System.out.println("子类public方法");
    }

    public String getPrivateField() {
        return privateField;
    }

    public void setPrivateField(String privateField) {
        this.privateField = privateField;
    }

    public String getProtectedField() {
        return protectedField;
    }

    public void setProtectedField(String protectedField) {
        this.protectedField = protectedField;
    }

    public String getPublicField() {
        return publicField;
    }

    public void setPublicField(String publicField) {
        this.publicField = publicField;
    }
}
public class Main {
    public static void main(String[] args) {
        //获取属性值
        getAndPrintField("privateField");
        getAndPrintField("protectedField");
        getAndPrintField("publicField");

        System.out.println();

        //获取父类中的属性
        getAndPrintField("fatherPrivate");
        getAndPrintField("fatherProtected");
        getAndPrintField("fatherPublic");

        System.out.println();

        //获取方法
        getAndPrintMethod("privateMethod");
        getAndPrintMethod("protectedMethod");
        getAndPrintMethod("publicMethod");

        System.out.println();

        //获取父类方法
        getAndPrintMethod("fatherPrivateMethod");
        getAndPrintMethod("fatherProtectedMethod");
        getAndPrintMethod("fatherPublicMethod");
    }

    private static void getAndPrintField(String filedName) {
        SubClass test = new SubClass();
        //获取属性
        Field field = ReflectionUtils.findField(test.getClass(), filedName, String.class);
        //赋权限,否则会抛IllegalStateException
        ReflectionUtils.makeAccessible(field);
        String val = (String)ReflectionUtils.getField(field, test);
        System.out.println(val);
    }

    private static void getAndPrintMethod(String methodName){
        SubClass test = new SubClass();
        Method method = ReflectionUtils.findMethod(test.getClass(), methodName);
        ReflectionUtils.makeAccessible(method);
        ReflectionUtils.invokeMethod(method, test);
    }
}

运行下看看:

嗯,可以获取所有变量、方法,包括父类的

3 反射的应用

Spring、MyBatis、Dubbo都大量使用了反射,例如Spring会根据xml中配置的beanName获取到Bean就用的反射。

后面再专门写博客介绍反射的应用吧。

还有一个用处是写单测的时候,可能方法是private的,这个时候我们可以用反射调用这个方法:

public class TestClass {

    private String MSG = "Original";

    private void privateMethod(String head , int tail){
        System.out.print(head + tail);
    }

    public String getMsg(){
        return MSG;
    }
}
public class UnitTest {
    public static void main(String[] args) {
        try {
            TestClass testClass = new TestClass();
            Method method = TestClass.class.getDeclaredMethod("privateMethod", String.class, int.class);
            method.setAccessible(true);
            method.invoke(testClass, "我是头", 666);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

跑跑看:

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值