java反射(Reflection)

初识反射

反射(Reflection)被视为动态预言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

反射机制提供的功能

1.在运行时判断任意一个对象所属的类。
2.在运行时构造任意一个类的对象。
3.在运行时判断任意一个类所具有的成员变量和方法。
4.在运行时调用任意一个对象的成员变量和方法。
5.生成动态代理。

反射相关的主要API

  • java.lang.Class:代表一个类
  • java.lang.reflect.Method:代表类的方法
  • java.lang.reflect.Field:代表类的成员变量
  • java.lang.reflect.Constructor:代表类的构造方法

Class类

Class类相当于一个照妖镜,通过镜子可以得到的信息:某个类的属性、方法和构造器、某个类实现了哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息。

在Object类中定义了以下方法,此方法被所有子类继承:

public final native Class<?> getClass();

以上的方法返回值的类型是一个Class类,此类是java反射的源头。

正常方式:1.引入需要的“类”名称 > 2.通过new实例化 > 3.取得实例化对象
反射方式:1.实例化对象 > 2.getClass()方法 > 3.得到完整的“类”名称

Class类常用的方法

Class clazz = Person.class;
clazz.newInstance();//调用缺省构造函数,返回该class对象的一个实例
clazz.getName(); //返回此class对象所表示的实体名称
clazz.getSuperclass();//返回当前class对象的父类的class对象
clazz.getInterfaces();//返回当前class对象的接口数字
clazz.getClassLoader();//返回该类的类加载器
clazz.getAnnotations();//返回当前class对象的所有注解

反射的应用

测试类Person.class

public class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

实例化Class类对象的四种方法

1.前提:已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。

//Class类:类的类Person.class
Class clazz = Person.class;

2.前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象。

Person person = new Person();
//getClass是继承Object的方法,返回实例所属的类的信息
Class clazz = person.getClass();

3.前提:已知一个类的全类名,可通过Class类的静态方法forName()获取。

//通过类所在路径全名,获取这个类的相关信息
Class clazz = Class.forName("com.ms.reflectdemo.Person");
//调用此类的无参构造方法,得到此类的实例
Object obj = clazz.newInstance();

4.前提:已知一个类的全类名,可通过类加载器loadClass()获取。

//通过类所在路径全名,获取这个类的相关信息
Class clazz = this.getClass().getClassLoader().loadClass("com.ms.reflectdemo.Person");
//调用此类的无参构造方法,得到此类的实例
Object obj = clazz.newInstance();

获取成员变量

//getField只能获取有访问权限的成员变量,获取无访问权限的成员变量会抛异常
//Field field = clazz.getField("name");
//getDeclaredField能获取该类的成员变量(包括私有、共有、保护)
Field field2 = clazz.getDeclaredField("name");
//设置字段可以访问,越过访问权限的限制
field2.setAccessible(true);
//设置成员变量name的值
field2.set(obj,"张三");
//获取成员变量name的值
System.out.println(field2.get(obj));
//获取类中public声明的所有成员变量
Field[] fields = clazz.getFields();
//getDeclaredFields获取所有的成员变量
Field[] fields2 = clazz.getDeclaredFields();

获取方法

//获取类中public声明的无参方法
Method method = clazz.getMethod("getName");
//获取类中的方法(包括私有、共有、保护)
Method method2 = clazz.getDeclaredMethod("getName");
//获取类中public声明的有参方法
Method method3 = clazz.getMethod("setName", String.class);
//设置方法可以访问,越过访问权限的限制
method.setAccessible(true);
//调用setName()方法
method3.invoke(obj,"李四");
//调用getName()方法
System.out.println(method2.invoke(obj));
//获取类中所有public方法
Method[] methods = clazz.getMethods();
//获取类中所有方法
Method[] methods2 = clazz.getDeclaredMethods();

类的加载过程

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。

1.类的加载:将类的class文件读入内存中,并为之创建一个java.lang.Class对象。此过程由类加载器完成。
2.类的连接:将类的二进制数据合并到JRE中
3.类的初始化:JVM负责对类进行初始化

类加载器(ClassLoader)

类加载器是用来把类(class)装载进内存的。JVM规范定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义加载器(user-defined class loader)。JVM在运行时会产生3个类加载器组成的初始化加载器层次结构。

引导类加载器(Bootstrap ClassLoader):用C++编写的,是JVM自带的类加载器,负责加载java平台核心库。该加载器无法直接获取。
扩展类加载器(Extension ClassLoader):负责加载jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包。
系统类加载器(System ClassLoader):负责加载java classpath或-D java.class.path所指目录下的类和jar包,是最常用的加载器。

public class TestClassLoader {
    public static void main(String[] args) throws IOException {
        //1.获取一个系统类加载器
        ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
        //2.获取系统类加载器的父类加载器,即扩展类加载器
        ClassLoader extLoader = sysLoader.getParent();
        //3.获取扩展类加载器的父类加载器,即引导类加载器;获取结果为null
        ClassLoader bootLoader = extLoader.getParent();
        //4.通过获取Class的实例,然后获取加载这个类的类加载器
        Class clazz = TestClassLoader.class;
        ClassLoader clazzLoader = clazz.getClassLoader();
        //5.所有lang包中的类都属于核心类库,由引导类加载器加载。
    }
}

通过类加载器获取properties配置文件

//通过类加载器获取配置文件信息,在类加载的时候执行一次,提高程序执行效率
Properties properties = new Properties();
properties.load(clazzLoader.getResourceAsStream("dbcofig.properties"));
String username = properties.getProperty("username");

还有什么方法可以用请查看源码,哪里不会点哪里。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迷图羊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值