学习笔记-基础知识13-反射机制

来源:互联网 发布:淘宝网 医用弹力祙 编辑:程序博客网 时间:2024/06/15 09:29
反射机制


1.反射的概念
要是想得到对象真正的类型,就得使用反射。
反射机制:
反射机制指的是程序在运行时能够获取自身的信息。
在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。
反射机制的优点与缺点:
反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性。
缺点是对性能有影响。使用反射基本上是一种解释操作,这类操作总是慢于只直接执行相同的操作。
Class类和Class类实例
Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class类。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,
不同的类的字节码是不同的,所以它们在内存中的内容是不同的;
用类来描述对象,用元数据来描述Class,反射就是得到元数据的行为。
一个类在虚拟机中只有一份字节码;

2.获得Class对象
3种方式:
a.调用某个类的class属性获取Class对象,
如Date.class会返回Date类对应的Class对象(其实就是得到一个类的一份字节码文件);
b.使用Class类的forName(String className)静态方法,className表示全限定名;
如String的全限定名:java.lang.String;
c.调用某个对象的getClass()方法。该方法属于Object类;
Class<?> clz = new Date().getClass();
获取Class 对象最常用的是利用属性的方法!


3.九个预定义Class对象
基本的Java类型(boolean、byte、char、short、int、long、float 和double)
和关键字void通过class属性也表示为Class对象;
Class类中boolean isPrimitive():判定指定的Class对象是否表示一个基本类型。
包装类和Void类的静态TYPE字段;
包装类都有一个常量TYPE,用来表示其基本数据类型的字节码
Integer.TYPE == int.class ;
Integer.class == int.class;
数组类型的Class实例对象:
Class<String[]> clz = String[].class;
Class类中boolean isArray():判定此Class对象是否表示一个数组类型。


4.利用Class获取类的属性信息
Class<BaseDemo> c = BaseDemo.class;
c:类可以,接口也可以
c.getPackage();得到包名
c.getName();得到全限定名
c.getSimpleName();得到类的简称
c.getSuperclass().getSimpleName();得到父类
c.getInterfaces();得到接口


5.Class中得到构造方法Constructor、方法Method、字段Field
常用方法:
Constructor类用于描述类中的构造方法:
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回该Class对象表示类的指定的public构造方法;
Constructor<?>[] getConstructors()
返回该Class对象表示类的所有public构造方法;
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回该Class对象表示类的指定的构造方法,和访问权限无关;
Constructor<?>[] getDeclaredConstructors()
返回该Class对象表示类的所有构造方法,和访问权限无关;
Method类用于描述类中的方法:
Method getMethod(String name, Class<?> ... parameterTypes)
返回该Class对象表示类和其父类的指定的public方法;
Method[] getMethods():
返回该Class对象表示类和其父类的所有public方法;
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回该Class对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;
Method[] getDeclaredMethods(): 
获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;


对于方法,字段,构造方法之类用类获取记住四个:
获取全部,获取特定,暴力获取全部,暴力获取特定!

6.利用反射创建对象
创建对象:
方法1.使用Class对象的newInstance()方法创建该Class对象的实例,
此时该Class对象必须要有无参数的构造方法。
方法2.使用Class对象获取指定的Constructor对象,
再调用Constructor的newInstance()方法创建对象类的实例,
此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,
那么必须先申请访问,将可以访问设置为true;
总结步骤:
a.获取该类的Class对象。
b.利用Class对象的getConstructor()方法来获取指定的构造方法。
c.申请访问(设置为可访问)
AccessibleObject对象的setAccessible(boolean flag)方法,
当flag为true的时候,就会忽略访问权限(可访问私有的成员)。
d.调用Constructor(构造方法)的newInstance()方法创建对象。


7.使用反射调用方法
每个Method的对象对应一个具体的底层方法。
获得Method对象后,程序可以使用Method里面的invoke方法来执行该底层方法。
Object invoke(Object obj,Object ... args):
其中:obj表示调用底层方法的对象,
args表示传递的实际参数。
若底层方法是静态的,那么可以忽略指定的obj参数。该参数可以为null。
若底层方法所需的形参个数为0,则所提供的args数组长度可以为0 或null。
不写,null或new Object[]{}
若底层方法返回的是数组类型,invoke方法返回的是底层方法的返回类型;


8.使用反射调用可变参数方法
使用反射调用可变参数方法,要把可变参数都当做是其对应的数组类型参数;
如show(XX... is)作为show(XX[] is)调用;
不管可变参数元素类型是引用类型,都使用Object[]封装一层,再传递,保证无误。


9.使用反射操作字段
Field提供两组方法操作字段:
xxx getXxx(Object obj):获取obj对象该Field的字段值,此处的xxx表示8 个基本数据类型。
若该字段的类型是引用数据类型则使用Object get(Object obj);
void setXxx(Object obj,xxx val):将obj对象的该Field字段设置成val值。
若该字段的类型是引用数据类型则使用void set(Object obj, Object value);


10.反射来获取泛型信息
对普通Field:
通过指定对应的Class对象,程序可以获得该类里面所有的Field,
不管该Field使用private,public。
获得Field对象后使用getType()来获取其类型。
Class<?> type = f.getType();//获得字段的类型
若该Field有泛型修饰:
Map<String,Integer>;
通过Type gType = f.getGenericType()得到泛型类型
将Type对象强转为ParameterizedType,其表示增加泛型后的类型
Type getRawType()返回被泛型限制的类型;
Type[] getActualTypeArguments()返回泛型参数类型;
利用反射来获取泛型的类型(泛型信息)步骤:
获取当前类
获取目标字段
获取包含泛型类型的类型getGenericType()
强转至子类ParameterizedType 因为Type 没有任何对应的方法
获得泛型真正的类型getActualTypeArguments()
0 0
原创粉丝点击