Java中的反射总结

释放双眼,带上耳机,听听看~!

反射:框架设计的灵魂
在现实开发中一般会使用到框架,使用框架能大量的减少代码的重复使用,而框架又是由很多反射机制写成的。
如果在开发过程中你不懂反射机制,那么你可以使用别人已经写好的框架,如果你希望使用自己写的框架,那么反射就需要掌握了。

获取class对象的三种方式

1.class.forName(全类名)
将字节码文件加载进内存,返回class对象
这种方式多用于配置文件,将类名定义在配置文件中,读取文件,加载类

Class c1 = Class.forName("unit.test.Teacher");
System.out.println(c1);
//运行结果:class unit.test.Teacher

2,类名.class
通过类名的属性class,获取class对象
这种方式多用于参数的传递

Class c2 = Teacher.class;
System.out.println(c2);
//运行结果:class unit.test.Teacher

3,对象.getclass()
通过getClass()方法获取,该方法在object类中定义
这种方法多用于对象的获取字节码方式。

Teacher t = new Teacher();
Class c3 = t.getClass();
System.out.println(c3);
//运行结果:class unit.test.Teacher

比较三个对象地址

三个Class对象均为同一个对象,地址相同。同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,无论通过哪一种方式获取到的Class对象都是同一个对象。

System.out.println(c1 == c2);
System.out.println(c1 == c3);
//返回值均为true

class对象的功能

先列举Teacher类。

package unit.test;

public class Teacher {
    //private String name;
    //private int ID;

    public String name ;
    protected int ID;
    String c;
    private String d;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void eat() {
        System.out.println("eat");
    }
    public void eat(String S) {
        System.out.println("eat foods");
    }
    public int getID() {
        return ID;
    }
    public void setID(int iD) {
        ID = iD;
    }
    @Override
    public String toString() {
        return "Teacher [name=" + name + ", ID=" + ID + ", c=" + c + ", d=" + d + "]";
    }


}

1,获取成员变量

获取多个 public 成员变量 :
Filed[] getFileds() 只能获取所有public修饰的成员变量

Class teacherClass = Teacher.class;

Field[] fields = teacherClass.getFields();
    for(Field f : fields) {
        System.out.println(f);
    }

//输出 public java.lang.String unit.test.Teacher.name

获取单个 public 成员变量 :
Filed getFiled(String name)获取指定public修饰的成员变量

   //获取对象指定对象的值
   
   
    Class teacherClass = Teacher.class;
    //先获取到成员变量字段
    Field fieldName = teacherClass.getField("name");
    //给定对象
    Teacher t = new Teacher();
    //获取该对象的成员变量值
    Object value = fieldName.get(t);
    System.out.println(value);
  
    //结果输出null(String的默认值)
//设置对象指定字段的值


Class teacherClass = Teacher.class;
//先获取到成员变量字段
Field fieldName = teacherClass.getField("name");
//给定对象
Teacher t = new Teacher();
//设定该对象的成员变量值
fieldName.set(t, "wang");
System.out.println(t.name);

//输出结果:wang

获取多个任意修饰指定字段的成员变量(暴力破解)
Field [] getDeclaredFields()

//获取多个任意修饰指定字段的成员变量


Class teacherClass = Teacher.class;
Field[] declaredFields = teacherClass.getDeclaredFields();
for(Field declaredField : declaredFields) {
    System.out.println(declaredField);
}


/*输出结果:
public java.lang.String unit.test.Teacher.name
protected int unit.test.Teacher.ID
java.lang.String unit.test.Teacher.c
private java.lang.String unit.test.Teacher.d
*/

获取单个任意修饰符指定的成员变量(暴力破解)
Field getDeclaredField(String S)

//获取单个任意修饰符指定的成员变量


//给定对象
Teacher t = new Teacher();
Field d = teacherClass.getDeclaredField("d");
//忽略访问修饰符的安全检查,保证访问到非public修饰的成员变量
d.setAccessible(true);//也叫做暴力反射
Object o = d.get(t);

//测试结果:null(默认初始值)

2,获取构造方法

获取多个无参构造方法:
Constructor<?>[] getConstructor

获取单个构造方法
Constructor<T> getConstructors(类<?> … parameterTypes)

//获取Teacher的class对象
Class teacherClass = Teacher.class;
//获取特定参数的构造器,括号内是构造方法的参数
Constructor constructor = teacherClass.getConstructor(String.class,int.class);
System.out.println(constructor);


//测试结果:public unit.test.Teacher(java.lang.String,int)
//通过构造器构造对象


//获取Teacher的class对象
Class teacherClass = Teacher.class;
//获取特定参数的构造器,括号内是构造方法的参数
Constructor constructor = teacherClass.getConstructor(String.class,int.class);
//创建对象
Object teacher_2 = constructor.newInstance("张三",23);
System.out.println(teacher_2);

//如果是创建无参构造除了上面的方法还可以用第二种简化版方法,直接用class对象的newInstance()方法
        teacherClass.newInstance();

//结果:Teacher [name=张三, ID=23, c=null, d=null]

获取多个构造方法()——暴力破解
Constructor<T>[] getDeclaredConstructor ()

获取单个构造方法 ——暴力破解
Constructor<?> getDeclaredConstructor(类<?>… parameterTypes )

3,获取成员方法:

获取多个成员方法
Method[] getMethod()

//获取多个方法

//获取Teacher的class对象
Class teacherClass = Teacher.class;

Method[] methods = teacherClass.getMethods();
for(Method method : methods) {
    System.out.println(method);
}

//测试结果:(除了子类的方法,还有很多父类object隐藏的方法)
/*
public int unit.test.Teacher.getID()
public java.lang.String unit.test.Teacher.toString()
public java.lang.String unit.test.Teacher.getName()
public void unit.test.Teacher.setName(java.lang.String)
public void unit.test.Teacher.eat(java.lang.String)
public void unit.test.Teacher.eat()
public void unit.test.Teacher.setID(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

*/

获取单个成员方法
Method getMethod(String name,类<?>… parameterTypes )

//无参的方法

//获取Teacher的class对象
Class teacherClass = Teacher.class;
//获取指定名称方法
Method eat_method = teacherClass.getMethod("eat");
Teacher t1 = new Teacher();
//执行方法
eat_method.invoke(t1);

//测试结果:eat
//有参的方法

//获取Teacher的class对象
Class teacherClass = Teacher.class;
//获取指定名称方法
Method eat_method_2 = teacherClass.getMethod("eat",String.class);
Teacher t2 = new Teacher();
//执行方法
eat_method_2.invoke(t2,"S");

//测试结果:eat foodsS

获取多个成员方法(暴力破解)
Method[] getDeclaredMethod()

获取单个成员方法(暴力破解)
Method getDeclaredMethod(String name,类<?>… parameterTypes )

4,获取类名

String getName()

//获取类名
Class teacherClass = Teacher.class;
String className = teacherClass.getName();
System.out.println(className);

//输出结果:
//unit.test.Teacher

小案例

需求:通过一个简易”框架”可以创建任意类对象,并且执行其中的任意方法
要求:无需改动任何代码,创建任意类对象,可以执行任意方法。
实现:配置文件+反射

步骤:
1,将需要创建对象的全类名和需要执行的方法定义在配置文件中

//test.properties

ClassName=unit.test.Teacher
Method=eat

2,在程序中加载读取配置文件

//创建 properties对象
Properties pro = new Properties();
//加载配置文件,转换为一个集合
//获取class目录下的配置文件,用类加载器接收
ClassLoader classloader = MainTest.class.getClassLoader();
InputStream is = classloader.getResourceAsStream("test.properties");
pro.load(is);

//获取配置文件中定义的数据
String className = pro.getProperty("ClassName");
String methodName = pro.getProperty("Method");

3,使用反射技术来加载类文件进入内存

//加载该类进入内存
Class cla = Class.forName(className);

4,创建对象

//创建对象
Object obj = cla.newInstance();
//获取方法对象
Method method = cla.getMethod(methodName);

5,执行方法

method.invoke(obj);

//输出:eat

给TA买糖
共{{data.count}}人
人已赞赏
知识分享

二进制八进制十六进制bcd码

2020-9-23 23:10:00

知识分享

网页中常见返回HTTP状态码含义

2020-9-24 19:44:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索