https://www.zhihu.com/question/24304289
一,先看一下反射的概念:
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
反射是java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!
看概念很晕的,继续往下看。
二,反射机制的作用:
1,反编译:.class-->.java
2,通过反射机制访问java对象的属性,方法,构造方法等;
这样好像更容易理解一些,下边我们具体看怎么实现这些功能。
三,在这里先看一下sun为我们提供了那些反射机制中的类:
java.lang.Class;
java.lang.reflect.Constructor; java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
很多反射中的方法,属性等操作我们可以从这四个类中查询。还是哪句话要学着不断的查询API,那才是我们最好的老师。
四,具体功能实现:
1,反射机制获取类有三种方法,我们来获取Employee类型
- //第一种方式:
- Classc1 = Class.forName("Employee");
- //第二种方式:
- //java中每个类型都有class 属性.
- Classc2 = Employee.class;
- //第三种方式:
- //java语言中任何一个java对象都有getClass 方法
- Employeee = new Employee();
- Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)
2,创建对象:获取类以后我们来创建它的对象,利用newInstance:
- Class c =Class.forName("Employee");
- //创建此Class 对象所表示的类的一个新实例
- Objecto = c.newInstance(); //调用了Employee的无参数构造方法.
3,获取属性:分为所有的属性和指定的属性:
a,先看获取所有的属性的写法:
- //获取整个类
- Class c = Class.forName("java.lang.Integer");
- //获取所有的属性?
- Field[] fs = c.getDeclaredFields();
- //定义可变长的字符串,用来存储属性
- StringBuffer sb = new StringBuffer();
- //通过追加的方法,将每个属性拼接到此字符串中
- //最外边的public定义
- sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
- //里边的每一个属性
- for(Field field:fs){
- sb.append("\t");//空格
- sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等
- sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字
- sb.append(field.getName()+";\n");//属性的名字+回车
- }
- sb.append("}");
- System.out.println(sb);
b,获取特定的属性,对比着传统的方法来学习:
- public static void main(String[] args) throws Exception{
- <span style="white-space:pre;"> </span>//以前的方式:
- /*
- User u = new User();
- u.age = 12; //set
- System.out.println(u.age); //get
- */
- //获取类
- Class c = Class.forName("User");
- //获取id属性
- Field idF = c.getDeclaredField("id");
- //实例化这个类赋给o
- Object o = c.newInstance();
- //打破封装
- idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。
- //给o对象的id属性赋值"110"
- idF.set(o, "110"); //set
- //get
- System.out.println(idF.get(o));
- }
4 ,获取方法,和构造方法,不再详细描述,只来看一下关键字:
方法关键字
含义
getDeclaredMethods()
获取所有的方法
getReturnType()
获得方法的放回类型
getParameterTypes()
获得方法的传入参数类型
getDeclaredMethod("方法名",参数类型.class,……)
获得特定的方法
构造方法关键字
含义
getDeclaredConstructors()
获取所有的构造方法
getDeclaredConstructor(参数类型.class,……)
获取特定的构造方法
父类和父接口
含义
getSuperclass()
获取某类的父类
getInterfaces()
获取某类实现的接口
这样我们就可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
五,反射加配置文件,使我们的程序更加灵活:
在设计模式学习当中,学习抽象工厂的时候就用到了反射来更加方便的读取数据库链接字符串等,当时不是太理解,就照着抄了。看一下.NET中的反射+配置文件的使用:
当时用的配置文件是app.config文件,内容是XML格式的,里边填写链接数据库的内容:
- <configuration>
- lt;appSettings>
- <add key="" value=""/>
- lt;/appSettings>
- </configuration>
反射的写法:
- assembly.load("当前程序集的名称").CreateInstance("当前命名空间名称".要实例化的类名);
这样的好处是很容易的方便我们变换数据库,例如我们将系统的数据库从SQL Server升级到Oracle,那么我们写两份D层,在配置文件的内容改一下,或者加条件选择一下即可,带来了很大的方便。
当然了,JAVA中其实也是一样,只不过这里的配置文件为.properties,称作属性文件。通过反射读取里边的内容。这样代码是固定的,但是配置文件的内容我们可以改,这样使我们的代码灵活了很多!
综上为,JAVA反射的再次学习,灵活的运用它,能够使我们的代码更加灵活,但是它也有它的缺点,就是运用它会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。
链接:https://www.zhihu.com/question/24304289/answer/147529485
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
首先我们了解一下JVM,什么是JVM,Java的虚拟机,java之所以能跨平台就是因为这个东西,你可以理解成一个进程,程序,只不过他的作用是用来跑你的代码的。上图是java的内存模型,我们关注的点,一个方法区,一个栈,一个堆,初学的时候老师不深入的话只告诉你java的内存分为堆和栈,易懂点吧!
假如你写了一段代码:Object o=new Object();
运行了起来!
首先JVM会启动,你的代码会编译成一个.class文件,然后被类加载器加载进jvm的内存中,你的类Object加载到方法区中,创建了Object类的class对象到堆中,注意这个不是new出来的对象,而是类的类型对象,每个类只有一个class对象,作为方法区类的数据结构的接口。jvm创建对象前,会先检查类是否加载,寻找类对应的class对象,若加载好,则为你的对象分配内存,初始化也就是代码:new Object()。
上面的流程就是你自己写好的代码扔给jvm去跑,跑完就over了,jvm关闭,你的程序也停止了。
为什么要讲这个呢?因为要理解反射必须知道它在什么场景下使用。
题主想想上面的程序对象是自己new的,程序相当于写死了给jvm去跑。假如一个服务器上突然遇到某个请求哦要用到某个类,哎呀但没加载进jvm,是不是要停下来自己写段代码,new一下,哦启动一下服务器,(脑残)!
反射是什么呢?当我们的程序在运行时,需要动态的加载一些类这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载,这样的好处对于服务器来说不言而喻,举个例子我们的项目底层有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类,这个时候反射就有用了,假设 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection这两个类我们要用,这时候我们的程序就写得比较动态化,通过Class tc = Class.forName("com.java.dbtest.TestConnection");通过类的全类名让jvm在服务器中找到并加载这个类,而如果是oracle则传入的参数就变成另一个了。这时候就可以看到反射的好处了,这个动态性就体现出java的特性了!举多个例子,大家如果接触过spring,会发现当你配置各种各样的bean时,是以配置文件的形式配置的,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。
答案比较粗糙,点到为止!
这里提供一篇比较深入的博文地址:深入解析Java反射(1) - 基础
反射机制:所谓的反射机制就是java语言在运行时拥有一项自观的能力。通过这种能力可以彻底的了解自身的情况为下一步的动作做准备。
下面具体介绍一下java的反射机制。
Java的反射机制的实现要借助于4个类:class,Constructor,Field,Method;
其中class代表的时类对 象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象。通过这四个对象我们可以粗略的看到一个类的各个组 成部分。
Java反射的作用:
在Java运行时环境中,对于任意一个类,可以知道这个类有哪些属性和方法。对于任意一个对象,可以调用它的任意一个方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于Java 语言的反射(Reflection)机制。
Java 反射机制主要提供了以下功能
在运行时判断任意一个对象所属的类。
在运行时构造任意一个类的对象。
在运行时判断任意一个类所具有的成员变量和方法。
在运行时调用任意一个对象的方法
反射的常用类和函数:Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;
其中class代表的是类对象,Constructor-类的构造器对象,Field-类的属性对象,Method-类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍Class类中针对这三个元素的方法:
1、得到构造器的方法
Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,
Constructor[] getConstructors() -- 获得类的所有公共构造函数
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关)
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)
2、获得字段信息的方法
Field getField(String name) -- 获得命名的公共字段
Field[] getFields() -- 获得类的所有公共字段
Field getDeclaredField(String name) -- 获得类声明的命名的字段
Field[] getDeclaredFields() -- 获得类声明的所有字段
3、获得方法信息的方法
Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法
Method[] getMethods() -- 获得类的所有公共方法
Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参数类型,获得类声明的命名的方法
Method[] getDeclaredMethods() -- 获得类声明的所有方法
在程序开发中使用反射并结合属性文件,可以达到程序代码与配置文件相分离的目的
如果我们想要得到对象的信息,一般需要“引入需要的‘包.类’的名称——通过new实例化——取得实例化对象”这样的过程。使用反射就可以变成“实例化对象——getClass()方法——得到完整的‘包.类’名称”这样的过程。
正常方法是通过一个类创建对象,反射方法就是通过一个对象找到一个类的信息。