一.反射的概念:
java反射机制是在程序运行状态中,可以动态获取任意一个类的所有属性和方法。以及获取它的实例和访问实例的所有属性和方法。这种动态获取类信息以及动态访问属性和方法的功能被成为java语言的反射机制。(在学习反射前,先了解Class对象的概念,以及动态编译和静态编译)

  • 静态编译:编译期确定类型,绑定对象(程序未运行)
  • 动态编译:运行时确定类型,绑定对象(程序运行中)

获取Class对象的四种方式

第一种:实例.getClass()
1.在内存中新建一个Person类的实例,对象p对这个内存地址进行引用
2.对象p调用getClass()方法,获取p对应的Class对象。这个方法是Object的一个方法
Person p = new Person();
Class cls = p.getClass();

第二种:Class.forName()            
1.Class类提供了一个静态方法forName(),然后将类的全限定名称作为参数
2.通过JVM查找并加载指定的类
3.如果没有找到会抛出ClassNotFoundException异常
Class cls1 = Class.forName("reflect.Person");

第三种:类.class
//通过类的静态属性class
Class cls2 = P.class;
注:上面三种方式,最常用的是第二种。在一些框架中比如spring,mybatis,
都是通过传入类的全称来操作类。    

第四种:类加载器,加载类全限的名称
Class cls3 = ClassLoader.getSystemClassLoader().loadClass("reflect.Person");

二.反射常用的API

public class Person {

    private String name ;
    public Integer age;
    
    public Person() {
        
    }
    
    public Person(String name) {
        this.name = name;
    }
    
    private void fun() {
        System.out.println("11111");
    }
}
注:通过例子介绍一部分API,其他的可以查看API文档
//通过类对象获取指定类的实例
Class cls1 = Class.forName("reflect.Person");
1.Person p = (Person)cls1.newInstance();

//通过构造方法获取实例,首先要获取构造方法对象
//获取无参构造函数对象
2.Constructor constructor = cls1.getDeclaredConstructor(null);
//获取实例
Person p1 = (Person)constructor.newInstance();

//调用p1实例中的fun方法,首先获取方法对象
//指定方法名和参数获取方法对象
3.Method method = cls1.getDeclaredMethod("fun",null);
//调用p1中的fun方法并且没有参数,此处可以理解为将p1实例作为参数传入,
然后在method.invoke(p1,null);
method对象的invoke方法中执行p1中名字为fun的方法。


4.//通过名字获取指定属性
    Field field = cls1.getDeclaredField("age");
    field.set(p1, 15);//给p1实例设置age的值为15
            
    Field field2 = cls1.getDeclaredField("name");                    
    field2.setAccessible(true);//设置私有的属性也可以访问
    field2.set(p1, "mary");
            
    System.out.println(p1.name);
    System.out.println(p1.age);

5.下面的方法基本和上面的类似,具体可看api
//获取本类中**声明的**所有方法,不受修饰符限制,私有方法访问前,需要setAccessible(true)
2.Method[] declaredMethods = cls1.getDeclaredMethods();            
            
//获取类中所有公开方法,包含继承父类的公开方法
3.Method[] methods = cls1.getMethods();
            
//获取构造方法
4.Constructor[] c = cls1.getDeclaredConstructors();
getDeclaredConstructors:表示获取类中所有的构造方法,4种权限修饰符都包括
getConstructors:表示获取类中所有公有的构造方法。
            
//获取本类中**声明的**所有属性,
5.Field[] fields = cls1.getDeclaredFields();
            
//获取本类中所有公开的属性
5.Field[] field3 = cls1.getFields();

三.反射的常见问题
1).使用场景
反射在平常开发中使用很少,但是在框架和设计模式中大量出现。比如动态代理设计模式,spring,mybatis..框架中都是使用了大量的反射机制。
1.JDBC连接数据库时使用了class.forName()利用反射加载数据库驱动;
2.spring的IOC,通过加载类的全限定名称获取Class对象,然后创建类的实例。
2).反射的优缺点
优点:动态加载类型,运行期获取类信息,提高代码灵活度,降低代码耦合性
缺点:性能瓶颈,反射相当于解释操作,通知jvm要做的事情。性能比直接的java代码要慢很多。可以动态的改变属性,包括私有的,会造成一定的安全问题。


forest
0 声望1 粉丝