目录
1、反射概述
1.1、概述
反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分。
在运行时,可以直接得到这个类的构造器对象:Constructor
在运行时,可以直接得到这个类的成员变量对象:Field
在运行时,可以直接得到这个类的成员方法对象:Method
这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。
1.2、反射的关键
反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分。
2、反射获取类对象
获取Class类的对象的三种方式
方式一:Class c1 = Class.forName(“全类名”);
方式二:Class c2 = 类名.class
方式三:Class c3 = 对象.getClass();
package com.itwpf.d2_reflect_class;
public class Student {
private String name;
private int age;
public Student() {
System.out.println("无参构造");
}
public Student(String name, int age) {
System.out.println("有参构造");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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;
}
public void run(){
System.out.println("跑得快");
}
public void eat(){
System.out.println("吃得多");
}
public String eat(String name){
System.out.println("吃"+name);
return "吃得很开心";
}
}
package com.itwpf.d2_reflect_class;
public class Test {
public static void main(String[] args) throws Exception {
//1.Class类中的一个静态方法:foeName(全限名:包名+类名)
Class c = Class.forName("com.itwpf.d2_reflect_class.Student");
System.out.println(c);
//2.类名.class
Class<Student> c2 = Student.class;
System.out.println(c2);
//3.对象.getClass()获取对象对应类的Class对象
Student s = new Student();
Class<? extends Student> c3 = s.getClass();
System.out.println(c3);
}
}
3、反射获取构造器对象
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取构造器的方法
方法 | 说明 |
Constructor<?>[] getConstructors() | 返回所有构造器对象的数组 (只能拿public的) |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造器对象的数组, 存在就能拿到 |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回单个构造器对象 (只能拿public的) |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回单个构造器对象, 存在就能拿到 |
package com.itwpf.d2_reflect_class;
import org.junit.Test;
import java.lang.reflect.Constructor;
public class Test02 {
@Test
public void getConstruct(){
//1.获取类对象
Class<Student> 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<Student> 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<Student> c = Student.class;
//2.定位单个构造器对象
Constructor<Student> cons = c.getConstructor();
//3.遍历构造器
System.out.println(cons.getName()+"==>"+cons.getParameterCount());
}
@Test
public void getDeclaredConstructor() throws NoSuchMethodException {
//1.获取类对象
Class<Student> c = Student.class;
//2.定位单个构造器对象
Constructor<Student> cons = c.getDeclaredConstructor();
//3.遍历构造器
System.out.println(cons.getName()+"==>"+cons.getParameterCount());
//定位某个有参构造器
Constructor cons1 = c.getDeclaredConstructor(String.class,int.class);
System.out.println(cons1.getName()+"==>"+cons1.getParameterCount());
}
}
Constructor类中用于创建对象的方法
符号 | 说明 |
T newInstance(Object... initargs) | 根据指定的构造器创建对象 |
public void setAccessible(boolean flag) | 设置为true,表示取消访问检查, 进行暴力反射 |
package com.itwpf.d2_reflect_class;
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test03 {
@Test
public void getDeclaredConstructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//1.获取类对象
Class<Student> c = Student.class;
//2.定位单个构造器对象
Constructor<Student> cons = c.getDeclaredConstructor();
//3.遍历构造器
System.out.println(cons.getName()+"==>"+cons.getParameterCount());
//如果遇到了私域的构造器,可以暴力反射
cons.setAccessible(true);//权限被打开
Student s = cons.newInstance();
System.out.println(s);
//定位某个有参构造器
Constructor cons1 = c.getDeclaredConstructor(String.class,int.class);
System.out.println(cons1.getName()+"==>"+cons1.getParameterCount());
Student ss = (Student)cons1.newInstance("孙", 1000);
System.out.println(ss);
}
}
4、反射获取成员变量对象
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取成员变量的方法
方法 | 说明 |
Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
获取成员变量的作用依然是在某个对象中取值、赋值
Field类中用于取值、赋值的方法
符号 | 说明 |
void set(Object obj, Object value): | 赋值 |
Object get(Object obj) | 获取值。 |
package com.itwpf.d2_reflect_class;
import org.junit.Test;
import java.lang.reflect.Field;
public class Test04 {
@Test
public void TestgetFields(){
Class<Student> c = Student.class;
Field[] declaredFields = c.getDeclaredFields();
for(Field f:declaredFields){
System.out.println(f.getName()+"==>"+f.getType());
}
}
@Test
public void TestgetField() throws NoSuchFieldException, IllegalAccessException {
Class<Student> c = Student.class;
Field d = c.getDeclaredField("name");
System.out.println(d.getName()+"==>"+d.getType());
Student s = new Student();
d.setAccessible(true);
d.set(s,"100");
String k = (String)d.get(s);
System.out.println(k);
}
}
5、反射获取方法对象
反射的第一步是先得到类对象,然后从类对象中获取类的成分对象。
Class类中用于获取成员方法的方法
方法 | 说明 |
Method[] getMethods() | 返回所有成员方法对象的数组 (只能拿public的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组, 存在就能拿到 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象 (只能拿public的) |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象, 存在就能拿到 |
Method类中用于触发执行的方法
符号 | 说明 |
Object invoke(Object obj, Object... args) | 运行方法 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数 (如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
package com.itwpf.d2_reflect_class;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test05 {
@Test
public void getDeclaredMethods(){
//1.获取类对象
Class<Student> c = Student.class;
//2.提取全部方法,包括私有
Method[] methods = c.getDeclaredMethods();
//3.遍历全部方法
for(Method m:methods){
System.out.println(m.getName()+",返回值类型"+m.getReturnType()+",参数个数"+m.getParameterCount());
}
}
@Test
public void getDeclaredMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//1.获取类对象
Class<Student> c = Student.class;
//2.提取全部方法,包括私有
Method m = c.getDeclaredMethod("eat");
Method m2 = c.getDeclaredMethod("eat",String.class);
//3.遍历方法
System.out.println(m.getName()+",返回值类型"+m.getReturnType()+",参数个数"+m.getParameterCount());
System.out.println(m2.getName()+",返回值类型"+m2.getReturnType()+",参数个数"+m2.getParameterCount());
//暴力反射
m2.setAccessible(true);
//触及方法的执行
Student s = new Student();
//注意:方法如果是没有结果回来,那么返回的是null
Object invoke = m2.invoke(s,"hello");
System.out.println(invoke);
}
}
6、反射的作用
反射的作用-绕过编译阶段为集合添加数据
反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的。
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。
package com.itwpf.d2_reflect_class;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class ReflectDemo {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass());
System.out.println(list2.getClass());
System.out.println(list1.getClass() == list2.getClass());
list2.add(23);
list2.add(24);
Class<? extends ArrayList> c = list2.getClass();
Method method = c.getDeclaredMethod("add",Object.class);
method.invoke(list2,"hello");
System.out.println(list2);
ArrayList list3 = list2;
list3.add("nihao");
System.out.println(list2);
}
}
运行结果:
class java.util.ArrayList
class java.util.ArrayList
true
[23, 24, hello]
[23, 24, hello, nihao]
反射是作用在运行时的技术,此时已经不存在泛型了。
可以在运行时得到一个类的全部成分然后操作。
可以破坏封装性。(很突出)
也可以破坏泛型的约束性。(很突出)
更重要的用途是适合:做Java高级框架
基本上主流框架都会基于反射设计一些通用技术功能。