反射

反射是在运行时获取类型的信息,再根据这些信息进行操作。

一、Class类

每个已加载的类在内存中都有一份类信息,每个对象都有指向它的类信息的引用。

在Java中,类信息对应的类就是java.lang.Class(注意不是小写的class),Object方法:

public final native Class<?> getClass()

Class是泛型类,还有一种获取Class方法:

Class<Date> cls = Date.class

接口也有Class对象:

Class<Comparable> cls = Comparable.class;

基本类型没有getClass方法,但也都有对应的Class对象,类型参数为相应的包装类型:

Class<Integer> intCls = int.class;
Class<Byte> byteCls = byte.class;
Class<Character> charCls = char.class;
Class<Double> doubleCls = double.class;

void也有:

Class<Void> voidCls = void.class;

对于数组每个维度都有一个:

String[] strArr = new String[10];
int[][] twoDimArr = new int[3][2];
int[] oneDimArr = new int[10];
Class<? extends String[]> strArrCls = strArr.getClass();
Class<? extends int[][]> twoDimArrCls = twoDimArr.getClass();
Class<? extends int[]> oneDimArrCls = oneDimArr.getClass();

根据类名加载Class:

Class<?> cls = Class.forName("java.util.HashMap");

下面介绍Class的一些方法。

1.名称信息

public String getName()
public String getSimpleName()
public String getCanonicalName()
public Package getPackage()

2.字段信息

类中定义的静态和实例变量被称为字段,在Java中用Field表示,位于包java.lang.reflect。Class中获取字段信息的方法:

//返回所有的public字段,包括其父类的,如果没有字段,返回空数组
public Field[] getFields()
//返回本类声明的所有字段,包括非public的,但不包括父类的
public Field[] getDeclaredFields()
//返回本类或者父类中指定名字的public字段,找不到抛异常
public Field getField(String name)
//根据名字找本类的字段
public Field getDeclaredField(String name)

Field也有很多方法获取字段信息:

//获取字段名称
public String getName()
//判断当前程序是否有该字段的访问权限
public boolean isAccessible()
//flag设为true表示允许读写非public的字段
public void setAccessible(boolean flag)
//获取指定对象obj中该字段的值
public Object get(Object obj)
//将指定对象obj中该字段的值设为value
public void set(Object obj, Object value)

在上面的set/get方法中,对于静态变量,obj被忽略,设置为null。

其他方法:

public int getModifiers()
public Class<?> getType()
public void setBoolean(Object obj, boolean z)
public boolean getBoolean(Object obj)
public void setDouble(Object obj, double d)
public double getDouble(Object obj)
public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
public Annotation[] getDeclaredAnnotations()

        try {Field f = Test.class.getDeclaredField("MAX_COUNT");int mod = f.getModifiers();System.out.println(Modifier.toString(mod)); //private static finalSystem.out.println(Modifier.isPublic(mod));//false} catch (NoSuchFieldException e) {e.printStackTrace();}

3.方法信息

用类Method表示,Class有如下方法:

public Method[] getMethods()
public Method[] getDeclaredMethods()
public Method getMethod(String name, Class<?>... parameterTypes)
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

Method类中的方法有:

public String getName()
public void setAccessible(boolean flag)
public Object invoke(Object obj, Object... args) throws
IllegalAccessException, Illegal-ArgumentException, InvocationTargetException

对于invoke方法,如果Method为静态方法,obj被忽略,传入null。args可以为null,

或者为空数组。方法的返回值被包装为Object返回,如果实际方法调用抛出异常,异常

被包装为InvocationTargetException重新抛出,可以通过getCause方法得到原异常。

4.创建对象和构造方法

Class有一个可以创建对象的方法:

public T newInstance() throws InstantiationException, IllegalAccessException

它会调用默认的构造方法,如果没有,抛出异常。

newInstance()方法只能使用默认的构造方法。Class还有一些获取其他构造方法的方法:

public Constructor<?>[] getConstructors()
public Constructor<?>[] getDeclaredConstructors()
public Constructor<T> getConstructor(Class<?>... parameterTypes)
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

类Constructor表示构造方法,通过它可以创建对象,方法为:

public T newInstance(Object ... initargs) throws InstantiationException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException

例子:

Constructor<StringBuilder> contructor= StringBuilder.class
.getConstructor(new Class[]{int.class});
StringBuilder sb = contructor.newInstance(100);

5.类型检查和转换

如果检查的类型是动态的,可以使用Class类的如下方法:

public native boolean isInstance(Object obj);

Class cls = Class.forName("java.util.ArrayList");if(cls.isInstance(list)){System.out.println("array list");
}

动态的强制类型转换,可以使用Class方法:

public T cast(Object obj)

判断Class之间的关系

//检查参数类型cls能否赋值给当前class类型的变量
public native boolean isAssignableFrom(Class<?> cls);

6.Class的类型信息

public native boolean isArray()
public native boolean isPrimitive() //是否是基础类型
public native boolean isInterface()
public boolean isEnum()
public boolean isAnnotation()
public boolean isAnonymousClass() //是否是匿名类
public boolean isMemberClass()  //是否是成员类,成员类定义在方法外,不是匿名类
public boolean isLocalClass() //是否是本地类,本地类定义在方法内,不是匿名类

7.类的声明信息

Class的其他方法:

public native int getModifiers()
public native Class<? super T> getSuperclass()
//对于类,为自己声明实现的所有接口,对于接口为直接扩展的接口,不包括父类继承的
public native Class<?>[] getInterfaces();
//自己声明的注解
public Annotation[] getDeclaredAnnotations()
//所有注解包括继承得到的
public Annotation[] getAnnotations()
//获取或者检查指定类型的注解
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
public boolean isAnnotationPresent(
Class<? extends Annotation> annotationClass)

8.类的加载

Class有两个静态方法,可以根据类名加载类:

public static Class<?> forName(String className) //这里的className与Class.getName()返回的值一致
public static Class<?> forName(String name, boolean initialize, ClassLoader loader) //inntialize表示加载后,是否执行类的初始化代码(如static语句块)

第一个方法相当于调用:

Class.forName(className, true, currentLoader)

9.反射与数组

对于数组类型,有一个专门的方法,可以获取它的元素类型:

public native Class<?> getComponentType()

例如:

String[] arr = new String[]{};
System.out.println(arr.getClass().getComponentType());//class java.lang.String

java.lang.reflect包中有一个针对数组的专门类Array,提供了对于数组的一些反射支持,主要方法有:

//创建指定元素类型、长度的数组
public static Object newInstance(Class<?> componentType, int length)
//创建多维数组
public static Object newInstance(Class<?> componentType, int... dimensions)
//获取数组array指定索引位置index处的值
public static native Object get(Object array, int index)
//修改数组array指定的索引位置的index处的值为value
public static native void set(Object array, int index, Object value)
//返回数组的长度
public static native int getLength(Object array)

Array也支持各种基本类型操作数组元素

public static native double getDouble(Object array, int index)
public static native void setDouble(Object array, int index, double d)
public static native void setLong(Object array, int index, long l)
public static native long getLong(Object array, int index)

10.反射与枚举

枚举类型也有一个专门的方法,可以获取所有的枚举常量:

public T[] getEnumConstants()

二、反射与泛型

我们曾经说过,泛型参数在运行时会被擦除,其实在类信息

Class中仍然有关于泛型的一些信息,可以通过反射得到。

获取类的泛型参数的Class实例方法:

public TypeVariable<Class<T>>[] getTypeParameters()

Field有如下方法:

public Type getGenericType()

Method有如下方法:

public Type getGenericReturnType()
public Type[] getGenericParameterTypes()
public Type[] getGenericExceptionTypes()

Constructor有如下方法:

public Type[] getGenericParameterTypes()

其中Type是一个接口,Class实现了Type,Type的其他子接口还有:

TypeVariable:类型参数,可以有上界,比如T extends Number

ParameterizedType :参数化类型,有原始类型和具体的类型参数比如,List

WildcardType :通配符类型,比如?、?extends Number、 ? super Integer

三、总结

不建议使用反射,理由如下:

1)没有编译器检测,容易出错

2)性能相对低下

所以,如果能用接口实现同样的灵活性,就不要使用反射。

转载于:https://www.cnblogs.com/Shadowplay/p/9986809.html

Java笔记(十九) 反射相关推荐

  1. java第十九次学习笔记

    java第十九次学习笔记 异常 java第十九次学习笔记 前言 一.try catch 二.多个异常如何处理 前言 斯人若彩虹遇上方知有 一.try catch package Demo01;impo ...

  2. Polyworks脚本开发学习笔记(十九)-将数据对象与参考对象对齐的方法

    Polyworks脚本开发学习笔记(十九)-将数据对象与参考对象对齐的方法 把开发手册理了一遍,发现还有几个点没有记录下来,其中一个就是使用点对的粗对齐和使用参考目标的精确对齐.为了把这个学习笔记凑够 ...

  3. 主成分分析碎石图_ISLR读书笔记十九:主成分分析(PCA)

    本文使用 Zhihu On VSCode 创作并发布 前面写的一些统计学习方法都是属于监督学习(supervised learning),这篇主成分分析(principal components an ...

  4. Mr.J-- jQuery学习笔记(十九)--自定义动画实现图标特效

    之前有写过自定义动画Mr.J-- jQuery学习笔记(十八)--自定义动画 这次实现一个小demo 图标特效 页面渲染 <!DOCTYPE html> <html lang=&qu ...

  5. 数据科学和人工智能技术笔记 十九、数据整理(上)

    十九.数据整理(上) 作者:Chris Albon 译者:飞龙 协议:CC BY-NC-SA 4.0 在 Pandas 中通过分组应用函数 import pandas as pd# 创建示例数据帧 d ...

  6. 【Visual C++】游戏开发笔记十九 DirectX与OpenGL的博弈

    From: http://blog.csdn.net/zhmxy555/article/details/7522960 本系列文章由zhmxy555(毛星云)编写,转载请注明出处. http://bl ...

  7. 【Visual C 】游戏开发笔记十九 DirectX与OpenGL的博弈

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本系列文 ...

  8. Java设计模式(十九):解释器设计模式

    1. 应用场景 给定一个语言后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器.客户端可以使用这个解释器来解释这个语言中的句子.(如:360读取lua脚本,这个细节的实现就是解释器模式) ...

  9. 设计模式笔记十九:备忘录模式

    原文:http://www.runoob.com/design-pattern/ 少许个人理解,如有错误请指出.欢迎一起讨论. 备忘录模式(Memento Pattern)(本文大部分摘自原文) 保存 ...

  10. javascript学习笔记(十九) 节点的操作

    包括节点的创建.添加.移除.替换.复制 本节要用到的html例子 1 <ul id="myList"> 2 <li>项目一</li> 3 < ...

最新文章

  1. Git中忽略文件权限或文件拥有者的改变
  2. 中国钢铁行业战略规划及项目建设动态分析报告2021-2027年
  3. Intellij idea 快键键
  4. c# MEF框架(四 MEF高级进阶)
  5. rhel5下的DNS服务器架设
  6. 手写数字识别项目介绍
  7. nsga2代码解读python_python自动化办公系列 | python操作pdf—— PyPDF2 和 pdfplumber模块(1)...
  8. 《用python写网络爬虫》 编写第一个网络爬虫
  9. Ansible详解(七)——Ansible palybook简单使用
  10. Python练习5-正则表达式
  11. Windows操作系统原理笔记
  12. 关于“H5小游戏源代码如何转换微信小游戏发布”
  13. 枫叶股票监控免费软件 股票基金涨幅盈亏监控 上班摸鱼炒股神器
  14. EasyDarwin EasyCamera支持海康摄像机接入了
  15. Jenkins杀掉子进程解决方法(转载)
  16. 大话设计模式6—模板方法模式(考试抄题)
  17. Unity功能——设备硬件绑定(通过设备SN码)
  18. Python 课程学习笔记(5)列表 [ ] lst
  19. 更改PPT的模板名称
  20. Qml控件之Calendar日历

热门文章

  1. 前端菜鸡入职一年后的……
  2. Shiro和SpringBoot简单集成
  3. 10月13日云栖精选夜读:【云栖大会】阿里云和红帽达成合作为百万级客户提供更多企业级解决方案...
  4. 世界级版本控制工具Vault v10.0发布,多项功能改进|附下载
  5. 关于Element学习笔记
  6. 1047. Student List for Course (25)
  7. (LeetCode 141/142)Linked List Cycle
  8. 微软职位内部推荐-Senior PM
  9. Android button 居中
  10. Android 应用程序发布流程注意事项(整理)