java基础中的反射机制

时间:2021-09-22 11:23:01

目的:为了了解注解式框架的原理 ViewInject bindView Retrofit2等,里面都用到了注解,底层都是通过反射实现的


什么是java中的反射机制?

通过Class对象,获取字节码文件中的成员变量,构造方法,普通方法的机制

1)反射机制是对类而言的,目的是为了获取类的所有属性和方法

Java反射机制实在程序运行状态中,对于任意一个类,都能知道这个类的所有的属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象方法的功能就是java语言的反射机制。

2)要想使用反射,必须知道该类的字节码文件对象(对应类的字节码文件)

3)如何获取字节码文件对应的类对象?


反射机制中常用的类及方法:(总共四个类)

Method类 Class类 Constructor构造函数类 Field字段类

forName("全类名");   获取字节码文件对象

getConstructor()  获取指定类型的构造函数 注意s

newInstance()  通过构造函数创建对象,构造方法将会被执行!

getField() 获取成员变量

getMethod(name,参数类型) 获取的方法的名称,和方法的参数类型

invoke(当前类的对象,方法的参数)  通过反射获取的方法如何执行 Method类对象调用的方法

method.setAccessible(true);


getDeclaredConstructor() 获取私有的构造函数

getDeclaredMethod()  获取私有的成员方法

getDeclaredField() 获取私有的成员变量


get()方法

set()

修改成员的值:set(Object obj,Object value)
将指定对象变量上此成员变量对象表示的字段值设置为指定的新值。


反射一般的操作步骤:

1)通过全类名,获取类对象,即类的字节码文件的操作

2)通过类对象,获取类的构造函数

3)通过构造函数,创建对象

4)通过对象,执行其中的方法


1)通过反射获取构造方法并使用

2)通过反射获取成员变量并使用

3)通过反射获取成员方法并使用

4)如果是私有的,就“Declared”+“暴力破解”


特点:

反射机制其实就是学习这四个类的api,反射是一种编程思想.

通过反射机制可以越过泛型检查,向集合中存储不同类型的数据.

泛型是用作编译器检查的,看看是不是有语法错误.

类名.class,可以获取类的字节码文件,即可以获取类对象.

反射是动态的,所以需要处理很多异常.


package com.crs.demo.ui.reflect;

import java.lang.reflect.Constructor;

/**
* Created on 2016/9/21.
* Author:crs
* Description:反射demo
* 通过Class对象,获取字节码文件中的成员变量,构造方法,普通方法的操作
* 1)通过全类名获取字节码文件对象
* 2)获取指定的构造函数
* 3)通过构造创建对象
*/
public class ReflectDemo {



private static Class mClass;
private static Constructor constructor;

public static void main(String[] args) {

//1)获取Class对象
try {
mClass = Class.forName("com.crs.demo.ui.reflect.PersonEntity");

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

//2)通过反射获取无参数构造函数并使用

//a:获取构造函数数组,但是不能够获取私有的构造方法
Constructor[] array = mClass.getConstructors();
for (Constructor con : array) {
//能够获取公有的构造方法
//System.out.print(con);
}

//b:能够获取所有的构造方法,包括私有的
Constructor[] arrayPrivate = mClass.getDeclaredConstructors();
for (Constructor con : arrayPrivate) {
//System.out.print(con);
}

//c:如何获取指定的某一个构造方法(获取空参数构造方法)
//public Constructor<T> getConstructors(Class < ? >...params)
//参数类型是你要获取的构造方法中的参数的class类型即可
try {
//这个构造方法获取不到,因为是私有的.
//Constructor constructors1 = mClass.getConstructor(String.class);
constructor = mClass.getConstructor(null);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//d:如何通过拿到的构造方法,创建对象 这个方法的返回结果为泛型
try {
Object o = constructor.newInstance();
System.out.print(o.toString());
} catch (Exception e) {
e.printStackTrace();
}

}
}

package com.crs.demo.ui.reflect;

import android.support.v4.view.ViewCompat;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/**
* Created on 2016/9/22.
* Author:crs
* Description:
* 1)通过反射获取构造方法并使用
* 2)通过反射获取成员变量并使用
* 3)通过反射获取成员方法并使用
* 3)如果是私有的,就“Declared”+“暴力破解”
*/
public class ReflectDemo1 {
public static void main(String[] args) {
//1需求:通过反射获取公共的有参数构造函数,并创建对象
try {
Class c = Class.forName("com.crs.demo.ui.reflect.PersonEntity");
Constructor con = c.getConstructor(String.class, int.class, String.class);
Object obj = con.newInstance("陈如水", 22, "上海市徐汇区");
System.out.print(obj.toString() + "\n");
} catch (Exception e) {
e.printStackTrace();
}

//2需求:获取私有的构造方法,并创建对象使用
try {
Class aClass = Class.forName("com.crs.demo.ui.reflect.PersonEntity");
Constructor cons = aClass.getDeclaredConstructor(String.class);
//私有的构造方法,可以通过暴力访问来破解java中的权限访问修饰符
cons.setAccessible(true);//调用此方法,开启暴力访问
Object object = cons.newInstance("守望江湖");
System.out.print(object.toString() + "\n");
} catch (Exception e) {
e.printStackTrace();
}

//3需求:通过反射获取公有的成员变量,并使用
try {
Class<?> aClass = Class.forName("com.crs.demo.ui.reflect.PersonEntity");
//获取成员变量字节数组
Field[] fields = aClass.getFields();
for (Field f : fields) {
System.out.print(f + "\n" + "\n");
//能够拿到公有的字段name
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

//4需求:通过反射获取所有的成员变量,并使用
try {
Class<?> aClass = Class.forName("com.crs.demo.ui.reflect.PersonEntity");
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
System.out.print(field + "\n" + "\n");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

//5需求:通过反射获取指定的成员变量,并进行赋值操作
try {
Class aClass = Class.forName("com.crs.demo.ui.reflect.PersonEntity");
Constructor constructor = aClass.getConstructor(null);
Object o = constructor.newInstance();
Field name = aClass.getField("name");
name.set(o, "chen");
System.out.print(o.toString() + "\n");
} catch (Exception e) {
e.printStackTrace();
}

//5需求:通过反射获取私有的成员变量,并进行赋值操作(Declared,暴力破解) set()方法 反射独有的
try {
Class aClass = Class.forName("com.crs.demo.ui.reflect.PersonEntity");
//获取对象
Constructor constructor = aClass.getConstructor(null);
Object object = constructor.newInstance();
//获取私有字段
Field age = aClass.getDeclaredField("age");
age.setAccessible(true);
//给字段设置值
age.set(object, 33);
System.out.print(object.toString() + "\n");
} catch (Exception e) {
e.printStackTrace();
}

//6需求:通过反射当前字段的值 get()方法 反射独有的
try {
Class aClass = Class.forName("com.crs.demo.ui.reflect.PersonEntity");
Constructor constructor = aClass.getConstructor(null);
Object object = constructor.newInstance();
Field address = aClass.getDeclaredField("address");
address.setAccessible(true);
address.set(object, "碧云天,黄叶地,秋色连波,波上寒烟翠!");
//获取值
Object addObject = address.get(object);
System.out.print(addObject.toString() + "\n");
} catch (Exception e) {
e.printStackTrace();
}


}
}


package com.crs.demo.ui.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
* Created on 2016/9/22.
* Author:crs
* Description:通过反射机制越过泛型检查
*/
public class ReflectDemo3 {
public static void main(String[] args) {
//泛型约束是编译期的语法检查
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
//如何通过泛型向list集合中添加"陈如水"呢?
try {
//在集合中可以存储Object类型的
Class aClass = Class.forName("java.util.ArrayList");
Method add = aClass.getMethod("add", Object.class);
add.invoke(list,"陈如水");
System.out.print(list);
//打印结果:[1, 2, 陈如水]
} catch (Exception e) {
e.printStackTrace();
}


}
}