java 反射详解

时间:2022-09-21 02:16:33

反射的概念和原理

类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。

字节码的信息包括:类名声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类

通过Class类、Method类、Field类等等类 可以得到  这个类字节码的全部信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法设置或获取字段的值这就是反射技术

注意:在反射技术中一个类的任何成员都有对应 的类进行描述。  比如:  成员变量(Field)   方法----> Method类

Class类

Class类解释说明:

Java中有一个Class类用于代表某一个类的字节码。通过获取这个class类的对象,就可以得到字节码的一些信息

得到class对象的三种方法

Java提供了三种方式获取类的字节码

forName():forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装(推荐使用这个,一般配合配置文件读取类的全名 创建对象)

类名.class

对象.getClass()

例子:

Person类,用于被测试的类

package cn.itcast.reflect;

public class Person {

private int id;

String name;

public Person(int id,String name){

this.id = id;

this.name = name;

}

public Person(){}

private Person(int id){

this.id = id;

}

public void eat(int num){

System.out.println(name+"吃很"+num+"斤饭");

}

private static void sleep(int num){

System.out.println("明天睡上"+num+"小时");

}

public static void  sum(int[] arr){

System.out.println("长度是:"+ arr.length);

}

@Override

public String toString() {

return " 编号:"+ this.id +" 姓名:"+ this.name;

}

}

获取class对象的代码:

public static void main(String[] args) throws ClassNotFoundException {

//推荐使用: 获取Class对象的方式一

Class clazz1 = Class.forName("cn.itcast.reflect.Person");

System.out.println("clazz1:"+ clazz1);

//获取Class对象的方式二: 通过类名获取

Class clazz2 = Person.class;

System.out.println("clazz1==clazz2?"+ (clazz1==clazz2));

//获取Class对象的方式三 :通过对象获取

Class clazz3 = new Person(110,"狗娃").getClass();

System.out.println("clazz2==clazz3?"+ (clazz2==clazz3));

}

打印结果:

clazz1:class cn.itcast.reflect.Person

clazz1==clazz2?true

clazz2==clazz3?true

通过class对象获取一些信息

获取类的全名(包名+类名),类的简单名称(不带包名,只有类名),类的修饰符

API解释说明:

1. getName()类的名称(全名,全限定名)

2 getSimpleName()类的的简单名称(不带包名)

3. getModifiers(); 类的的修饰符

例子:

import java.lang.reflect.Constructor;

import java.lang.reflect.Modifier;

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

System.out.println("-----------获取类的全名------------");

//通过Class对象获取类的全名(包含 包名)

String fullName = clazz.getName();

System.out.println(fullName);

//通过class对象获取类名(不包含包名)

String simpleName =  clazz.getSimpleName();

System.out.println(simpleName);

//通过class对象获取类的修饰符

int modifyName = clazz.getModifiers();

String retval = Modifier.toString(modifyName);

System.out.println("Class Modifier = " + retval);

打印结果:

-----------获取类的全名------------

cn.itcast.reflect.Person

Person

Class Modifier = public

获取类的全部构造函数,私有的,公有的

API:

getConstructors()获取一个类的所有公共的构造方法

getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

代码:

//通过Class对象获取对应的构造方法

Constructor[] constructors = clazz.getConstructors();  // getConstructors()获取一个类的所有公共的构造方法

for(Constructor constructor : constructors){

System.out.println(constructor);

}

System.out.println("\n-------------获取所有的构造方法,包括私有的-------------");

Constructor[] constructors2 =  clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

for(Constructor constructor2 : constructors2){

System.out.println(constructor2);

}

打印的结果:

----------获取所有的公共构造方法--------------

public cn.itcast.reflect.Person()

public cn.itcast.reflect.Person(int,java.lang.String)

-------------获取所有的构造方法,包括私有的-------------

private cn.itcast.reflect.Person(int)

public cn.itcast.reflect.Person()

public cn.itcast.reflect.Person(int,java.lang.String)

获取指定的构造对象,然后new出一个对象(这个是不能new出private修饰的构造函数)

API:

newInstance方法构造对象,默认使用的是无参数的构造方法

举例:Object ins = clazz.newInstance();

getConstructor(参数类型的.class)获取单个指定的构造方法。

举例:clazz.getConstructor(int.class,String.class);

局限地方:不能获取private的构造函数

例子:

System.out.println("\n获取指定的构造方法,然后new出一个对象");

//newInstance方法构造对象,默认使用的是无参数的构造方法

Object ins = clazz.newInstance();

Person p = (Person) ins;

System.out.println(p);

//getConstructor 获取单个指定的构造方法。

clazz.getConstructor(int.class,String.class);

Constructor constructor = clazz.getConstructor(int.class,String.class);  //

Person p2  = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象

System.out.println(p2);

打印结果:

获取指定的构造方法,然后new出一个对象

编号:0 姓名:null

编号:999 姓名:小城

获取指定的私有构造函数

API:

getDeclaredConstructor 方法:获取指定的私有构造函数

例子:

System.out.println("\n获取指定的私有构造函数");

Constructor constructor1 =  clazz.getDeclaredConstructor(int.class);

System.out.println(constructor1);

打印结果:

获取指定的私有构造函数

private cn.itcast.reflect.Person(int)

暴力反射:

System.out.println("暴力反射");

Constructor constructor2 =  clazz.getDeclaredConstructor(int.class);

System.out.println(constructor2);

constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象

Person p3  =(Person) constructor2.newInstance(100);

System.out.println(p3);

打印结果:

暴力反射

private cn.itcast.reflect.Person(int)

编号:100 姓名:null

获取构造函数的完整代码:

package cn.itcast.reflect;

import java.lang.reflect.Constructor;

import java.lang.reflect.Modifier;

/*

如何通过Class对象获取构造方法。

*/

public class Demo2 {

public static void main(String[] args) throws Exception {

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

// System.out.println("-----------获取类的全名------------");

// //通过Class对象获取类的全名(包含 包名)

// String fullName = clazz.getName();

// System.out.println(fullName);

//

//

// //通过class对象获取类名(不包含包名)

// String simpleName =  clazz.getSimpleName();

// System.out.println(simpleName);

//

// //通过class对象获取类的修饰符

// int modifyName = clazz.getModifiers();

// String retval = Modifier.toString(modifyName);

//     System.out.println("Class Modifier = " + retval);

//     System.out.println("----------获取所有的公共构造方法--------------");

//

// //通过Class对象获取对应的构造方法

// Constructor[] constructors = clazz.getConstructors();  // getConstructors()获取一个类的所有公共的构造方法

// for(Constructor constructor : constructors){

// System.out.println(constructor);

// }

//

// System.out.println("\n-------------获取所有的构造方法,包括私有的-------------");

// Constructor[] constructors2 =  clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

// for(Constructor constructor2 : constructors2){

// System.out.println(constructor2);

// }

// System.out.println("\n获取指定的构造方法,然后new出一个对象");

//

// //newInstance方法构造对象,默认使用的是无参数的构造方法

// Object ins = clazz.newInstance();

// Person p = (Person) ins;

// System.out.println(p);

//

// //getConstructor 获取单个指定的构造方法。

// clazz.getConstructor(int.class,String.class);

// Constructor constructor = clazz.getConstructor(int.class,String.class);  //

// Person p2  = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象

// System.out.println(p2);

// System.out.println("\n获取指定的私有构造函数");

// Constructor constructor1 =  clazz.getDeclaredConstructor(int.class);

// System.out.println(constructor1);

// //

System.out.println("暴力反射");

Constructor constructor2 =  clazz.getDeclaredConstructor(int.class);

System.out.println(constructor2);

constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象

Person p3  =(Person) constructor2.newInstance(100);

System.out.println(p3);

}

}

通过class类获取 字节码中的方法信息

获取全部的方法部分

Api详解:

getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。

例子:

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

//获取到所有公共的方法

Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

//Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。

for(Method method  : methods){

System.out.println(method);

}

获取指定的方法,并执行它

API:

getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法

getDeclaredMethod("sleep",int.class);////执行私有的方法

setAccessible(true);//设置访问权限允许访问

invoke(p, 6);//invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。

用法:

Person p = new Person(110,"狗娃");

//获取指定的方法,但是不能获取私有的方法

Method m = clazz.getMethod("eat", int.class);

//invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。

m.invoke(p, 3);

//执行私有的方法

Method m2 =clazz.getDeclaredMethod("sleep",int.class);

//设置访问权限允许访问

m2.setAccessible(true);

//静态的方法第一个参数写null,表示没有对象调用,类本身会调用

m2.invoke(p, 6);

暴力反射:

//暴力反射,获取私有的方法,并执行它

Method m = clazz.getDeclaredMethod("sleep", int.class);

System.out.println(m);

m.setAccessible(true);

m.invoke(p, 8);

获取方法部分完整代码:

package cn.itcast.reflect;

import java.lang.reflect.Method;

/*

通过Class对象获取到对应的方法。

在反射技术中使用了Method类描述了方法的。

*/

public class Demo3 {

public static void main(String[] args) throws Exception {

//获取到对应的Class对象

Class<?> clazz = Class.forName("cn.itcast.reflect.Person");

// //获取到所有公共的方法

// Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

//// Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。

// for(Method method  : methods){

// System.out.println(method);

// }

Person p = new Person(110,"狗娃");

//

// //获取指定的方法,但是不能获取私有的方法

// Method m = clazz.getMethod("eat", int.class);

// //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。

// m.invoke(p, 3);

//

//

// //执行私有的方法

// Method m2 =clazz.getDeclaredMethod("sleep",int.class);

// //设置访问权限允许访问

// m2.setAccessible(true);

// //静态的方法第一个参数写null,表示没有对象调用,类本身会调用

// m2.invoke(p, 6);

// Method m = clazz.getMethod("sum", int[].class);

// m.invoke(p,new int[]{12,5,9});

//暴力反射,获取私有的方法,并执行它

Method m = clazz.getDeclaredMethod("sleep", int.class);

System.out.println(m);

m.setAccessible(true);

m.invoke(p, 8);

}

}

通过class对象获取到字段信息

代码;

public static void main(String[] args) throws Exception {

//获取到对应的Class对象

Class clazz = Class.forName("cn.itcast.reflect.Person");

//获取 到所有的成员变量(包含私有的)

// Field[] fields = clazz.getDeclaredFields();

// for(Field field  : fields){

// System.out.println(field);

// }

Person p = new Person();

Field field = clazz.getDeclaredField("id");

//设置访问权限可以访问

field.setAccessible(true);

field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。

System.out.println(p);

}

反射API总结:

Class类

1. getName()类的名称(全名,全限定名)

2 getSimpleName()类的的简单名称(不带包名)

  1. getModifiers(); 类的的修饰符

4.getConstructors()获取一个类的所有公共的构造方法

5.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。

6.newInstance方法构造对象,默认使用的是无参数的构造方法

举例:Object ins = clazz.newInstance();

7.getConstructor(参数类型的.class)获取单个指定的构造方法。

举例:clazz.getConstructor(int.class,String.class);

局限地方:不能获取private的构造函数

8.getDeclaredConstructor 方法:获取指定的私有构造函数

方法部分

getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。

getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。

getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法

clazz.getDeclaredMethod("sleep",int.class);//执行私有的方法

m2.invoke(p, 6); //表示m2这个方法被p这个对象执行了,后面的参数是m2这个方法需要的参数

字段部分

1.获取公共字段

Field[] getFields()

2.获取指定参数的公共字段

Field getField(String name)

3.获取所有的字段

Field[] getDeclaredFields()

4.获取指定参数的字段,包括私用

Field getDeclaredField(String name)

一般用getDeclaredConstructor方法进行获取构造函数,一般不获取private修饰的构造函数