Java笔记(十九) 反射
反射
反射是在运行时获取类型的信息,再根据这些信息进行操作。
一、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 final
- System.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)性能相对低下
所以,如果能用接口实现同样的灵活性,就不要使用反射。
Java笔记(十九) 反射的更多相关文章
- Java笔记(十九)……多线程
概述 进程: 是一个正在执行中的程序 每一个进程执行都有一个执行顺序,该执行顺序是一个执行路径,或者叫一个控制单元 线程: 就是进程中的一个独立的控制单元,线程在控制着进程的执行 一个进程中至少有一个 ...
- python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法
python3.4学习笔记(十九) 同一台机器同时安装 python2.7 和 python3.4的解决方法 同一台机器同时安装 python2.7 和 python3.4不会冲突.安装在不同目录,然 ...
- “全栈2019”Java第九十九章:局部内部类与继承详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第二十九章:数组详解(中篇)
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- “全栈2019”Java第十九章:关系运算符、条件运算符和三元运算符
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- (C/C++学习笔记) 十九. 模板
十九. 模板 ● 模板的基本概念 模板(template) 函数模板:可以用来创建一个通用功能的函数,以支持多种不同形参,进一步简化重载函数的函数体设计. 语法: template <<模 ...
- java笔记十:java中的反射
Java中,反射是一种强大的工具.它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接.反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而 ...
- Java基础学习笔记十九 IO
File IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再 ...
- Java基础学习笔记十九 File
IO概述 回想之前写过的程序,数据都是在内存中,一旦程序运行结束,这些数据都没有了,等下次再想使用这些数据,可是已经没有了.那怎么办呢?能不能把运算完的数据都保存下来,下次程序启动的时候,再把这些数据 ...
- Java学习笔记十九:Java中的访问控制修饰符
Java中的访问控制修饰符 一:Java修饰符的种类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class Hello ...
随机推荐
- zoj3471 状态压缩dp基础
/* dp[S]表示状态S下的最大收益,0表示没有了,1表示还在 */ #include<bits/stdc++.h> using namespace std; <<],mp[ ...
- 第一周学习总结-Java
2018年7月15日 暑假第一周,我从网上找了一些讲Java的视频,学到了一些Java的基础,同时也弥补了一些之前学c/c++的知识漏洞.例如,了解到了原码反码补码和按位取反运算符(~)的运算原理. ...
- Eclipse中java文件生成jar文件的方法
在eclpse中找到你要导出的java程序 选中它 单击文件 -->export 在弹出的export对话框中找到 jar File 单击选中-->next 按图示顺序依次 选 ...
- JavaBean toString() - 将bean对象打印成字符串
JavaBean toString方式 https://www.cnblogs.com/thiaoqueen/p/7086195.html //方法一:自动生成 @Override public St ...
- C#学习-属性是对字段的扩展
属性是对字段的扩展. 根据面向对象语言的封装思想,字段最好设为private,因为这样可以防止客户端直接对字段进行篡改,从而保证了内部成员的完整性. 于是为了访问类中的私有字段,C#提供了属性这种机制 ...
- [转] webpack3最新版本配置研究(五) devtool,webpack-dev-server,CommonsChunkPlugin
devtool devtool是webpack中config自带的属性只要使用就可以了不用安装 webpack官网的解释如下 当 webpack 打包源代码时,可能会很难追踪到错误和警告在源代码中的原 ...
- [HNOI2007]梦幻岛宝珠
题解: 一道比较好的题目 首先比较显然的就是我们要按照a*2^b的b的顺序来枚举 那么状态f[i][j]表示当前在b,用了a*2^b 刚开始没想到怎么不同层之间搞 看了题解发现非常简单 由于每一层到最 ...
- C# 之 向服务器上传资源
首先写客服端,winform 应用 或者 WPF 应用 模拟一个post提交: /// <summary> /// 将本地文件上传到指定的服务器(HttpWebRequest方法) /// ...
- python全栈开发day98-DRF
1.CBV源码流程 2.restful协议 1 所有的数据,不过是通过网络获取的还是操作(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性 2 面向资源架构(RO ...
- 1000. A+B Problem
Description Calculate a+b Input Two integer a,b (0<=a,b<=10) Output Output a+b Sample Input 1 ...