简介Java反射基础
【参考资料: 疯狂Java讲义 Chapter 18】
1、类加载、连接、初始化
当Java程序需要某一个类时,如果该类尚未加载到内存中,系统会通过加载、连接、初始化三个步骤将该类加载到内存,并完成初始化工作。
- 类加载:将类的class文件加载到内存,并为之创建一个java.lang.Class对象。类的加载是通过类加载器,类加载器由JVM提供,统称为系统类加载器。除了利用JVM提供的类加载器,我们还可通过继承java.lang.ClassLoader来编写自己的类加载器。一旦一个类被载入JVM,同一个类(用类的全限定名和类的类加载器作为唯一标识)就不会被重复载入了。
- 类连接:将类的二进制数据合并到JRE中。
- 类初始化:JVM对类进行初始化,主要是针对静态属性进行初始化。
2、类加载器
JVM启动时,会形成由三个类加载器类组成的初始类的加载器层次结构:
- 根类加载器(Bootstrap classLoader):负责加载Java的核心类。根类加载器是由JVM自身实现的,并非ClassLoader的子类。
- 扩展类加载器(Extension ClassLoader):负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs属性所指定的目录)中JAR的类包。
- 系统类加载器(System ClassLoader):在JVM启动时,负责加载来自命令java中的-classpath或java.class.path系统属性或CLASSPATH环境变量所指定的JAR包和类路径。程序中可通过ClassLoader.getSystemClassLoader()获取该类加载器。
三个类加载器之间的层次关系:
3、通过反射操作类
1)获取java.lang.Class对象的常用方式
- Class类的静态方法forName(String className)。其中传入的className参数为类的全限定名。
- 调用类的class属性来获取该类的Class对象。如Class strClass = String.class。
- 调用对象的getClass()方法。
2)Class类提供的接口
获取Class对象所对应类的构造器的接口:
Constructor<T> getConstructor(Class<?>... parameterTypes) //返回对应该类的public的构造器,构造器参数列表的类型声明次序符合parameterTypes类型声明次序,被封装成了Constructor对象
Constructor<?>[] getConstructors() //获取所有public构造器
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //返回对应parameterTypes类型声明次序的该类的构造器,与访问级别无关
Constructor<?>[] getDeclaredConstructors()//返回所有的构造器,与访问级别无关 5 Constructor<?> getEnclosingConstructor() //用于匿名类或内部类
获取Class对象对应类的方法的接口:
Method getMethod(String name, Class<?>... parameterTypes); //返回由方法名name和参数列表类型parameterTypes限定的public方法
Method[] getMethods(); //所有public方法
Method getDeclaredMethod(String name, Class<?>... parameterTypes); //返回由方法名和参数列表类型parameterTypes限定的方法,与访问级别无关
Method[] getDeclaredMethods(); //所有方法 5 Method getEnclosingMethod(); //用于获取内部类或匿名类的方法
获取Class对象对应类所包含的属性的接口:
Field getField(String name); //返回对应name的public 属性
Field[] getFields(); //所有public属性
Field getDeclaredField(String name);
Field[] getDeclaredFields();
【注:方法名中带有Declared的方法返回的构造器、方法或属性等都是忽略访问级别的;而不带有Declared的方法返回public的类成员。】
访问Class对应类的注释的接口:
<A extends Annotation> A getAnnotation(Class<A> annotationClass); //返回符合特定注解类型annotationClass的注解
Annotation[] getAnnotations(); //当前Class的所有注解
Annotation[] getDeclaredAnnotations(); //直接出现在当前元素上的注解
Class中用于判断该Class是否为注释类型、数组类型、接口类型的接口:
boolean isAnnotation();
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); //判断是否出现了特定类型的注解
boolean isAnonymousClass();
boolean isArray();
boolean isEnum();
boolean isInstance(Object obj); //判断obj类型是否与当前Class对应的类型兼容
boolean isInterface();
boolean isLocalClass();
boolean isPrimitive();
其他接口:
String getName();//返回该Class代表的类或接口的全称
String getPackage(); //返回包名
String getSimpleName(); //Class对应类的简称
Class<? super T> getSuperclass(); //返回超类
对于上述接口中出现的Class<?>... parameterTypes,是指定的参数列表的Class对象。如:
public class ReflectionTest{ private int privateAttribute = -1;
public int publicAttribute = -2; public String publicStrAttribute = "DefaultString"; public void info(){
System.out.println("This is info() of class ReflectionTest");
} public void info(String str){
System.out.println("This is info(String) of class ReflectionTest");
} public void info(String str, Integer num){
System.out.println("This is info(String, Integer) of class ReflectionTest");
} private void privateInfo(){
System.out.println("This is privateInfo method");
} public static void main(String[] args) throws Exception{
Class<ReflectionTest> testClass = ReflectionTest.class; Method info1 = testClass.getMethod("info", null);
System.out.println("方法参数列表长度: "+info1.getParameterTypes().length); Method info2 = testClass.getMethod("info", String.class);
System.out.println("方法参数列表长度: "+info2.getParameterTypes().length); Method info3 = testClass.getMethod("info", String.class, Integer.class);
System.out.println("方法参数列表长度: "+info3.getParameterTypes().length);
}
}
3)通过反射生成并操作对象
- 通过Class对象的newInstance方法
- 通过Class对象获取对应类的Constructor,再通过Constructor对象的newInstance方法
Class<ReflectionTest> testClass = ReflectionTest.class; //通过Class对象构造Class对应类的实例
ReflectionTest rt1 = testClass.newInstance();
Constructor constructor = testClass.getConstructor(null);
ReflectionTest rt2 = (ReflectionTest)constructor.newInstance(null); //调用默认构造函数,参数列表为空
【注:代码基于ReflectionTest类】
4)调用方法
- public方法,直接通过Method对象的Object invoke(Object obj,Object... args)方法;其中obj为调用该方法的Class对应类的实例,args为方法的参数。
Object newTest = constructor.newInstance(null);
Method info = testClass.getMethod("info", null);
info.invoke(newTest, null);
- private方法,首先要调用Method类的setAccessible(boolean flag)方法,否则报错:java.lang.NoSuchMethodException
然后调用private方法:
Method privateMethod = testClass.getDeclaredMethod("privateInfo", null); //获取private方法使用getDeclaredMethod方法
privateMethod.setAccessible(true);
privateMethod.invoke(newTest, null);
5)操作属性值
- 操作8个基本类型时,使用Field的getXXX(Object obj)或setXXX(Object obj, XXX value),其中obj为被访问的Class对应的类。
- 操作引用类型时,使用Field的get(Object obj)或set(Object obj, Object value)
//操作属性
Field privateField = testClass.getDeclaredField("privateAttribute"); //私有属性
System.out.println(privateField.getInt(newTest));
privateField.setInt(newTest, -1000);
System.out.println(privateField.get(newTest)); Field strField = testClass.getField("publicStrAttribute"); //公有属性
System.out.println(strField.get(newTest));
strField.set(newTest, "test value");
System.out.println(strField.get(newTest));
6)操作数组
java.lang.reflect包下含有Array类,Array类提供了可以动态创建和访问Java数组的静态方法。
主要接口:
static static Object newInstance(Class<?> componentType, int... dimensions); //多维度的数组
static Object newInstance(Class<?> componentType, int length); //指定数组长度的数组 static XXX getXXX(Object array, int index); //对于8中基本类型
static void setXXX(Object array, int index, XXX newValue); static Object get(Object array, int index); //对于引用类型
static void setXXX(Object array, int index, Object newValue);
简介Java反射基础的更多相关文章
- java反射基础知识(四)反射应用实践
反射基础 p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没有接触过的话,建议先看一下官方文档的Quick Start. 在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的 ...
- java反射基础知识(一)
一.反射 反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...
- java反射(基础了解)
package cn.itcast_01; /** *Person类 */ public class Person { /** 姓名 */ private String name; ...
- 深入解析Java反射基础
博客原文:http://www.sczyh30.com/posts/Java/java-reflection-1/ - 这老哥写的特别好 一.回顾:什么是反射? 反射(Reflection)是Java ...
- Java 反射基础
1.反射概念: Java运行时,动态获得类的信息以及动态调用对象的方法的功能. 在运行时判断任意一个对象所属的类 在运行时构造任意一个类的对象 在运行时判断任意一个类所具有的成员变量和方法 在运行时调 ...
- java反射基础知识(五)反射应用实践
详解Java反射各种应用 Java除了给我们提供在编译期得到类的各种信息之外,还通过反射让我们可以在运行期间得到类的各种信息.通过反射获取类的信息,得到类的信息之后,就可以获取以下相关内容: Cl ...
- java反射基础知识(三)
原文地址:http://tutorials.jenkov.com/java-reflection/index.html http://www.cnblogs.com/penghongwei/p/329 ...
- java反射基础知识(二)
1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以让我们在运行时获取类的函数.属性.父类.接口等 Class 内部信息的机制.通过反射还可以让我们在运行期实例化对象 ...
- 5、java反射基础
Class对象: Class对象记录了所有与类相关的信息,当类加载器从文件系统中加载.class文件到JVM中的同时会为每一个类创建一个Class对象.通过Class对象可以获取到类的属性.方法.构造 ...
随机推荐
- <Error>: CGContextRestoreGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
转自这里 出 错原因:设置app的状态栏样式的使用使用了旧的方式,在info.plist里面设置了View controller- based status bar appearance为NO,默 ...
- int/double/string使用
在计算机中存储数据和儿童在抽屉中存放物品很类似. 例如: 要在计算机中存一个数字50,需要两句话. int a; //将要放的物品告诉家长 a=50; //将物品放到某个抽屉中 计算机存储变量的过 ...
- 控制GridView中字段的长度,规范数据
前台: <asp:GridView ID="GridView1" runat="server" OnRowDataBound="GridVi ...
- java SimpleDateFormat非线程安全测试
public class MyThread extends Thread { private SimpleDateFormat sdf; private String dateString; publ ...
- META 标签的使用
<meta />标记详解 说明: meta是一个单边标签 ,主要功能:是用于设置或显示一些控制信息,告诉浏览器以什么编码显示. <meta>标记有两个主要的属性: http-e ...
- CSS 绝对定位和相对定位
CSS定位属性:一个定位属性,需配合四个定位坐标,实现定位 固定定位fixed 说明: 1.固定定位是相对于"浏览器窗口" 2.如果只设置了定位属性,未指定定位坐标时,元素将停留在 ...
- Contest1065 - 第四届“图灵杯”NEUQ-ACM程序设计竞赛(个人赛)E粉丝与分割平面
题目描述 在一个平面上使用一条直线最多可以将一个平面分割成两个平面,而使用两条直线最多可将平面分割成四份,使用三条直线可将平面分割成七份--这是个经典的平面分割问题,但是too simple,作为一个 ...
- InnoDB 离线转储工具
一,应用场景; 1,表空间严重损坏,无法恢复;2,数据库表空间文件丢失后从磁盘上打捞出部分数据页面;3,恢复删除记录; 二,功能; 从数据页中直接转储出文本格式的行数据,从而可以后期用 LOAD DA ...
- C语言中格式化输出的转换说明的fldwidth和precision解析
首先说什么是C语言的格式化输出,就是printf和它的几个变种(grep -E "v?(sn|s|f)printf").像这些函数都有一个参数format,format中可以加点转 ...
- ASP.NET的WebFrom组件LinkButton使用
在ASP.NET的WebForm组件中的LinkButton组件也是一个服务器端的组件,这个组件有点类似于HTML中的<A>标识符.它的主要作用是就是在ASP.NET页面中显示一个超链接. ...