1.反射是什么
程序中的反射指程序运行状态中,
1、对于给定的一个类(Class)对象,可以获得这个类(Class)对象的所有属性和方法;
2、对于给定的一个对象(new XXXClassName<? extends Object>),都能够调用它的任意一
个属性和方法。
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制,就叫做Java反射机制
2.反射有什么用
直接new User()不就可以了,为什么要用这种反射写法?
实例化一个User()对象,不使用反射,如果想再实例化其他对象比如new Person(),那么
就需要修改源代码,并重新编译。使用反射后就不需要修改源代码只需要灵活改动类描述就
可以了,不需要重新再编译。 如下代码所示
//类描述,可根据需要实例化的描述而改动
String className = "com.tledu.pojo.User";
//使用反射中API创建对象
Class.forName(className).newInstance();
反射的优缺点:
优点:
增加程序的灵活性,避免固有逻辑写死到程序中
代码相对简洁,可以提高程序的复用性
缺点:
相比于直接调用反射有比较大的性能销毁
内部暴露和安全隐患
3.反射怎么用
3.1 获取类对象的三种方式
//获取类对象的三种方式
Class<User> clazz1 = User.class;
Class<?> clazz2 = Class.forName("com.tledu.mjw.User");
Class<? extends User> clazz3 = new User().getClass();
3.2 类中属性的获取
一些方法
System.out.println("包名:"+clazz.getPackage());
System.out.println(clazz.getName()); //com.tledu.pojo.User 全类名
System.out.println("类名:"+clazz.getSimpleName());
//getFields():可以获取本类及父类中的所有公共的属性
Field[] fields = clazz.getFields();
for (Field field : fields) {
// System.out.println(field.getName());
}
//getDeclaredFields():获取本类中的所有的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
// System.out.println(Modifier.toString(declaredField.getModifiers()) +" "+declaredField.getType().getSimpleName()+" "+declaredField.getName());
}
//获取指定的公共的属性对象
Field field = clazz.getField("age");
//System.out.println(Modifier.toString(field.getModifiers()) +" "+field.getType().getSimpleName()+" "+field.getName());
//获取父类
Class<? super User> superclass = clazz.getSuperclass();
//System.out.println(superclass.getSimpleName());
//获取类加载器
//System.out.println(clazz.getClassLoader());
3.3 类中方法的获取
//getMethods() 获取本类及父类中的公共的方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// System.out.println(method.getName());
}
//获取本类中的所有的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
// System.out.println(Modifier.toString(declaredMethod.getModifiers())+" "+declaredMethod.getReturnType().getSimpleName()+" "+declaredMethod.getName()+" "+ Arrays.toString(declaredMethod.getParameterTypes()));
}
//获取某个方法通过反射的方式调用执行
Method method = clazz.getMethod("eat", String.class, Integer.class);
//invoke用来调用方法的,第一个参数表示要执行的方法所属对象,后面的可变参数表示该执行方法的传入值
method.invoke(user,"西瓜",3);
//私有方法的调用
Method method2 = clazz.getDeclaredMethod("run");
//开启对私有方法的访问权限
method2.setAccessible(true);
method2.invoke(user);
3.4 类中构造方法的获取
Class clazz = User.class;
//获取构造器对象
Constructor constructor = clazz.getConstructor();
//System.out.println(constructor.getName());
//Constructor[] constructors = clazz.getConstructors(); 获取本类中的公共构造
Constructor[] constructors = clazz.getDeclaredConstructors(); //获取本类中所有的构造
for (Constructor constructor1 : constructors) {
// System.out.println(Arrays.toString(constructor1.getParameterTypes()));
}
//创建一个User对象 通过构造
Constructor constructor1 = clazz.getDeclaredConstructor(String.class, String.class);
constructor1.setAccessible(true);
User o = (User)constructor1.newInstance("tom", "boy");
System.out.println(o);
3.5 利用反射创建对象
Class<User> clazz = User.class;
Class<? extends User> aClass = new User().getClass();
Class clazz2 = Class.forName("com.tledu.pojo.User");
//需求:
// 创建出对象
// new User();
// new Person();
// new Grade();
// new Student();
// new ......
String clazzName = "Person";
String str = "com.tledu.pojo."+clazzName;
Class.forName(str).newInstance();
3.6 反射破局单例
利用反射创建出来的对象,不会遵从单例模式下只返回同一个对象的情况
正常的创建对象情况下,单例模式返回的为同一个对象
// Apple apple = Apple.getInstance();
// Apple apple2 = Apple.getInstance();
//
// System.out.println(apple);
// System.out.println(apple2);
//反射破局单例
Class clazz = Apple.class;
Constructor declaredConstructor = clazz.getDeclaredConstructor();
//给该方法权限
declaredConstructor.setAccessible(true);
System.out.println(declaredConstructor.newInstance());
System.out.println(declaredConstructor.newInstance());
3.7 反射的其他用法
反射常用来封装工具类或者在框架的底层实现