反射
反射机制:
当一个类被加载进内存后,都会相应的有一个字节码文件(里面有类的信息)对象,我们去剖析这个类的的构成,还能调用该类中的功能,想要通过反射去调用类中的功能和属性,那必须先要得到,该类对应的字节码文件对象(Class)
获取换一个类的字节码文件对象的三种方式:
方式1:
通过Object类中的 getClass();
Student student = new Student();
Class aClass = student.getClass();
方式2:
每个类都有一个class 静态属性
Class studentClass = Student.class;
方式3:
通过 Class 类中的一个静态方法来获取
static Class<?> forName (String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象。通过一个类的全路径,就可以获取到该类的字节码文件对象
类的全路径: 该类带有包名的写法 例如: org.westos.demo2.Student 一个类全路径的写法
Class<?> aClass3 = Class.forName("org.westos.demo2.Student");
System.out.println(aClass3== studentClass);
随便建一个学生类
public class Student {
}
测试类
public class MyDemo {
public static void main(String[] args) throws Exception {
//方式1:通过Object类中的 getClass()
Student student = new Student();
Class aClass = student.getClass();
Class aClass1 = student.getClass();
System.out.println(aClass);
System.out.println(aClass==aClass1);
Student student2 = new Student();
Class aClass2 = student2.getClass();
System.out.println(aClass1==aClass2);
//方式2,每个类都有一个class 静态属性
Class studentClass = Student.class;
System.out.println(studentClass==aClass);
//方式3:通过 Class 类中的一个静态方法来获取
Class<?> aClass3 = Class.forName("org.westos.demo2.Student");
System.out.println(aClass3== studentClass);
}
}
类的构成:
成员方法,Method
构造方法 Constructor
成员变量 Field
使用反射剖析一个类
我们要使用反射去剖析一个类,必须先获取到该类所对应的字节码文件对象;
1.获取该类的字节码文件对象
Class clazz = Class.forName("org.westos.demo3.Student");
2.研究构造方法 那我们就得得到构造方法的对象
//A:
//获取所有构造方法
//public Constructor<?>[] getConstructors () 获取所有的构造方法不包含私有的
//public Constructor<?>[] getDeclaredConstructors () 获取所有的构造方法 包括私有的
//B:
//获取单个构造方法
//public Constructor<T> getConstructor (Class < ? >...parameterTypes)获取单个的构造方法 不包含私有的
//public Constructor<T> getDeclaredConstructor (Class < ? >...parameterTypes)获取单个的构造方法包含私有的
随便建一个学生类
public class Student {
//提供构造方法
public Student() {
System.out.println("空参构造执行了");
}
public Student(String name) {
System.out.println("一个参数的构造执行了"+name);
}
private Student(String name, int age) {
System.out.println("私有的构造方法执行了"+name+"=="+age);
}
}
测试类
public class MyTest {
public static void main(String[] args) throws Exception {
Constructor[] constructors = clazz.getConstructors(); //获取该类中所有的构造方法对象,但是私有的构造方法获取不到
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
System.out.println("--------------------");
//获取该类中所有的构造方法对象,包括私有
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
System.out.println("--------------------------------------");
//获取单个的构造方法对象
Constructor constructor = clazz.getConstructor(); //获取共有的
System.out.println(constructor);
System.out.println("-------------------------");
//获取单个有参的构造方法对象
//参数:就是你构造方法中参数类型的Class类型
Constructor constructor1 = clazz.getConstructor(String.class);
System.out.println(constructor1);
System.out.println("-----------------------------");
//获取私有的构造方法对象
//Constructor constructor2 = clazz.getConstructor(String.class, int.class);
//System.out.println(constructor2);
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
System.out.println(declaredConstructor);
}
}
用反射创建一个类的对象:
获取空参构造方法对象:
使用newInstance(Object…initargs):
方式一:
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
方式二:
Object obj2 = clazz.newInstance();
public static void main(String[] args) throws Exception{
//通过空参构造创建一个类的对象
Class clazz= Class.forName("org.westos.demo3.Student");
//获取空参构造方法对象
Constructor constructor = clazz.getConstructor();
Object obj = constructor.newInstance();
System.out.println(obj);
System.out.println("--------------------------------");
//通过空参构造创建一个类的对象 方式2
Object obj2 = clazz.newInstance();
System.out.println(obj2);
}
通过反射获取带参构造方法并使用:
使用newInstance(Object…initargs):
//我们能够获取到了,一个类的构造方法对象,能够什么,就能够创建该类对象
Class clazz = Class.forName("org.westos.demo3.Student");
//我们想要通过空参构造创建一个类的对象
//获取空参构造对象
Constructor constructor = clazz.getConstructor();
//创建该类对象
//newInstance(Object...initargs)
//使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
Object obj = constructor.newInstance();
System.out.println(obj);
System.out.println("-------------------------------");
过反射获取私有构造方法并使用:
我们以前创建对象的方式是
Student student = new Student();
使用反射来创建:
要点是用:con.setAccessible(true) ; 取消语法检查不然会报错 因为私有的外界不能直接访问;来暴力破解私有
Constructor constructor1 = clazz.getConstructor(String.class);
Object obj2 = constructor1.newInstance("张三");
System.out.println(obj2);
System.out.println("-----------------------------------------------------");
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class, int.class);
declaredConstructor.setAccessible(true); //暴利破解 取消语法检测
Object obj3 = declaredConstructor.newInstance("李四", 24);
System.out.println(obj3);
通过反射获取成员变量并使用:
A:获取所有成员变量
public Field[] getFields():
获取所有的成员变量包含从父类继承过来的
public Field[] getDeclaredFields() :
获取所有的成员变量 包含私有的 也包含从父类继承过来的成员变量
B:获取单个成员变量
public Field getField(String name)
public Field getDeclaredField(String name)
public static void main(String[] args) throws Exception{
//只要使用反射,就先获取该类的字节码文件对象
Class clazz = Class.forName("org.westos.demo4.Student");
//获取字段对象
Field[] fields = clazz.getFields(); //获取所有公共的字段对象
for (Field field : fields) {
System.out.println(field);
}
System.out.println("-------------------------");
//获取所有的字段对象,包括私有的
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("--------------------------------");
//获取单个的字段对象
Field age = clazz.getField("age");
System.out.println(age);
//获取私有的当个字段对象
Field sex = clazz.getDeclaredField("sex");
System.out.println(sex);
}
通过反射给字段设置值:
void set (Object obj, Object value):
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
-
obj: 表示的就是对象
-
value: 表示的意思就是要具体赋的值
(俗话:参1,你要给哪个对象设,参数2 就是你给字段设置的具体的值)public static void main(String[] args) throws Exception{ Class clazz = Class.forName("org.westos.demo4.Student"); //获取成员变量age; Field age = clazz.getDeclaredField("age"); //创建对象 Object obj = clazz.newInstance(); //给字段设置值 age.set(obj,100); Student student= (Student) obj; System.out.println(student.age); //通过字段对象获取字段的值 Object o = age.get(obj); System.out.println(o); //给一个类中的私有字段设置值 Field sex = clazz.getDeclaredField("sex"); sex.setAccessible(true);//取消语法检测 sex.set(obj,'男'); Object o1 = sex.get(obj); System.out.println(o1); }
通过反射获取无参无返回值成员方法并使用:
A:获取所有成员方法:
public Method[] getMethods() //获取所有的公共的成员方法不包含私有的 包含从父类继承过来的过来的公共方法
public Method[] getDeclaredMethods()//获取自己的所有成员方法 包含私有的
B:获取单个成员方法:
//参数1: 方法名称 参数2:方法行参的class 对象
public Method getMethod(String name,Class<?>… parameterTypes) //获取单个的方法 不包含私有的
public Method getDeclaredMethod(String name,Class<?>… parameterTypes) 获取单个方法包括私有的
public static void main(String[] args) throws Exception{
//先要获取该类的字节码文件对象
Class clazz = Class.forName("org.westos.demo5.Student");
//获取给类中的方法对象
//获取所有的公共方法对象
Method[] methods = clazz.getMethods(); //获取所有的公共的方法对象,包括父类的
for (Method method : methods) {
System.out.println(method.getName());
}
System.out.println("-----------------------------------------");
//获取该类中所有的方法对象,包括私有的,不包含父类方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("-------------------------------------------");
//获取单个的公共方法
//参1 就是你要获取的方法名,参数2,方法中参数类型的,class类型
Method show = clazz.getMethod("show");
System.out.println(show);
//获取有参的方法对象
Method test = clazz.getMethod("test", String.class);
System.out.println(test);
//获取私有的方法对象
Method myMethod = clazz.getDeclaredMethod("myMethod", String.class, int.class);
System.out.println(myMethod);
}
public static void main(String[] args) throws Exception {
//获取字节码文件对象
Class clazz = Class.forName("org.westos.demo5.Student");
//以前
//new Student().show();
Method show = clazz.getMethod("show");
//Object invoke (Object obj, Object...args)
//对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
Object obj = clazz.newInstance();
show.invoke(obj);
System.out.println("--------------------");
Method show2 = clazz.getMethod("show2");
Object value = show2.invoke(obj);
System.out.println(value);
System.out.println("------------------------------------");
//调用有参的方法
Method test = clazz.getMethod("test", String.class);
test.invoke(obj, "zhangsan");
//调用私有的方法
Method myMethod = clazz.getDeclaredMethod("myMethod", String.class, int.class);
myMethod.setAccessible(true);//取消语法检测
myMethod.invoke(obj, "wnagwu", 25);
}
学生类
public class Student {
public void show(){
System.out.println("我是一个无参数的公共方法");
}
public String show2() {
System.out.println("我是一个无参数的公共方法,有返回值");
return "一个字符串";
}
public void test(String name) {
System.out.println("我是一个有参数的公共方法"+name);
}
private void myMethod(String name,int age) {
System.out.println("我是一个有参数的私有方法" +name+"=="+age);
}
}
案例演示: 我给你ArrayList 的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
// list.add("100");
//泛型:只在编译期有效,运行期就擦除了
//反射就是运行期间
Class aClass = list.getClass();
//获取add()方法的方法对象
Method add = aClass.getDeclaredMethod("add", Object.class);
//让add()方法执行
add.invoke(list, "abc");
System.out.println(list);
}