一、什么是反射
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。)语言的一个关键性质。
二、反射的作用
我们知道反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!
反射机制主要提供以下功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理。
三、反射案例
1、反射中的常用类
java.lang.Class;
java.lang.reflect.Constructor; java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
2、得到Class对象的各种方式
package Study.Reflection_Study;
/**
* @author NJUPT_MR.Z
* @create 2022-05-12 19:13
* @Description 得到Class对象的各种方式
*/
public class GetClass {
public static void main(String[] args) throws Exception {
//1.Class.forName();多用于配置文件,读取类全路径,加载类
String classAllPath = "Study.Reflection_Study.Cat";
Class<?> aClass = Class.forName(classAllPath);
System.out.println(aClass);
//2.类名.class();多用于参数传递
Class<Cat> aClass1 = Cat.class;
System.out.println(aClass1);
//3.对象.getClass();适用于有对象实例的情况
Cat cat = new Cat();
Class<? extends Cat> aClass2 = cat.getClass();
System.out.println(aClass2);
//4.classLoader.loadClass();类加载器[4种]
//(1)得到类加载器
ClassLoader classLoader = cat.getClass().getClassLoader();
//(2)通过类加载器得到Class对象
Class<?> aClass3 = classLoader.loadClass(classAllPath);
System.out.println(aClass3);
System.out.println(aClass.hashCode());
System.out.println(aClass1.hashCode());
System.out.println(aClass2.hashCode());
System.out.println(aClass3.hashCode());
//5.基本数据类型.class
Class<Integer> integerClass = int.class;
Class<Character> characterClass = char.class;
System.out.println(integerClass + " " + characterClass);
//6.基本数据类型包装类.TYPE
Class<Integer> type = Integer.TYPE;
System.out.println(type);
System.out.println(integerClass.hashCode());
System.out.println(type.hashCode());
}
}
运行结果:
class Study.Reflection_Study.Cat
class Study.Reflection_Study.Cat
class Study.Reflection_Study.Cat
class Study.Reflection_Study.Cat
1828972342
1828972342
1828972342
1828972342
int char
int
460141958
460141958
3、演示哪些类型有Class对象
package Study.Reflection_Study;
import java.io.Serializable;
/**
* @author NJUPT_MR.Z
* @create 2022-05-12 19:29
* @Description 演示哪些类型有Class对象
*/
public class AllTypeClass {
public static void main(String[] args) {
Class<String> aClass1 = String.class;//外部类
Class<Serializable> aClass2 = Serializable.class;//接口
Class<Integer[]> aClass3 = Integer[].class;//数组
Class<char[][]> aClass4 = char[][].class;
Class<Override> aClass5 = Override.class;//注解
Class<Thread.State> aClass6 = Thread.State.class;//枚举
Class<Integer> aClass7 = int.class;//基本数据类型
Class<Void> aClass8 = void.class;//void类型
Class<Class> aClass9 = Class.class;//Class类
System.out.println(aClass1);
System.out.println(aClass2);
System.out.println(aClass3);
System.out.println(aClass4);
System.out.println(aClass5);
System.out.println(aClass6);
System.out.println(aClass7);
System.out.println(aClass8);
System.out.println(aClass9);
}
}
运行结果:
class java.lang.String
interface java.io.Serializable
class [Ljava.lang.Integer;
class [[C
interface java.lang.Override
class java.lang.Thread$State
int
void
class java.lang.Class
4、 演示Class类常用方法
package Study.Reflection_Study;
import java.lang.reflect.Field;
/**
* @author NJUPT_MR.Z
* @create 2022-05-12 18:58
* @Description 演示Class类常用方法
*/
public class Class02 {
public static void main(String[] args) throws Exception {
String classAllPath = "Study.Reflection_Study.Cat";
//1.获取Class对象
Class<?> cls = Class.forName(classAllPath);//<?>表示不确定Java类型,可去掉
//2.输出Class
System.out.println(cls);//哪个类的class对象
System.out.println(cls.getClass());//运行类型
//3.得到包名
System.out.println(cls.getPackage().getName());
//4.得到类名
System.out.println(cls.getName());
//5.生成对象实例
Object o = cls.getDeclaredConstructor().newInstance();
//6.通过反射获取属性
Field age = cls.getField("age");//公有属性
System.out.println(age);
//7.给属性设置值
age.set(o,10);
System.out.println(age.get(o));
//8.得到所有公有属性
Field[] fields = cls.getFields();
for (Field f: fields) {
System.out.println(f);
}
}
}
运行结果:
class Study.Reflection_Study.Cat
class java.lang.Class
Study.Reflection_Study
Study.Reflection_Study.Cat
public int Study.Reflection_Study.Cat.age
10
public int Study.Reflection_Study.Cat.age
public java.lang.String Study.Reflection_Study.Cat.sex
5、通过反射机制创建实例
package Study.Reflection_Study;
import java.lang.reflect.Constructor;
/**
* @author NJUPT_MR.Z
* @create 2022-05-14 18:57
* @Description 通过反射机制创建实例
*/
public class ReflectCreateInstance {
public static void main(String[] args) throws Exception {
//获取User类的Class对象
Class<?> userClass = Class.forName("Study.Reflection_Study.User");
//通过public的无参构造器创建实例
Object o = userClass.newInstance();
System.out.println(o);
//通过public的有参构造器创建实例
Constructor<?> constructor = userClass.getConstructor(String.class);
Object o1 = constructor.newInstance("猪头");
System.out.println(o1);
//通过非public的有参构造器创建实例☆☆☆
Constructor<?> declaredConstructor = userClass.getDeclaredConstructor(int.class, String.class);
declaredConstructor.setAccessible(true);//暴破,使用反射访问private构造器
Object o2 = declaredConstructor.newInstance(1000,"呆子");
System.out.println(o2);
}
}
class User {
private int age=10;
private String name="猫";
public User() {
}
public User(String name) {
this.name = name;
}
private User(int age, String name) {
this.age = age;
this.name = name;
}
public String toString() {
return "User[age=" + age + ", name=" + name + "]";
}
}
运行结果:
User[age=10, name=猫]
User[age=10, name=猪头]
User[age=1000, name=呆子]
6、演示通过反射调用方法
package Study.Reflection_Study;
import java.lang.reflect.Method;
/**
* @author NJUPT_MR.Z
* @create 2022-05-14 19:40
* @Description 演示通过反射调用方法
*/
public class ReflectAccessMethod {
public static void main(String[] args) throws Exception {
Class<?> bossClass = Class.forName("Study.Reflection_Study.Boss");
Object o = bossClass.newInstance();
//调用hi方法
Method hi = bossClass.getDeclaredMethod("hi", String.class);
hi.invoke(o, "呆子");
//调用say方法
Method say = bossClass.getDeclaredMethod("say", int.class, String.class, char.class);
say.setAccessible(true);//暴破
System.out.println(say.invoke(o, 100, "狗头", 'a'));
System.out.println(say.invoke(null, 200, "猫头", 'b'));
//在反射中,如果方法有返回值,统一返回Object
Object returnValue = say.invoke(o, 20, "猪头", 'c');
System.out.println("运行类型为" + returnValue.getClass());
}
}
class Boss {
public int age;
private static String name;
public Boss() {
}
private static String say(int n, String s, char c) {
return n + " " + s + " " + c;
}
public void hi(String s) {
System.out.println("hi," + s);
}
}
运行结果:
hi,呆子
100 狗头 a
200 猫头 b
运行类型为class java.lang.String
7、演示反射操作属性
package Study.Reflection_Study;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* @author NJUPT_MR.Z
* @create 2022-05-14 19:27
* @Description 演示反射操作属性
*/
public class ReflectAccessProperty {
public static void main(String[] args) throws Exception {
//获取Class对象
Class<?> stuClass = Class.forName("Study.Reflection_Study.Student");
//创建对象
Constructor<?> constructor = stuClass.getConstructor();
Object o = constructor.newInstance();
System.out.println(o);
//反射得到age属性对象
Field age = stuClass.getField("age");
age.set(o,88);//通过反射操作属性
System.out.println(age.get(o));
System.out.println(o);
//反射操作name属性
Field name = stuClass.getDeclaredField("name");
name.setAccessible(true);//暴破获取private属性
name.set(o,"猪头");//或者name.set(null,"猪头"),因为name是static的
System.out.println(name.get(o));//或者name.get(null)
System.out.println(o);
}
}
class Student {
public int age;
private static String name;
public Student() {
}
public String toString() {
return "Student [age=" + age + ", name=" + name + "]";
}
}
运行结果:
Student [age=0, name=null]
88
Student [age=88, name=null]
猪头
Student [age=88, name=猪头]
四、反射机制利弊
反射虽然很灵活,能够使得写的代码,变的大幅精简,所以在用的时候,一定要注意具体的应用场景,反射的优缺点如下:
优点:
(1)能够运行时动态获取类的实例,大大提高系统的灵活性和扩展性。
(2)与Java动态编译相结合,可以实现无比强大的功能
缺点:
(1)使用反射的性能较低
(2)使用反射相对来说不安全
(3)破坏了类的封装性,可以通过反射获取这个类的私有方法和属性