java 反射机制
一, 概述
1, 什么是反射机制
反射机制是在运行状态中, 对于任意一个类, 都能够知道这个类的所有属性和方法; 对于任意一个对象, 都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制.
2, 反射机制能做什么
反射机制主要提供了以下功能:
1) 在运行时判断任意一个对象所属的类;
2) 在运行时构造任意一个类的对象;
3) 在运行时判断任意一个类所具有的成员变量和方法;
4) 在运行时调用任意一个对象的方法;
5) 生成动态代理.
3, 反射的优点和缺点
为什么要用反射机制? 直接创建对象不就可以了吗, 这就涉及到了动态与静态的概念:
静态编译: 在编译时确定类型, 绑定对象, 即通过.
动态编译: 运行时确定类型, 绑定对象. 动态编译最大限度发挥了 java 的灵活性, 体现了多态的应用, 有以降低类之间的藕合性.
一句话, 反射机制的优点就是可以实现动态创建对象和编译, 体现出很大的灵活性, 特别是在 J2EE 的开发中它的灵活性就表现的十分明显.
比如, 一个大型的软件, 不可能一次就把把它设计的很完美, 当这个程序编译后, 发布了, 当发现需要更新某些功能时, 我们不可能要用户把以前的卸载, 再重新安装新的版本, 假如 这样的话, 这个软件肯定是没有多少人用的. 采用静态的话, 需要把整个程序重新编译一次才可以实现功能的更新,
而采用反射机制的话, 它就可以不用卸载, 只需要在运行时才动态的创建和编译, 就可以实现该功 能.
它的缺点是对性能有影响. 使用反射基本上是一种解释操作, 我们可以告诉 JVM, 我们希望做什么并且它 满足我们的要求. 这类操作总是慢于只直接执行相同的操作.
4, 反射的原理
JAVA 语言编译之后会生成一个. class 文件, 这些 Class 对象承载了这个类型的父类, 接口, 构造函数, 方法, 属性等原始信息, 这些 class 文件在程序运行时会被 ClassLoader 加载到虚拟机中.
反射就是通过字节码文件找到某一个类, 类中的方法以及属性等.
5, 反射的应用场景
个人觉得使用反射机制的一些地方:
1) 工厂模式: Factory 类中用反射的话, 添加了一个新的类之后, 就不需要再修改工厂类 Factory 了
2) 动态代理模式
3) 数据库 JDBC 中通过 Class.forName(Driver). 来获得数据库连接驱动
4) 分析类文件: 毕竟能得到类中的方法等等
二, 反射常用方法
利用反射机制能获得类的所有信息 , 类中有什么信息, 它就可以获得什么信息.
反射的实现主要借助以下四个类
Class: 类的对象
Constructor: 类的构造方法
Field: 类中的属性对象
Method: 类中的方法对象
我们知道所有类的对象其实都是 Class 的实例, 所以要获得对象, 首先要获得 class 实例
1, 获得 class 实例三种方法
- Class<?> demo1=Class.forName("com.jincou.study.Demo"); // 一般推荐这种
- Class<?> demo2=new Demo().getClass();
- Class<?> demo3=Demo.class;
获得 class 对象后, 我们就可以通过 class 对象获得实际对象
Demo obj=(Demo)demo1.newInstance();// 创建对象的实例, 这里需要一个无参的构造函数
OK, 有了对象就什么都好办了, 想要什么信息就有什么信息了.
2, 获得构造函数
- Constructor getConstructor(Class[] params)// 根据指定参数获得 public 构造器
- Constructor[] getConstructors() // 获得 public 的所有构造器
- Constructor getDeclaredConstructor(Class[] params)// 根据指定参数获得 public 和非 public 的构造器
- Constructor[] getDeclaredConstructors() // 获得 public 的所有构造器
3, 获得类方法
- Method getMethod(String name, Class[] params) // 根据方法名, 参数类型获得方法
- Method[] getMethods() // 获得所有的 public 方法
- Method getDeclaredMethod(String name, Class[] params) // 根据方法名和参数类型, 获得 public 和非 public 的方法
- Method[] getDeclaredMethods() // 获得所以的 public 和非 public 方法
4, 获得类中属性
- Field getField(String name) // 根据变量名得到相应的 public 变量
- Field[] getFields() // 获得类中所以 public 的方法
- Field getDeclaredField(String name)// 根据方法名获得 public 和非 public 变量
- Field[] getDeclaredFields() // 获得类中所有的 public 和非 public 方法
三, 综合小案例
上面的都是讲解理论, 主要是日后可以当做自己的查找的 API 来用, 下面来一个综合小案例来加深对它的理解:
- package com.jincou.study;
- import java.lang.reflect.Constructor;
- import java.lang.reflect.Field;
- import java.lang.reflect.Method;
- public class Main {
- /**
- * 为了看清楚 Java 反射部分代码, 所有异常我都最后抛出来给虚拟机处理!
- */
- public static void main(String[] args) throws Exception {
- System.out.println("Demo1===============================================");
- //Demo1. 通过 Java 反射机制得到类的包名和类名
- Demo1();
- System.out.println("Demo2===============================================");
- //Demo2. 验证所有的类都是 Class 类的实例对象
- Demo2();
- System.out.println("Demo3===============================================");
- //Demo3. 通过 Java 反射机制, 用 Class 创建类对象 [这也就是反射存在的意义所在], 无参构造
- Demo3();
- System.out.println("Demo4===============================================");
- //Demo4: 通过 Java 反射机制得到一个类的构造函数, 并实现构造带参实例对象
- Demo4();
- System.out.println("Demo5===============================================");
- //Demo5: 通过 Java 反射机制操作成员变量, set 和 get
- Demo5();
- System.out.println("Demo6===============================================");
- //Demo6: 通过 Java 反射机制得到类的一些属性: 继承的接口, 父类, 函数信息, 成员信息, 类型等
- Demo6();
- System.out.println("Demo7===============================================");
- //Demo7: 通过 Java 反射机制调用类中方法
- Demo7();
- System.out.println("Demo8===============================================");
- //Demo8: 通过 Java 反射机制获得类加载器
- Demo8();
- }
- /**
- * Demo1: 通过 Java 反射机制得到类的包名和类名
- */
- public static void Demo1()
- {
- Person person = new Person();
- System.out.println("包名:" + person.getClass().getPackage().getName());
- System.out.println("完整类名:" + person.getClass().getName());
- }
- /**
- * Demo2: 验证所有的类都是 Class 类的实例对象
- */
- public static void Demo2() throws ClassNotFoundException
- {
- // 定义两个类型都未知的 Class , 设置初值为 null, 看看如何给它们赋值成 Person 类
- Class<?> class1 = null;
- Class<?> class2 = null;
- // 写法 1, 可能抛出 ClassNotFoundException [多用这个写法]
- class1 = Class.forName("com.jincou.study.Person");
- System.out.println("(写法 1) 包名:" + class1.getPackage().getName() + ","
- + "完整类名:" + class1.getName());
- // 写法 2
- class2 = Person.class;
- System.out.println("(写法 2) 包名:" + class2.getPackage().getName() + ","
- + "完整类名:" + class2.getName());
- }
- /**
- * Demo3: 通过 Java 反射机制, 用 Class 创建类对象 [这也就是反射存在的意义所在]
- */
- public static void Demo3() throws Exception
- {
- Class<?> class1 = null;
- class1 = Class.forName("com.jincou.study.Person");
- // 由于这里不能带参数, 所以你要实例化的这个类 Person, 一定要有无参构造函数哈~
- Person person = (Person) class1.newInstance();
- person.setAge(20);
- person.setName("张三");
- System.out.println("name:" + person.getName() + "age:" + person.getAge());
- }
- /**
- * Demo4: 通过 Java 反射机制得到一个类的构造函数, 并实现创建带参实例对象
- */
- public static void Demo4() throws Exception
- {
- Class<?> class1 = null;
- Person person1 = null;
- Person person2 = null;
- class1 = Class.forName("com.jincou.study.Person");
- // 得到一系列构造函数集合
- Constructor<?>[] constructors = class1.getConstructors();
- // 无参构造函数
- person1 = (Person) constructors[0].newInstance();
- person1.setAge(30);
- person1.setName("李四");
- // 有参构造函数
- person2 = (Person) constructors[1].newInstance(20,"王五");
- System.out.println("name:" + person1.getName() + "age:" + person1.getAge() );
- System.out.println("name:" + person2.getName() + "age:" + person2.getAge() );
- }
- /**
- * Demo5: 通过 Java 反射机制操作成员变量, set 和 get
- */
- public static void Demo5() throws Exception
- {
- Class<?> class1 = null;
- class1 = Class.forName("com.jincou.study.Person");
- Object obj = class1.newInstance();
- // 获取 com.jincou.study.Person.name 的属性名
- Field personNameField = class1.getDeclaredField("name");
- personNameField.setAccessible(true);
- personNameField.set(obj, "张三");
- System.out.println("修改属性之后得到属性变量的值:" + personNameField.get(obj));
- }
- /**
- * Demo6: 通过 Java 反射机制得到类的一些属性: 继承的接口, 父类, 函数信息, 成员信息, 类型等
- */
- public static void Demo6() throws ClassNotFoundException
- {
- Class<?> class1 = null;
- class1 = Class.forName("com.jincou.study.SuperMan");
- // 取得父类名称
- Class<?> superClass = class1.getSuperclass();
- System.out.println("SuperMan 类的父类名:" + superClass.getName());
- // 取得属性信息
- Field[] fields = class1.getDeclaredFields();
- for (int i = 0; i <fields.length; i++) {
- System.out.println("类中的成员:" + fields[i]);
- }
- // 取得类方法
- Method[] methods = class1.getDeclaredMethods();
- // 取得 SuperMan 类的方法
- System.out.println("函数名:" + methods[0].getName());
- System.out.println("函数代码写法:" + methods[0]);
- // 取得类实现的接口, 因为接口类也属于 Class, 所以得到接口中的方法也是一样的方法得到哈
- Class<?> interfaces[] = class1.getInterfaces();
- for (int i = 0; i <interfaces.length; i++) {
- System.out.println("实现的接口类名:" + interfaces[i].getName() );
- }
- }
- /**
- * Demo7: 通过 Java 反射机制调用类方法
- */
- public static void Demo7() throws Exception
- {
- Class<?> class1 = null;
- class1 = Class.forName("com.jincou.study.SuperMan");
- // 调用 fly() 方法
- Method method = class1.getMethod("fly");
- method.invoke(class1.newInstance());
- // 调用 walk(int m) 方法
- method = class1.getMethod("walk",int.class);
- method.invoke(class1.newInstance(),100);
- }
- /**
- * Demo8: 通过 Java 反射机制得到类加载器信息
- */
- public static void Demo8() throws ClassNotFoundException
- {
- Class<?> class1 = null;
- class1 = Class.forName("com.jincou.study.SuperMan");
- String nameString = class1.getClassLoader().getClass().getName();
- System.out.println("类加载器类名:" + nameString);
- }
- }
- /**
- * Person 类
- */
- class Person{
- private int age;
- private String name;
- public Person(){
- }
- public Person(int age, String name){
- this.age = age;
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- //SuperMan 类
- class SuperMan extends Person implements ActionInterface
- {
- private boolean BlueBriefs;
- public void fly()
- {
- System.out.println("我是 fly 方法......");
- }
- public boolean isBlueBriefs() {
- return BlueBriefs;
- }
- public void setBlueBriefs(boolean blueBriefs) {
- BlueBriefs = blueBriefs;
- }
- @Override
- public void walk(int m) {
- System.out.println("我是 walk 方法, 我的 int 值为:" + m );
- }
- }
- //ActionInterface 接口
- interface ActionInterface{
- public void walk(int m);
- }
查看运行结果:
想太多, 做太少, 中间的落差就是烦恼. 想没有烦恼, 要么别想, 要么多做. 中校 [2]
来源: https://www.cnblogs.com/qdhxhz/p/9230805.html