反射是什么,反射的作用是什么,怎么使用反射,反射的效果是什么。本篇内容均有提到
什么是反射?
反射是一种用在运行时动态获取类的相关信息的机制(包括私有属性和私有方法)
Java反射主要用到的类Class、Field、Constructor、Method
反射是围绕Class类开展的,一切反射相关的代码都是从获取java.lang.Class类对象开始,Class对象包含了一个类的所有信息,各种与类相关的信息都可以在Class类里找到,并且可以对这个类的对象进行操作。当一个类被加载到内存(缓存cache)中时会自动生成一个类对应的字节码文件对象(Class类对象),获得Class类的实例有三种方法:Class.forName(类名)、类的对象名.getClass()、类.class;
//获得类的Class对象
//方法1:
Class clazz = Class.forName(className);
System.out.println(clazz);
//方法2:
Class clazz1 = User.class;
System.out.println(clazz==clazz1);
//方法3:
User user = new User();
Class clazz2 = user.getClass();
System.out.println(clazz2==clazz1);
clazz.getFields();//获得这个对象的所有属性
通过Class类对象可以获取构造器对象、Method类对象、Field类对象;
获取构造器对象
//使用反射机制时,只知道类的全名称(包名加类名) String className = "com.ffyc.javareflect.User"; //1.通过类名获得类的class对象 Class aclass = Class.forName(className); //2.通过类的Class对象,创建对象 Object obj = aclass.newInstance(); System.out.println(obj); //通过Class类的实例调用方法来获得类中的构造方法。通过构造方法api中的方法创建对象 //1. Constructor constructor = aclass.getConstructor(); Object obj1=constructor.newInstance(); //2. Constructor constructor1=aclass.getConstructor(String.class,String.class); Object obj2=constructor1.newInstance("li","111"); //3. Constructor[] constructors = aclass.getConstructors();//获得所有公共的构造方法 System.out.println(constructors.length); //4.获得类中任意的构造方法,包含私有的构造方法 aclass.getDeclaredConstructor(); //5.获得类中所有的的构造方法,包含私有的构造方法 aclass.getDeclaredConstructors();
获取Method类的对象
String className = "com.ffyc.javareflect.User";
Class aClass = Class.forName(className);
//获得私有,破坏封装,不建议使用
Object o=aClass.newInstance();
//模拟从数据库查询数据
HashMap<String,String> map = new HashMap<>();
map.put("account","lll");
map.put("password","111");
Field[] fields = aClass.getFields();//获取类的所有属性
System.out.println(fields);
//获得类中成员方法
Method method = aClass.getMethod("eat");
method.invoke(o,args);//通过Method类的对象执行方法
获取Field类的对象
String className = "com.ffyc.javareflect.User";
//调用时自动生成无参构造
Class aClass = Class.forName(className);
//对user中所有属性进行赋值
Object object = aClass.newInstance();//通过类的字节码文件对象创建user的对象
HashMap<String,String> map = new HashMap<>();
map.put("account","password");
map.put("password","account");
Field[] fields = aClass.getFields();
for(Field field:fields){
String methodName = "set"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1);
Method method = aClass.getMethod(methodName,field.getType());
method.invoke(object,args);
}
反射的作用
反射机制拥有强大的功能,能够在Java程序运行时凭借完整类名动态地获取类相关信息,即使是私有的方法和属性也能被获取(但是这样就会破坏类原本的封装性,一般不建议这样干),同时在程序运行时使用反射会增加性能开销,不建议频繁地使用反射,那样会大大地增加程序性能开销。
反射最重要的用途就是开发各种通用框架。
反射的优缺点
优点:
1.增强代码的复用率,比如动态代理
2.可以在运行时动态地获取类的所有信息
3.增强程序的灵活性,可以在程序运行时动态地修改属性的值
缺点:
1.反射加载需要分析,可能会大大增加性能开销,不建议过度使用反射
2.反射可以获取类的私有属性、私有方法,破坏了类原本的封装性
3.使用反射可能需要在一个没有安全限制的环境
反射的用途
1)比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。还有在struts2的struts.xml中配置action,也是通过反射调用的action。
2)还有在我们创建数据库链接时,这句代码Class tc = Class.forName(“com.java.dbtest.TestConnection”)就是告诉JVM去加载这个类,而加载的过程是在程序执行过程中动态加载的。通过类的全类名让jvm在服务器中找到并加载这个类,而如果是使用别的数据库,那就要换一个类了,如果是传统写死的方法创建,就要修改原来类的代码,而对于反射,则只是传入的参数就变成另一个了而已,可以通过修改配置文件,而不是直接修改代码。
3)再比如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。只是如果这个类还没有,获取时会获取不到,但不会导致编译错误,更不会导致程序的崩溃。
4)还有当我们在使用 IDE(如 Eclipse\IDEA)时,当我们输入一个队长或者类并向调用它的属性和方法时,一按 (“.”)点号,编译器就会自动列出她的属性或方法,这里就会用到反射。