版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、12.1 Java类加载机制前面我们给大家介绍过JVM的功能(提供运行时环境、垃圾回收机制和提供中立的体系结构)。在提供运行时环境中有个子功能是ClassLoader(类加载器),它主要用于将主类(即包含了main方法的类)加载到JVM的code segment(代码区)。然后运行环境找到main方法(程序入口)开始执行程序。在整个程序运行的过程中,会有更多的class被动态Load到内存中。类加载机制如图12-1所示:图12-1 类加载机制需要注意的是:类并非一次性就全部加载完毕,而是在需要的时候(运行期间)动态加载到内存。利用java -verbose:class Test可以观察类的具体
2、加载过程。12.2 Java反射机制什么是反射Java 程序在运行期间可以动态加载、解析和使用一些在编译阶段并不确定的类型数据,这一机制被称为反射(Reflection)。反射库(reflection library)提供了一个非常丰富且精心设计的工具类,以便编写能够动态操纵Java代码的程序。使用反射,在设计和运行中添加新类时,能够快速的应用开发工具动态的查询新添加类的能力。反射方式反射机制提供的功能加载运行时才能确定的数据类型解析类的结构、分析类的能力、获取其内部信息操作类(进行实例化访问非静态成员,直接利用类名访问静态成员)或其实例(访问属性、调用方法、创建新对象) Class类在程序运
3、行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,被称为Class(注意与class的区别)。通过 Class可以完整的得到一个类中的完整结构,包括此类中的方法定义,属性定义等。Class是反射的源头或入口,通过查看JDK帮助手册其常见方法如图:12.2.2 如何获取Class类对象.1 针对引用数据类型通过ClassLoader的loadClass方法Class c1 = ClassLoader.getSystemClassLoader().loadClass(com.itjob.Person);调用静态方法Class.forName()Class.forName(c
4、om.itjob.Person);Class.forName(oracle.jdbc.dirver.OracleDriver);调用Object类中定义的getClass()方法Person p = new Person();Class c1 = p.getClass();Class c2 = Hello.getClass();使用.class表达式Class c1 = String.class;Class c2 = com.itjob.Person.class;.2 针对基本数据类型及void使用.class 表达式Class c1 = int.class;Class c2 = double
5、.class;Class c3 = void.class;调用相应封装类的Type 属性Class c1 = Integer.TYPE;Class c2 = Double.TYPE;Class c3 = Void.TYPE;示例如下:try /1. 引用数据类型/1.1 利用ClassLoader类的loaderClass(类全名称);手动加载,会有异常System.out.println(ClassLoader.getSystemClassLoader().loadClass(com.itjob.Person ).getName();/1.2 利用Class.forName(类全名称);手动
6、加载,会有异常System.out.println(Class.forName(com.itjob.Person).getName();/1.3 调用Object类中定义的getClass()方法System.out.println(new Person().getClass().getName();/1.4 使用.class表达式System.out.println(Person.class.getName();/2. 基本数据类型和void/2.1 使用.class表达式System.out.println(int.class.getName();System.out.println(do
7、uble.class.getName();System.out.println(void.class.getName();/2.2 通过各自的包装类.TYPESystem.out.println(Integer.TYPE);System.out.println(Double.TYPE); catch (ClassNotFoundException e) e.printStackTrace();12.2.3 获取实例对象不光可以取得对象所在类的信息,也可以直接通过Class类的newInstance方法进行对象实例化操作。newInstance方法原型如下:public T newInstanc
8、e() throws InstantiationException,IllegalAccessException调用过程:p.getClass().newInstance();或:Person.class.newInstance();或:Class.forName(com.itjob.Person).newInstance()创建一个Person类的实例。newInstance方法调用默认的构造器初始化新创建的对象,如果这个类没有默认的构造器,就会抛出一个异常。要想调用有参构造方法,则必须使用Constructor类的newInstance方法。12.2.4 获取类的结构Class类的实例用于
9、表示运行时的Java数据类型,包括类、接口、数组、枚举、注解、基本数据类型。在类加载时,Java虚拟机会自动创建相应Class对象。通过反射得到一个类的完整结构要使用到包,此包下的常见类如下:java.lang.reflect.Constructor 获取类实现的所有接口要想取得一个类所实现的全部接口,则必须使用 Class类中的getInterfaces()方法。此方法定义如下:public Class getInterfaces()。因为一个类可以同时实现多个接口,因此此方法返回一个Class类的对象数组,之后就可以直接利用Class类中的getName()方法输出即可。示
10、例如下:interface Ainterface Bclass Person implements A, Bpublic class Test public static void main(String args) aces();for(Class cc : c)System.out.println(cc.getName(); 获取类所继承的父类一个类可以实现多个接口,但是只能继承一个父类,如果没有明确的指明继承那个类,则肯定继承的是Object类。所以要想取得一个类的父类,可以直接使用Class类中的getSuperclass()方法。此方法定义如下:public Clas
11、s getSuperclass()。此方法返回的是Class实例,和之前得到接口一样,可以通过getName()方法取得名称。 示例如下:class Aclass Person extends Apublic class Test public static void main(String args) System.out.println(Person.class.getSuperclass().getName(); 获取类中的全部构造方法可以直接使用Class类中的getConstructors()方法或getDeclaredConstructors()方法取得本类中的全部
12、构造方法。这两个方法的返回类型都是Constructor的数组。Constructor类定义在java.lang.reflect包中,常用方法如下:取得访问修饰权限的时候却发现返回的是一个int数字而不是 public等类型的修饰符关键字。这是因为在整个Java中对于方法的修饰符是使用一顶的数字表示出来的,如图所示:如果要想把这个数字还原成用户可以看懂的关键字,则必须依靠Modifier类完成,此类定义在java.lang.reflect包中。直接使用Modifier类的以下方法即可将修饰符转变:public static String toString(int mod);示例如下:impor
13、t java.lang.reflect.*;class Personprivate String name;private int age;public Person() public Person(String name, int age) = name;this.age = age;Overridepublic String toString() / TODO Auto-generated method stubreturn 我叫 + + ,我今年 + this.age;public class Test public static void mai
14、n(String args) /获取所有的构造方法Constructor cs = Person.class.getDeclaredConstructors();for(Constructor c : cs)/遍历所有的构造方法/输出构造方法的修饰符System.out.println(构造器修饰符: + Modifier.toString(c.getModifiers();/输出构造方法名称System.out.println(构造方法名: + c.getName();/输出构造方法所有参数Class ct = c.getParameterTypes();if(ct.length = 0)S
15、ystem.out.println(这是无参的构造方法);elseint i = 0;for(Class p : ct)System.out.println(参数 + (i+1) + : + p.getName();i+;现在我们已经知道如何获取一个类的所有构造方法规范,此时我们可以利用Constructor类的newInstance调用有参的构造方法来实例化对象,其过程如下:1、通过Class类中的getConstructors()方法或getDeclaredConstructors()取得本类中的全部构造方法。2、分析每个构造方法的参数情况,了解每个构造方法的原型。3、通过Class类中的
16、getDeclaredConstructor(Class. parameterTypes)方法,向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数。4、通过调用Constructor的newInstance(Object. initargs)方法实例化对象。示例如下:try Constructor c = Person.class.getDeclaredConstructor(String.class, int.class);System.out.println(c.newInstance(张三, 25); catch (IllegalArgumentException e)
17、 e.printStackTrace(); catch (InstantiationException e) e.printStackTrace(); catch (IllegalAccessException e) e.printStackTrace(); catch (InvocationTargetException e) e.printStackTrace();catch (SecurityException e1) e1.printStackTrace(); catch (NoSuchMethodException e1) e1.printStackTrace();
18、获取类中的方法要想取得一个类中的全部方法,可以使用Class类中的getDeclaredMethods()方法,此方法返回一个Method类的对象数组,如果要想进一步取得方法的具体信息,例如:方法的参数,抛出的异常声明等等内容,就必须依靠Method类来完成。输出本类中的全部方法:public Method getDeclaredMethods() throws SecurityException输出全部的方法(包括父类中的):public Method getMethods() throws SecurityException方法操作:取得全部的返回值:public Class getRet
19、urnType()取得全部的参数:public Class getParameterType()取得修饰符:public int getModifiers()取得异常信息:public Class getExceptionType()示例如下:/ 获得非继承的所有方法ods();for (Method m : methods) System.out.print(Modifier.toString(m.getModifiers() + + m.getReturnType().getName() + + m.getName() + ();Class paras = m.getParameterTy
20、pes();for (Class p : paras) System.out.print(p.getName() + );System.out.println();通过Class类的getMethod方法或getDeclaredMethod方法,根据一个类中的方法名称及参数类型取得Method对象,并通过invoke()方法调用指定的方法。invoke方法原型如下:public Object invoke(Object obj, Object. args) throws IllegalAccessException, IllegalArgumentException, InvocationTa
21、rgetException如果要调用的方法是类的静态方法,obj指定为null即可,然后后面是参数列表。如果是非静态方法,必须传入一个类的实例化对象,然后后面是参数列表。如果方法是无参方法:m.invoke(obj); /非静态m.invoke(null);/静态如果方法带参数:m.invoke(obj, 10, 20);/静态m.invoke(null, 10, 20);/非静态示例如下:Person类中的方法原型:public void fun1(int a, int b);public static void fun2(int a, String b);调用方式:/ 非静态方法调用方式m
22、ethod = Person.class.getDeclaredMethod(fun1, int.class, int.class);method.invoke(obj, 10, 20);/ 静态方法调用方式smethod = Person.class.getDeclaredMethod(fun2, int.class, String.class);smethod.invoke(null, 10, hello world java); 获取类中的属性在反射操作中也同样可以取得一个类中的全部属性,但是在取得属性的时候有以下两种不同的操作:得到本类、实现的接口和父类中的所有公共属性
23、:public Field getFields() throws SecurityException得到本类中的全部属性(包括私有属性):public Field getDeclaredFields() throws SecurityException以上方法返回的都是Field的数组,每一个Field对象就表示类中的一个属性。属性操作:取得属性修饰符:public int getModifiers()取得属性类型:public Class getType()取得属性名称:public String getName()示例如下:/ 获取类中所有的属性Field field = Person.c
24、lass.getDeclaredFields();for(Field f : field)/ 属性修饰符System.out.print(Modifier.toString(f.getModifiers() + );/ 属性类型System.out.print(f.getType().getName() + );/ 属性名称System.out.println(f.getName();setter()及getter()方法是一个标准的属性的访问方法,如果一个类的属性被封装,则必须通过setter及getter方法设置和取得属性的值。实际上此方法的操作之所以要这样规定,主要原因是由于反射机制可以
25、给予支持的。通过反射可以调用setter()及getter()方法。如果要操作一个类中的属性,则可以通过Field类来完成。而不必麻烦的通过setter()及getter()得到。取得公共属性:public Field getField(String name) throws NoSuchFieldException, SecurityException取得本类属性(包括私有):public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException取得属性内容:public Object
26、 get(Object obj) throws IllegalArgumentException,IllegalAccessException设置属性内容:public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException设置属性可见(在访问私有属性的时候,必须让这个属性可见):public void setAccessible(boolean flag) throws SecurityException示例如下:Field f = Person.class.getD
27、eclaredField(name);/name是本类中的私有属性f.setAccessible(true);/设置其可见f.set(obj, 李四);/设置属性System.out.println(f.get(obj);/取得属性与方法类似,如果类中的属性是static修饰的,则get和set方法中的obj为null即可。获取类结构信息综合实例:package reflect;import java.lang.reflect.*;import java.util.Scanner;public class ReflectTest public static void printConstruc
28、tors(Class cl)Constructor constructors = cl.getDeclaredConstructors();for(Constructor c : constructors)String name = c.getName();System.out.print( );String modifiers = Modifier.toString(c.getModifiers();if(modifiers.length() 0)System.out.print(modifiers + );System.out.print(name + ();Class paramType
29、s = c.getParameterTypes();for(int i = 0; i 0)System.out.print(, );System.out.print(paramTypesi.getName();System.out.println(););public static void printMethods(Class cl)Method methods = cl.getDeclaredMethods();for(Method m : methods)String name = m.getName();Class retType = m.getReturnType();System.
30、out.print( );String modifiers = Modifier.toString(m.getModifiers();if(modifiers.length() 0)System.out.print(modifiers + );System.out.print(retType.getName() + + name + ();Class paramTypes = m.getParameterTypes();for(int i = 0; i 0)System.out.print(, );System.out.print(paramTypesi.getName();System.ou
31、t.println(););public static void printFields(Class cl)Field fields = cl.getDeclaredFields();for(Field f : fields)Class type = f.getType();String name = f.getName();System.out.print( );String modifiers = Modifier.toString(f.getModifiers();if(modifiers.length() 0)System.out.print(modifiers + );System.
32、out.println(type.getName() + + name + ;);public static void main(String args) String name = null;if(args.length 0)name = args0;elseScanner in = new Scanner(System.in);System.out.print(Enter class name(eg:java.util.Date):);name = in.next();try Class cl = Class.forName(name);Class supercl = cl.getSupe
33、rclass();String modifiers = Modifier.toString(cl.getModifiers();if(modifiers.length() 0)System.out.print(modifiers + );System.out.print(class + name);if(supercl != null & supercl != Object.class)System.out.print( extends + supercl.getName();System.out.print(nn);printConstructors(cl);System.out.print
34、ln();printMethods(cl);System.out.println();printFields(cl);System.out.println(); catch (ClassNotFoundException e) / TODO Auto-generated catch blocke.printStackTrace();12.2.5 通过反射操作数组反射机制不光只能用在类中,也可以应用在任意的引用数据类型上。当然,这就包含了数组,数组使用 Array类完成。Class类中存在以下一个方法,用于返回一个数组对象的实例:public Class getComponentType ()接
35、下来可以利用java.lang.reflect包中的Array类的有些方法来操作:开辟新数组:public static Object newInstance(Class componentType, int. dimensions) throws IllegalArgumentException, NegativeArraySizeException得到数组指定下标的内容:public static Object get(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsExcepti
36、on修改内容:public static void set(Object array, int index, Object value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException示例如下:int arr = 1, 3, 5, 7, 9;Class c = arr.getClass().getComponentType();/ 创建新数组对象,长度为10Object newArr = Array.newInstance(c, 10);/ 利用set修改指定下标的值Array.set(newArr, 0, 10)
37、;Array.set(newArr, 1, 20);/ 利用get返回指定下标的值System.out.println(数组下标为1的元素为: + Array.get(newArr, 1);12.2.6 反射与Annotation一个Annotation要想让其变得有意义,则必须结合发射机制取得Annotation中设置的全部内容。在 Class类中存在以下几种与Annotation 操作有关的方法:实际应用ORM(实体关系映射orm 即Object-relational mapping)示例如下:package com.itjob;import java.lang.annotation.*;
38、import java.lang.reflect.Field;/ 数据库中的类型列表enum dbType varchar,number/ 该注解指明字段的名称和对应的数据类型Target(value=ElementType.FIELD)Retention(value=RetentionPolicy.RUNTIME)interface ColumnAnnotation public String columnName();/ 数据库中字段的名称public dbType dbtype();/ 数据库中字段的类型/ 该注解指明数据库中表的名称Target(value=ElementType.TY
39、PE)Retention(value=RetentionPolicy.RUNTIME)interface TableAnnotation public String tableName();/数据库中表的名称TableAnnotation(tableName=student)/ 表名称为studentclass Student / 对应表student中字段名sname,类型varcharColumnAnnotation(columnName=sname, dbtype=dbType.varchar)private String name;/ 对应表student中字段名sage,类型numb
40、erColumnAnnotation(columnName=sage, dbtype=dbType.number)private int age;public Student(String name, int age) = name;this.age = age;public String getName() return name;public void setName(String name) = name;public int getAge() return age;public void setAge(int age) this.age = age;class ORMHelp/ 把对象转换为相应的sql语句插入到数据库中public void insert(Object table)StringBuilder sb = new StringBuilder();sb.append(insert into );/ 获得对象的Class实例Cl
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025-2030绿色建筑产业市场发展现状与竞争格局评估研究报告
- 2025-2030纳米药物递送系统技术突破与市场增长潜力分析报告
- 2025-2030纳米涂层技术提升免漆门耐磨性实验报告
- 2025-2030纳米材料在新能源电池中应用前景探讨
- 2025-2030红木家具真伪鉴定技术发展与行业规范建设
- 2025-2030精酿啤酒跨界联名营销效果评估与创新方向报告
- 2025-2030精酿啤酒主题民宿业态与中国鲜啤品牌体验营销结合路径研究报告
- 2025-2030精神疾病数字疗法产品注册审批难点与市场教育策略
- 2025-2030精密传动装置技术壁垒突破与进口替代空间专项调研
- 安全知识测试题的及答案解析
- 第二单元写作《学会记事》课件-统编版语文七年级上册
- 2025至2030输配电设备发展趋势分析与未来投资战略咨询研究报告
- 2025四川成都未来医学城招聘8人考试参考题库及答案解析
- 2025届四川省南充市高三第一次诊断考-化学试题+答案
- 脊髓损伤教学课件
- 山东省名校考试联盟2026届高三上学期10月阶段性检测化学试卷(含答案)
- (南开中学)重庆市高2026届高三第二次质量检测 历史试卷(含答案详解)
- 2025云南省曲靖市公开选拔市属国有企业领导人员及市场化选聘职业经理人(10人)笔试参考题库附带答案详解
- 急性高原反应指南解读
- 冬季防冻措施安全培训课件
- 2025西南证券股份有限公司校园招聘300人笔试参考题库附带答案详解
评论
0/150
提交评论