反射
1、简介
1.1 概念
反射是指对于任何一个Class类,在运行的时候都可以直接得到这个类全部成分。
在运行时,可以直接得到这个类的构造器对象:Constructor。
在运行时,可以直接得到这个类的成员变量对象:Field。
在运行时,可以直接得到这个类的成员方法对象:Method。
这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。
1.2 反射的关键
反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。
HelloWorld.java -> javac -> HelloWorld.class
Class c = HelloWorld.class;
1.3 反射的作用
反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分。
反射的核心思想和关键就是:得到编译以后的class文件对象。
2、反射获取类对象
2.1 获取Class类的对象的三种方式
没有junit基础的建议先看一下,链接: https://blog.csdn.net/cndiafcbsfiuv/article/details/128587373?spm=1001.2014.3001.5501
新建一个Student类
package com.cp;
public class Student {
}
新建一个Test类
package com.cp;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//1、Class类中的静态方法:forName(全限定名 包名+类名)
Class c = Class.forName("com.cp.Student");
System.out.println(c);
//2、类名.class
Class c1 = Student.class;
System.out.println(c1);
//3、对象.getClass() 获取对象对应类的class对象
Student s = new Student();
Class c2 = s.getClass();
System.out.println(c2);
}
}
3、反射获取构造器对象
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
新建一个Student后续使用
package com.cp;
public class Student {
private String name;
private int age;
public static String schoolName;
public static final String COUNTRY = "中国";
public Student() {
System.out.println("无参构造器");
}
public Student(String name, int age) {
System.out.println("有参数构造器");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.1 Class类中用于获取构造器的方法
方法 | 说明 |
---|---|
Constructor<?>[] getConstructors() | 返回所有构造器对象的数组(只能拿public的) |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
Constructor getConstructor(Class<?>… parameterTypes) | 返回单个构造器对象(只能拿public的) |
Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 返回单个构造器对象,存在就能拿到 |
package com.cp;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class TestStudent01 {
@Test
public void getConstructors(){
//1、获取类对象
Class c = Student.class;
//2、提取类中的全部public构造器对象
Constructor[] constructors = c.getConstructors();
//3、遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + constructor.getParameterCount());
}
}
@Test
public void getDeclaredConstructors(){
//1、获取类对象
Class c = Student.class;
//2、提取类中的全部构造器对象
Constructor[] constructors = c.getDeclaredConstructors();
//3、遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + constructor.getParameterCount());
}
}
@Test
public void getConstructor() throws NoSuchMethodException {
//1、获取类对象
Class c = Student.class;
//2、提取类中的全部public构造器对象
Constructor constructor = c.getConstructor();
//3、打印构造器
System.out.println(constructor.getName() + constructor.getParameterCount());
}
@Test
public void getDeclaredConstructor() throws NoSuchMethodException {
//1、获取类对象
Class c = Student.class;
//2、提取类中的全部public构造器对象
Constructor constructor = c.getDeclaredConstructor();
//3、打印构造器
System.out.println(constructor.getName() + constructor.getParameterCount());
//2、提取类中的全部public构造器对象
Constructor constructor1 = c.getDeclaredConstructor(String.class,int.class);
//3、打印构造器
System.out.println(constructor1.getName() + constructor1.getParameterCount());
}
}
3.2 使用反射技术获取构造器对象并使用
方法 | 说明 |
---|---|
T newInstance(Object… initargs) | 根据指定的构造器创建对象 |
public void setAccessible(boolean flag) | 设置为true,表示取消访问检查,进行暴力反射 |
package com.cp;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class TestStudent02 {
@Test
public void getDeclaredConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1、获取类对象
Class c = Student.class;
//2、提取类中的全部public构造器对象
Constructor constructor = c.getDeclaredConstructor();
//3、打印构造器
System.out.println(constructor.getName() + constructor.getParameterCount());
//暴力反射
constructor.setAccessible(true);//权限被打开
//无参构造器为private类型,直接调用会报错,加上上面那一句
Student s = (Student) constructor.newInstance();
System.out.println(s);
//2、提取类中的全部public构造器对象
Constructor constructor1 = c.getDeclaredConstructor(String.class,int.class);
//3、打印构造器
System.out.println(constructor1.getName() + constructor1.getParameterCount());
constructor1.newInstance("孙悟空",1000);
System.out.println(constructor1);
}
}
3.3 使用反射技术获取构造器的作用
1、创建对象
2、如果是非public的构造器,需要打开权限(暴力反射setAccessible(boolean)),然后再创建对象
4、反射获取成员变量对象
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
4.1 Class类中用于获取成员变量的方法
方法 | 说明 |
---|---|
Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
4.2 使用反射技术获取成员变量对象并使用
方法 | 说明 |
---|---|
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 获取值 |
package com.cp;
import org.junit.Test;
import java.lang.reflect.Field;
public class FieldDemo01 {
@Test
public void getDeclaredFields(){
//1、定位Class对象
Class c = Student.class;
//2、定位全部成员变量
Field[] fields = c.getDeclaredFields();
//3、遍历成员变量
for (Field field : fields) {
System.out.println(field.getName()+" "+field.getType());
}
}
@Test
public void getDeclaredField() throws NoSuchFieldException, IllegalAccessException {
//1、定位Class对象
Class c = Student.class;
//2、定位某个成员变量
Field field = c.getDeclaredField("name");
//3、打印成员变量
System.out.println(field.getName()+" "+field.getType());
//4、赋值
Student s = new Student();
//暴力打开权限
field.setAccessible(true);
field.set(s,"测试");
System.out.println(s);
//5、取值
String name = (String) field.get(s);
System.out.println(name);
}
}
4.3 使用反射技术获取成员变量对象的作用
1、在某个对象中取值和赋值。
2、如果某成员变量是非public的,需要打开权限(暴力反射setAccessible(boolean)),然后再取值、赋值
5、反射获取方法对象
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
4.1Class类中用于获取成员方法的方法
方法 | 说明 |
---|---|
Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class<?>… parameterTypes) | 返回单个成员方法对象(只能拿public的) |
Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
4.2 使用反射技术获取方法对象并使用
获取成员方法的作用依然是在某个对象中进行执行此方法
方法 | 说明 |
---|---|
Object invoke(Object obj, Object… args) | 参数一:用obj对象调用该方法,参数二:调用方法的传递的参数(如果没有就不写)返回值:方法的返回值(如果没有就不写) |
package com.cp;
public class Dog {
private Student name;
public Dog() {
}
public Dog(Student name) {
this.name = name;
}
private void run(){
System.out.println("狗跑");
}
private String eat(String name){
System.out.println("狗吃"+name);
return "吃的很开心";
}
public static void inAddr(){
System.out.println("静态方法地址");
}
private void eat(){
System.out.println("狗吃");
}
public Student getName() {
return name;
}
public void setName(Student name) {
this.name = name;
}
}
package com.cp;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodDemo01 {
@Test
public void getDeclaredMethods(){
//1、获取类对象
Class c = Dog.class;
//2、提取全部方法,包括私有的
Method[] methods = c.getDeclaredMethods();
//3、遍历全部方法
for (Method method : methods) {
System.out.println("方法名 "+method.getName()+" 返回值类型 "+method.getReturnType() +" 参数个数 "+method.getParameterCount());
}
}
@Test
public void getDeclaredMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//1、获取类对象
Class c = Dog.class;
//2、提取某个方法,包括私有的
Method method = c.getDeclaredMethod("eat");
Method method1 = c.getDeclaredMethod("eat",String.class);
//3、打印方法信息
System.out.println("方法名 "+method.getName()+" 返回值类型 "+method.getReturnType() +" 参数个数 "+method.getParameterCount());
System.out.println("方法名 "+method1.getName()+" 返回值类型 "+method1.getReturnType() +" 参数个数 "+method1.getParameterCount());
//4、触发方法执行
Dog d = new Dog();
//暴力反射,打开权限
method.setAccessible(true);
//如果方法没有返回结果,返回为null
Object result = method.invoke(d);
System.out.println(result);
method1.setAccessible(true);
Object result1 = method1.invoke(d,"骨头");
System.out.println(result1);
}
}
4.3 使用反射技术获取方法对象的作用
1、在某个对象中触发该方法执行。
2、如果某成员方法是非public的,需要打开权限(暴力反射setAccessible(boolean)),然后再触发执行
反射可以破坏封装性,私有的也可以执行了。