前言
项目主体源码可以从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);
}
}
}