Java反射

前言

项目主体源码可以从reflectionDemo获得,喜欢的朋友可以点个star~。
参考文献在参考资料部分有介绍。

概述

在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以。
想要使用反射机制,就必须要先获取到该类的字节码文件对象(.class),通过字节码文件对象,就能够通过该类中的方法获取到我们想要的所有信息(方法,属性,类名,父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。
IT行业里这么说,没有反射也就没有框架,现有的框架都是以反射为基础。在实际项目开发中,用的最多的是框架,填的最多的是类,反射这一概念就是将框架和类揉在一起的调和剂。所以,反射才是接触项目开发的敲门砖。

Java获取Class对象的三种方法

Student.java

public class Student {
    //默认构造方法
    Student(String str){
        System.out.println("默认的构造方法 s = " + str);
    }
    //无参构造方法
    public Student(){
        System.out.println("调用公有无参构造方法");
    }
    //有一个参数的构造方法
    public Student(char name){
        System.out.println("name = " + name);
    }
    //有多个参数的构造方法
    public Student(String name, int age){
        System.out.println("name = " + name + "; age = " + age);
    }
    //受保护的构造方法
    protected Student(boolean n){
        System.out.println("受保护的构造方法 n = " + n);
    }
    //私有构造方法
    private Student(int age){
        System.out.println("私有的构造方法 age = " + age);
    }
}

Fanshe.java

public class Fanshe {
    public static void main(String[] args) {
        //第一种方法获取Class对象
        Student student = new Student(); //产生一个Student对象,一个Class对象
        Class stuClass = student.getClass(); //获取Class对象
        System.out.println(stuClass.getName());

        //第二种方法获取Class对象
        Class stuClass2 = Student.class;
        //这里来判断第一次和第二次获取是否为同一个
        System.out.println(stuClass == stuClass2);

        //第三种方法获取Class对象
        try {
            //这里路径需要指定包路径和class类路径
            Class stuClass3 = Class.forName("pers.xipiker.v1.Student");
            //这里来判断是否为同一个
            System.out.println(stuClass3 == stuClass2);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
获取构造方法

Student.java

public class Student {
    //默认构造方法
    Student(String str){
        System.out.println("默认的构造方法 s = " + str);
    }
    //无参构造方法
    public Student(){
        System.out.println("调用公有无参构造方法");
    }
    //有一个参数的构造方法
    public Student(char name){
        System.out.println("name = " + name);
    }
    //有多个参数的构造方法
    public Student(String name, int age){
        System.out.println("name = " + name + "; age = " + age);
    }
    //受保护的构造方法
    protected Student(boolean n){
        System.out.println("受保护的构造方法 n = " + n);
    }
    //私有构造方法
    private Student(int age){
        System.out.println("私有的构造方法 age = " + age);
    }
}

Constructors.java

/**
 * 通过Class对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员;
 * 1.获取构造方法:
 * 批量的方法:
 *     public Constructor[] getConstructors():所有"公有的"构造方法;
 *     public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有);
 * 获取单个的方法:
 *     public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的、无参"的构造方法;
 *     public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有、无参;
 * 调用构造方法:
 *     Constructor-->newInstance(Object... initrags)
 *     newInstance(管理构造函数的类):使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
 *     它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用
 */
public class Constructors {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.加载Class对象
        Class clazz = Class.forName("pers.xipiker.v1.Student");
        //2.获取所有"公有的"构造方法
        System.out.println("******************所有公有的构造方法****************");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c : constructors){
            System.out.println(c);
        }
        //3.获取所有的构造方法(包括私有、受保护、默认、公有)
        System.out.println("******************获取所有的构造方法(包括私有、受保护、默认、公有)****************");
        Constructor[] constructors1 = clazz.getDeclaredConstructors();
        for (Constructor c : constructors1){
            System.out.println(c);
        }
        //4.获取单个的"公有、无参"构造方法
        System.out.println("******************获取单个的公有、无参构造方法****************");
        Constructor con = clazz.getConstructor(null);
        System.out.println(con);
        //Object obj = con.newInstance();
        //System.out.println("obj = " + obj);

        //5.获取私有构造方法,并调用
        System.out.println("******************获取私有构造方法,并调用****************");
        con = clazz.getDeclaredConstructor(char.class);
        System.out.println(con);
        //调用构造方法
        con.setAccessible(true); //暴力访问(忽略掉访问修饰符)
        Object obj = con.newInstance('男');
        //System.out.println(obj);
    }
}
获取成员变量

Student.java

public class Student {
    public Student(){

    }
    public String name;
    protected int age;
    char sex;
    private String phoneNum;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", phoneNum='" + phoneNum + '\'' +
                '}';
    }
}

Fields.java

/**
 * 获取成员变量并调用:
 * 1.批量:
 *      Field[] getFields():获取所有的"公有字段";
 *      Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
 * 2.获取单个:
 *      public Field getField(String fieldName):获取某个"公有的"字段;
 * 		public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的);
 * 设置字段的值:
 *      Field --> public void set(Object obj,Object value):
 *      参数说明:
 *          obj:要设置的字段所在的对象;
 *          value:要为字段设置的值;
 */
public class Fields {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.获取Class对象
        Class clazz = Class.forName("pers.xipiker.v2.Student");
        //2.获取所有公有字段
        System.out.println("******************获取所有公有字段****************");
        Field[] fields = clazz.getFields();
        for(Field f : fields){
            System.out.println(f);
        }
        //3.获取所有字段,包括:私有、受保护、默认、公有
        System.out.println("******************获取所有字段,包括:私有、受保护、默认、公有****************");
        Field[] fields1 = clazz.getDeclaredFields();
        for (Field f : fields1){
            System.out.println(f);
        }
        //4.获取某个"公有的"字段
        System.out.println("******************获取某个公有的字段****************");
        //可以试验一下把name改为私有变量phoneNum,将会报java.lang.NoSuchFieldException这个异常
        Field f = clazz.getField("name");
        System.out.println(f);
        //获取一个对象,产生Student对象等同于(Student stu = new Student();)
        Object object = clazz.getConstructor().newInstance();
        f.set(object, "xipiker");
        //验证
        Student student = (Student)object;
        System.out.println("验证:" + student.name);
        //5.获取某个字段(可以是私有的)
        f = clazz.getDeclaredField("phoneNum");
        System.out.println(f);
        //暴力反射,接触私有限定,没有加的话会报java.lang.IllegalAccessException这个异常
        f.setAccessible(true);
        f.set(object, "13513513513");
        System.out.println("验证电话:" + student);
    }
}
获取成员方法

Student.java

public class Student {
    public void show1(String s){
        System.out.println("show1-公有方法-s-" + s);
    }
    protected void show2(){
        System.out.println("show2-受保护方法-无参");
    }
    void show3(){
        System.out.println("show3-默认方法-无参");
    }
    private String show4(int age){
        System.out.println("show4-私有方法-age-" + age);
        return "xipiker";
    }
}

MethodClazz.java

/**
 * 获取成员方法并调用:
 * 1.批量:
 *      public Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类);
 *      public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的);
 * 2.获取单个:
 * 		public Method getMethod(String name,Class<?>... parameterTypes)(获取公有):
 * 	    参数:
 * 	        name:方法名;
 * 	        Class...:形参的Class类型对象;
 * 	    public Method getDeclaredMethod(String name,Class<?>... parameterTypes)(获取私有)
 * 调用方法:
 *      Method --> public Object invoke(Object obj,Object... args):
 *      参数:
 *          obj:要调用方法的对象;
 *          args:调用方式时所传递的实参;
 */
public class MethodClazz {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //1.获取Class对象
        Class clazz = Class.forName("pers.xipiker.v3.Student");
        //2.获取所有"公有方法"
        System.out.println("******************获取所有公有方法****************");
        Method[] methods = clazz.getMethods();
        for (Method m : methods){
            System.out.println(m);
        }
        //3.获取所有的成员方法,包括私有的(不包括继承的)
        System.out.println("******************获取所有的成员方法,包括私有的(不包括继承的)****************");
        methods = clazz.getDeclaredMethods();
        for (Method m : methods){
            System.out.println(m);
        }
        //4.获取公有的show1()方法
        System.out.println("******************获取公有的show1()方法****************");
        Method m = clazz.getMethod("show1", String.class);
        System.out.println(m);
        //实例化一个Student对象
        Object object = clazz.getConstructor().newInstance();
        m.invoke(object, "xipiker");
        //5.获取私有的show4()方法
        System.out.println("******************获取私有的show4()方法****************");
        m = clazz.getDeclaredMethod("show4", int.class);
        System.out.println(m);
        //解除私有限定
        m.setAccessible(true);
        Object object2 = m.invoke(object, 20);
        System.out.println("return:"+object2);
    }
}
反射main方法

Student.java

public class Student {
    public static void main(String[] args) {
        System.out.println("main方法执行-" + args[0] + "-" + args[1]);
    }
}

Main.java

public class Main {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1.获取Student对象的字节码
        Class clazz = Class.forName("pers.xipiker.v4.Student");
        //2.获取main方法
        Method method = clazz.getMethod("main", String[].class);
        //3.调用main方法
        method.invoke(null, (Object)new String[]{"a","b"});
    }
}
通过反射运行配置文件内容

pro.txt

className = pers.xipiker.v5.Student
methodName = show

Student.java

public class Student {
    public void show(){
        System.out.println("is show()");
    }
}

ReflectLodFile.java

/**
 * 利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改,
 * 只需要将新类发送给客户端,并修改配置文件即可。
 */
public class ReflectLodFile {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName(getValue("className"));
        Method method = clazz.getMethod(getValue("methodName"));
        method.invoke(clazz.getConstructor().newInstance());
    }

    //获取配置文件相应的value
    public static String getValue(String key) throws IOException {
        Properties pro = new Properties();
        //这里指定文件的绝对路径
        FileReader in = new FileReader("/Users/mac/Desktop/pro.txt");
        pro.load(in);
        in.close();
        return pro.getProperty(key);
    }
}
通过反射越过泛型检查

OverGeneric.java

/**
 *  通过反射越过泛型检查
 *  例如:有一个String泛型的集合,怎样能向这个集合中添加一个Integer类型的值?
 */
public class OverGeneric {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        ArrayList<String> list = new ArrayList<>();
        list.add("xipiker1");
        list.add("xipiker2");
        //插入Integer类型
        Class listClass = list.getClass();
        Method m = listClass.getMethod("add", Object.class);
        m.invoke(list, 100);
        //遍历集合
        for(Object object : list){
            System.out.println(object);
        }
    }
}
参考资料

Java基础之—反射(非常重要)
Java中反射机制详解
谈谈Java反射机制
练习源码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值