12_Java类加载机制与反射.doc

上传人:苏美尔 文档编号:7194548 上传时间:2020-11-04 格式:DOC 页数:15 大小:400.51KB
返回 下载 相关 举报
12_Java类加载机制与反射.doc_第1页
第1页 / 共15页
12_Java类加载机制与反射.doc_第2页
第2页 / 共15页
12_Java类加载机制与反射.doc_第3页
第3页 / 共15页
12_Java类加载机制与反射.doc_第4页
第4页 / 共15页
12_Java类加载机制与反射.doc_第5页
第5页 / 共15页
点击查看更多>>
资源描述

《12_Java类加载机制与反射.doc》由会员分享,可在线阅读,更多相关《12_Java类加载机制与反射.doc(15页珍藏版)》请在三一文库上搜索。

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代码的程序。使用反射,在设计和运行中添加新类时,能够快速的应用开发工具动态的查询新添加类的能力。反射方式反射机制提供的功能加载运行时才能确定的数据类型解析类的结构、分析类的能力、获取其内部信息操作类(进行实例化访问非静态成员,直接利用类名访问静态成员)或其实例(访问属性、调用方法、创建新对象)12.2.1 Clas

3、s类在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识,被称为Class(注意与class的区别)。通过 Class可以完整的得到一个类中的完整结构,包括此类中的方法定义,属性定义等。Class是反射的源头或入口,通过查看JDK帮助手册其常见方法如图:12.2.2 如何获取Class类对象12.2.2.1 针对引用数据类型通过ClassLoader的loadClass方法Class c1 = ClassLoader.getSystemClassLoader().loadClass(com.itjob.Person);调用静态方法Class.forName()Cla

4、ss.forName(com.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;Class c3 = oracle.jdbc.dirver.OracleDriver.class;12.2.

5、2.2 针对基本数据类型及void使用.class 表达式Class c1 = int.class;Class c2 = double.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().l

6、oadClass(com.itjob.Person ).getName();/1.2 利用Class.forName(类全名称);手动加载,会有异常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 使用.c

7、lass表达式System.out.println(int.class.getName();System.out.println(double.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 获取实例对象不光可以取得对象所在类的信息,也可以直接通过

8、Class类的newInstance方法进行对象实例化操作。newInstance方法原型如下:public T newInstance() throws InstantiationException,IllegalAccessException调用过程:p.getClass().newInstance();或:Person.class.newInstance();或:Class.forName(com.itjob.Person).newInstance()创建一个Person类的实例。newInstance方法调用默认的构造器初始化新创建的对象,如果这个类没有默认的构造器,就会抛出一个异常。

9、要想调用有参构造方法,则必须使用Constructor类的newInstance方法。12.2.4 获取类的结构Class类的实例用于表示运行时的Java数据类型,包括类、接口、数组、枚举、注解、基本数据类型。在类加载时,Java虚拟机会自动创建相应Class对象。通过反射得到一个类的完整结构要使用到java.lang.reflect包,此包下的常见类如下:java.lang.reflect.Fieldjava.lang.reflect.Methodjava.lang.reflect.Constructorjava.lang.reflect.Modifierjava.lang.reflect.

10、Array12.2.4.1 获取类实现的所有接口要想取得一个类所实现的全部接口,则必须使用 Class类中的getInterfaces()方法。此方法定义如下:public Class getInterfaces()。因为一个类可以同时实现多个接口,因此此方法返回一个Class类的对象数组,之后就可以直接利用Class类中的getName()方法输出即可。示例如下:interface Ainterface Bclass Person implements A, Bpublic class Test public static void main(String args) Class c = P

11、erson.class.getInterfaces();for(Class cc : c)System.out.println(cc.getName();12.2.4.2 获取类所继承的父类一个类可以实现多个接口,但是只能继承一个父类,如果没有明确的指明继承那个类,则肯定继承的是Object类。所以要想取得一个类的父类,可以直接使用Class类中的getSuperclass()方法。此方法定义如下:public Class getSuperclass()。此方法返回的是Class实例,和之前得到接口一样,可以通过getName()方法取得名称。 示例如下:class Aclass Person

12、 extends Apublic class Test public static void main(String args) System.out.println(Person.class.getSuperclass().getName();12.2.4.3 获取类中的全部构造方法可以直接使用Class类中的getConstructors()方法或getDeclaredConstructors()方法取得本类中的全部构造方法。这两个方法的返回类型都是Constructor的数组。Constructor类定义在java.lang.reflect包中,常用方法如下:取得访问修饰权限的时候却发现

13、返回的是一个int数字而不是 public等类型的修饰符关键字。这是因为在整个Java中对于方法的修饰符是使用一顶的数字表示出来的,如图所示:如果要想把这个数字还原成用户可以看懂的关键字,则必须依靠Modifier类完成,此类定义在java.lang.reflect包中。直接使用Modifier类的以下方法即可将修饰符转变:public static String toString(int mod);示例如下:import java.lang.reflect.*;class Personprivate String name;private int age;public Person() pu

14、blic Person(String name, int age) this.name = name;this.age = age;Overridepublic String toString() / TODO Auto-generated method stubreturn 我叫 + this.name + ,我今年 + this.age;public class Test public static void main(String args) /获取所有的构造方法Constructor cs = Person.class.getDeclaredConstructors();for(Con

15、structor c : cs)/遍历所有的构造方法/输出构造方法的修饰符System.out.println(构造器修饰符: + Modifier.toString(c.getModifiers();/输出构造方法名称System.out.println(构造方法名: + c.getName();/输出构造方法所有参数Class ct = c.getParameterTypes();if(ct.length = 0)System.out.println(这是无参的构造方法);elseint i = 0;for(Class p : ct)System.out.println(参数 + (i+1

16、) + : + p.getName();i+;现在我们已经知道如何获取一个类的所有构造方法规范,此时我们可以利用Constructor类的newInstance调用有参的构造方法来实例化对象,其过程如下:1、通过Class类中的getConstructors()方法或getDeclaredConstructors()取得本类中的全部构造方法。2、分析每个构造方法的参数情况,了解每个构造方法的原型。3、通过Class类中的getDeclaredConstructor(Class. parameterTypes)方法,向构造方法中传递一个对象数组进去,里面包含了构造方法中所需的各个参数。4、通过调

17、用Constructor的newInstance(Object. initargs)方法实例化对象。示例如下:try Constructor c = Person.class.getDeclaredConstructor(String.class, int.class);System.out.println(c.newInstance(张三, 25); catch (IllegalArgumentException e) e.printStackTrace(); catch (InstantiationException e) e.printStackTrace(); catch (Illeg

18、alAccessException e) e.printStackTrace(); catch (InvocationTargetException e) e.printStackTrace();catch (SecurityException e1) e1.printStackTrace(); catch (NoSuchMethodException e1) e1.printStackTrace();12.2.4.4 获取类中的方法要想取得一个类中的全部方法,可以使用Class类中的getDeclaredMethods()方法,此方法返回一个Method类的对象数组,如果要想进一步取得方法的

19、具体信息,例如:方法的参数,抛出的异常声明等等内容,就必须依靠Method类来完成。输出本类中的全部方法:public Method getDeclaredMethods() throws SecurityException输出全部的方法(包括父类中的):public Method getMethods() throws SecurityException方法操作:取得全部的返回值:public Class getReturnType()取得全部的参数:public Class getParameterType()取得修饰符:public int getModifiers()取得异常信息:pu

20、blic Class getExceptionType()示例如下:/ 获得非继承的所有方法Method methods = Person.class.getDeclaredMethods();for (Method m : methods) System.out.print(Modifier.toString(m.getModifiers() + + m.getReturnType().getName() + + m.getName() + ();Class paras = m.getParameterTypes();for (Class p : paras) System.out.prin

21、t(p.getName() + );System.out.println();通过Class类的getMethod方法或getDeclaredMethod方法,根据一个类中的方法名称及参数类型取得Method对象,并通过invoke()方法调用指定的方法。invoke方法原型如下:public Object invoke(Object obj, Object. args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException如果要调用的方法是类的静态方法,obj指定为null即可,然

22、后后面是参数列表。如果是非静态方法,必须传入一个类的实例化对象,然后后面是参数列表。如果方法是无参方法: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);调用方式:/ 非静态方法调用方式method = Person.class.getDeclaredMethod(fun1

23、, 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);12.2.4.5 获取类中的属性在反射操作中也同样可以取得一个类中的全部属性,但是在取得属性的时候有以下两种不同的操作:得到本类、实现的接口和父类中的所有公共属性:public Field getFields() throws SecurityEx

24、ception得到本类中的全部属性(包括私有属性):public Field getDeclaredFields() throws SecurityException以上方法返回的都是Field的数组,每一个Field对象就表示类中的一个属性。属性操作:取得属性修饰符:public int getModifiers()取得属性类型:public Class getType()取得属性名称:public String getName()示例如下:/ 获取类中所有的属性Field field = Person.class.getDeclaredFields();for(Field f : fiel

25、d)/ 属性修饰符System.out.print(Modifier.toString(f.getModifiers() + );/ 属性类型System.out.print(f.getType().getName() + );/ 属性名称System.out.println(f.getName();setter()及getter()方法是一个标准的属性的访问方法,如果一个类的属性被封装,则必须通过setter及getter方法设置和取得属性的值。实际上此方法的操作之所以要这样规定,主要原因是由于反射机制可以给予支持的。通过反射可以调用setter()及getter()方法。如果要操作一个类中

26、的属性,则可以通过Field类来完成。而不必麻烦的通过setter()及getter()得到。取得公共属性:public Field getField(String name) throws NoSuchFieldException, SecurityException取得本类属性(包括私有):public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException取得属性内容:public Object get(Object obj) throws IllegalArgumentExce

27、ption,IllegalAccessException设置属性内容:public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException设置属性可见(在访问私有属性的时候,必须让这个属性可见):public void setAccessible(boolean flag) throws SecurityException示例如下:Field f = Person.class.getDeclaredField(name);/name是本类中的私有属性f.setAcces

28、sible(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 printConstructors(Class cl)Constructor constructors = cl

29、.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 paramTypes = c.getParameterTypes();for(int i = 0; i

30、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.out.print( );String modifiers = Modifier.to

31、String(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.out.println(););public static void printField

32、s(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.out.println(type.getName() + + name + ;);pu

33、blic 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.getSuperclass();String modifiers = Modifier.toStri

34、ng(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.println();printMethods(cl);System.out.println();

35、printFields(cl);System.out.println(); catch (ClassNotFoundException e) / TODO Auto-generated catch blocke.printStackTrace();12.2.5 通过反射操作数组反射机制不光只能用在类中,也可以应用在任意的引用数据类型上。当然,这就包含了数组,数组使用 Array类完成。Class类中存在以下一个方法,用于返回一个数组对象的实例:public Class getComponentType ()接下来可以利用java.lang.reflect包中的Array类的有些方法来操作:开辟

36、新数组:public static Object newInstance(Class componentType, int. dimensions) throws IllegalArgumentException, NegativeArraySizeException得到数组指定下标的内容:public static Object get(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException修改内容:public static void set(Object array,

37、 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);Array.set(newArr, 1, 20);/ 利用get返回指定下标的值Sy

38、stem.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.*;import java.lang.reflect.Field;/ 数据库中的类型列表e

39、num dbType varchar,number/ 该注解指明字段的名称和对应的数据类型Target(value=ElementType.FIELD)Retention(value=RetentionPolicy.RUNTIME)interface ColumnAnnotation public String columnName();/ 数据库中字段的名称public dbType dbtype();/ 数据库中字段的类型/ 该注解指明数据库中表的名称Target(value=ElementType.TYPE)Retention(value=RetentionPolicy.RUNTIME)

40、interface TableAnnotation public String tableName();/数据库中表的名称TableAnnotation(tableName=student)/ 表名称为studentclass Student / 对应表student中字段名sname,类型varcharColumnAnnotation(columnName=sname, dbtype=dbType.varchar)private String name;/ 对应表student中字段名sage,类型numberColumnAnnotation(columnName=sage, dbtype=

41、dbType.number)private int age;public Student(String name, int age) this.name = name;this.age = age;public String getName() return name;public void setName(String name) this.name = name;public int getAge() return age;public void setAge(int age) this.age = age;class ORMHelp/ 把对象转换为相应的sql语句插入到数据库中publi

42、c void insert(Object table)StringBuilder sb = new StringBuilder();sb.append(insert into );/ 获得对象的Class实例Class c = table.getClass();/ 获取类的注释TableAnnotation annotation = c.getAnnotation(TableAnnotation.class);/ 获取类的注解的指定字段的值String tablename = annotation.tableName();sb.append(tablename);sb.append();/ 获

43、得所有属性字段Field fields = c.getDeclaredFields();int len = fields.length;/ 保存列名称的数组String columnname = new Stringlen;/ 保存对应列的数据类型的数组dbType columntype = new dbTypelen;/ 保存对应列插入的值的数组String columnvalue = new Stringlen;for (int i = 0; i len; i+) / 获得每个属性的ColumnAnnotation注解ColumnAnnotation cannotation = fieldsi.getAnnotation(ColumnAnnotation.class);/

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 科普知识


经营许可证编号:宁ICP备18001539号-1