Java笔记--反射

Java笔记–反射

什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制

java程序中许多对象在运行时都会出现两种类型:编译时的类型和运行时的类型,比如Person p = new Student() ,这行代码会生成一个p变量,该变量编译时类型为Person,运行时类型为Student,假如程序在接受到外部传入的一个对象,该对象的编译时的类型为Objective,但程序又需要调用该对象运行时类型的方法,此时有,两种解决方法,一种是强制转换,还有一种就是依靠反射了

以Person p = new Student()为例,当我们new Student时,JVM会加载Student.class文件,JVM会去磁盘中找到这个.class文件然后加载到内存中,穿件一个class对象并且分配内存,此时若再new Student,不会再产生一个对象,一个类只产生一个class对象

1,反射的使用

Class对象获取该类的方法:Method对象
Class对象获取该类的构造器:Constructor对象
Class对象获取该类的成员变量:Field对象

1.1,获取该类的方法

1).批量的方法:
public Constructor[] getConstructors():所有”公有的”构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

2).获取单个的方法,并调用:
public Constructor getConstructor(Class… parameterTypes):获取单个的”公有的”构造方法:
public Constructor getDeclaredConstructor(Class… parameterTypes):获取”某个构造方法”可以是私有的,或受保护、默认、公有;

调用构造方法:
Constructor–>newInstance(Object… initargs)

2、newInstance是 Constructor类的方法(管理构造函数的类)
api的解释为:
newInstance(Object… initargs)使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象。并为之调用

public class Student_1 {
    //默认构造方法
    Student_1(String str){
        System.out.println("默认的构造方法:"+str);
    }

    //无参构造方法
    public Student_1() {
        System.out.println("这是一个公有无参构造方法");
    }

    //有一个参数的构造方法
    public Student_1(char name) {
        System.out.println("姓名:"+name);
    }

    //有多个参数的构造方法
    public Student_1(char name,int age) {
        System.out.println("姓名:"+name+"年龄:"+age);
    }

    //受保护的构造方法
    protected Student_1(boolean n){
        System.out.println("受保护的构造方法 :" + n);
    }

    //私有构造方法
    private Student_1(int age){
        System.out.println("私有的构造方法   年龄:"+ age);
    }
}
import java.lang.reflect.Constructor;

public class Constructors {
    public static void main(String[] args) throws Exception{
        //加载Class对象
        Class clazz = Class.forName("day8_7.Student_1");

        //获取所有公有的构造方法
        System.out.println("*****获取公有构造方法*****");
        Constructor[] conArray = clazz.getConstructors();
        for(Constructor c : conArray) {
            System.out.println(c);
        }

        System.out.println("*****所有的构造方法*****");
        conArray = clazz.getDeclaredConstructors();
        for(Constructor c : conArray) {
            System.out.println(c);
        }

        System.out.println("*****获取公有无参构造方法*****");
        Constructor con = clazz.getConstructor(null);

        System.out.println("con="+con);
        //调用构造方法
        Object obj = con.newInstance();
        System.out.println("obj = " + obj);
        Student_1 stu = (Student_1)obj;

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

结果

*****获取公有构造方法*****
public day8_7.Student_1(char,int)
public day8_7.Student_1(char)
public day8_7.Student_1()
*****所有的构造方法*****
private day8_7.Student_1(int)
protected day8_7.Student_1(boolean)
public day8_7.Student_1(char,int)
public day8_7.Student_1(char)
public day8_7.Student_1()
day8_7.Student_1(java.lang.String)
*****获取公有无参构造方法*****
con=public day8_7.Student_1()
这是一个公有无参构造方法
obj = day8_7.Student_1@15db9742
******************获取私有构造方法,并调用*******************************
public day8_7.Student_1(char)
姓名:男

1.2,获取该类的成员变量

1.批量的
1).Field[] getFields():获取所有的”公有字段”
2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;
2.获取单个的:
1).public Field getField(String fieldName):获取某个”公有的”字段;
2).public Field getDeclaredField(String fieldName):获取某个字段(可以是私有的)

设置字段的值:
Field –> public void set(Object obj,Object value):
参数说明:
1.obj:要设置的字段所在的对象;
2.value:要为字段设置的值;

1.3,获取成员方法并调用

  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:调用方式时所传递的实参;

1.4,通过反射运行配置文件内容

Student 类

/*
 * 通过反射运行配置文件内容
 */
public class Student {
    public void show() {
        System.out.println("show");
    }
}

配置文件Pro.txt:

className = day8_7.Student
methodName = show

测试类

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;

public class StudentTest {
    public static void main(String[] args) throws Exception{
        //通过反射获取Class对象
        Class stuClass = Class.forName("day8_7.Student");

        //获取show方法
        Method m = stuClass.getMethod(getValue("methodName"));

        //调用show方法
        m.invoke(stuClass.getConstructor().newInstance());
    }

    public static String getValue(String key) throws IOException{
        //获取配置文件的对象
        Properties pro = new Properties();
        //获取输入流
        FileReader in = new FileReader("F:\\pro.txt");
        //将流加载到配置文件
        pro.load(in);
        in.close();
        //返回根据key获取的value值
        return pro.getProperty(key);
    }
}

运行结果:
show

利用反射和配置文件,可以使应用程序更新时对源码无需任何修改,只要将新类发送给客户端并修改配置文件

要替换的student2类:

public class Student2 {
    public void show2(){
        System.out.println("is show2()");
    }
}

配置文件更改为:

className = cn.fanshe.Student2
methodName = show2

控制台输出:
is show2();

参考博客点这里

你可能感兴趣的:(Java)