12_Java类加载机制与反射_第1页
12_Java类加载机制与反射_第2页
12_Java类加载机制与反射_第3页
12_Java类加载机制与反射_第4页
12_Java类加载机制与反射_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

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

3、调用方法、创建新对象)12.2.1 Class类在程序运行期间,Java运行时系统始终为全部的对象维护一个被称为运行时的类型标识,被称为Class(留意与class的区分)。通过 Class可以完整的得到一个类中的完整结构,包括此类中的方法定义,属性定义等。Class是反射的源头或入口,通过查看JDK挂念手册其常见方法如图:12.2.2 如何猎取Class类对象 针对引用数据类型·通过ClassLoader的loadClass方法Class c1 = ClassLoader.getSystemClassLoader().loadClass("com.itjo

4、b.Person");·调用静态方法Class.forName()Class.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.

5、class;Class c2 = com.itjob.Person.class;Class c3 = oracle.jdbc.dirver.OracleDriver.class; 针对基本数据类型及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. 引用

6、数据类型/1.1 利用ClassLoader类的loaderClass("类全名称");手动加载,会有特别System.out.println(ClassLoader.getSystemClassLoader().loadClass("com.itjob.Person" ).getName();/1.2 利用Class.forName(类全名称);手动加载,会有特别System.out.println(Class.forName("com.itjob.Person").getName();/1.3 调用Object类中定义的getCl

7、ass()方法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(double.class.getName();System.out.println(void.class.getName();/2.2 通过各自的包装类.TYPESystem.out.p

8、rintln(Integer.TYPE);System.out.println(Double.TYPE); catch (ClassNotFoundException e) e.printStackTrace();12.2.3 猎取实例对象不光可以取得对象所在类的信息,也可以直接通过Class类的newInstance方法进行对象实例化操作。newInstance方法原型如下:public T newInstance() throws InstantiationException,IllegalAccessException调用过程:p.getClass().newInstance();或:P

9、erson.class.newInstance();或:Class.forName("com.itjob.Person").newInstance()创建一个Person类的实例。newInstance方法调用默认的构造器初始化新创建的对象,假如这个类没有默认的构造器,就会抛出一个特别。要想调用有参构造方法,则必需使用Constructor类的newInstance方法。12.2.4 猎取类的结构Class类的实例用于表示运行时的Java数据类型,包括类、接口、数组、枚举、注解、基本数据类型。在类加载时,Java虚拟机会自动创建相应Class对象。通过反射得到一个类的完整结

10、构要使用到java.lang.reflect包,此包下的常见类如下:java.lang.reflect.Fieldjava.lang.reflect.Methodjava.lang.reflect.Constructor<T>java.lang.reflect.Modifierjava.lang.reflect.Array 猎取类实现的全部接口要想取得一个类所实现的全部接口,则必需使用 Class类中的getInterfaces()方法。此方法定义如下:public Class getInterfaces()。由于一个类可以同时实现多个接口,因此此方法返回一个Cla

11、ss类的对象数组,之后就可以直接利用Class类中的getName()方法输出即可。示例如下:interface Ainterface Bclass Person implements A, Bpublic class Test public static void main(String args) Class c = Person.class.getInterfaces();for(Class cc : c)System.out.println(cc.getName(); 猎取类所继承的父类一个类可以实现多个接口,但是只能继承一个父类,假如没有明确的指明继承那个类,则确定继

12、承的是Object类。所以要想取得一个类的父类,可以直接使用Class类中的getSuperclass()方法。此方法定义如下:public Class<? super T> getSuperclass()。此方法返回的是Class实例,和之前得到接口一样,可以通过getName()方法取得名称。 示例如下:class Aclass Person extends Apublic class Test public static void main(String args) System.out.println(Person.class.getSuperclass().getName

13、(); 猎取类中的全部构造方法可以直接使用Class类中的getConstructors()方法或getDeclaredConstructors()方法取得本类中的全部构造方法。这两个方法的返回类型都是Constructor的数组。Constructor类定义在java.lang.reflect包中,常用方法如下:取得访问修饰权限的时候却发觉返回的是一个int数字而不是 public等类型的修饰符关键字。这是由于在整个Java中对于方法的修饰符是使用一顶的数字表示出来的,如图所示:假如要想把这个数字还原成用户可以看懂的关键字,则必需依靠Modifier类完成,此类定义在java

14、.lang.reflect包中。直接使用Modifier类的以下方法即可将修饰符转变:public static String toString(int mod);示例如下:import 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

15、 method stubreturn "我叫" + + ",我今年" + this.age;public class Test public static void main(String args) /猎取全部的构造方法Constructor<?> cs = Person.class.getDeclaredConstructors();for(Constructor<?> c : cs)/遍历全部的构造方法/输出构造方法的修饰符System.out.println("构造器修饰符:" +

16、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) + ":&

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

18、个参数。4、通过调用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.p

19、rintStackTrace(); catch (IllegalAccessException e) e.printStackTrace(); catch (InvocationTargetException e) e.printStackTrace();catch (SecurityException e1) e1.printStackTrace(); catch (NoSuchMethodException e1) e1.printStackTrace(); 猎取类中的方法要想取得一个类中的全部方法,可以使用Class类中的getDeclaredMethods()方法,此方

20、法返回一个Method类的对象数组,假如要想进一步取得方法的具体信息,例如:方法的参数,抛出的特别声明等等内容,就必需依靠Method类来完成。输出本类中的全部方法:public Method getDeclaredMethods() throws SecurityException输出全部的方法(包括父类中的):public Method getMethods() throws SecurityException方法操作:取得全部的返回值:public Class<?> getReturnType()取得全部的参数:public Class<?> getParamet

21、erType()取得修饰符:public int getModifiers()取得特别信息:public Class<?> getExceptionType()示例如下:/ 获得非继承的全部方法Method methods = Person.class.getDeclaredMethods();for (Method m : methods) System.out.print(Modifier.toString(m.getModifiers() + " "+ m.getReturnType().getName() + " " + m.getN

22、ame() + "(");Class<?> paras = m.getParameterTypes();for (Class<?> p : paras) System.out.print(p.getName() + " ");System.out.println(")");通过Class类的getMethod方法或getDeclaredMethod方法,依据一个类中的方法名称及参数类型取得Method对象,并通过invoke()方法调用指定的方法。invoke方法原型如下:public Object invok

23、e(Object obj, Object. args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException·假如要调用的方法是类的静态方法,obj指定为null即可,然后后面是参数列表。·假如是非静态方法,必需传入一个类的实例化对象,然后后面是参数列表。假如方法是无参方法:m.invoke(obj); /非静态m.invoke(null);/静态假如方法带参数:m.invoke(obj, 10, 20);/静态m.invoke(null, 10, 20);/非静

24、态示例如下:Person类中的方法原型:public void fun1(int a, int b);public static void fun2(int a, String b);调用方式:/ 非静态方法调用方式method = Person.class.getDeclaredMethod("fun1", int.class, int.class);method.invoke(obj, 10, 20);/ 静态方法调用方式smethod = Person.class.getDeclaredMethod("fun2", int.class, Strin

25、g.class);smethod.invoke(null, 10, "hello world java"); 猎取类中的属性在反射操作中也同样可以取得一个类中的全部属性,但是在取得属性的时候有以下两种不同的操作:得到本类、实现的接口和父类中的全部公共属性:public Field getFields() throws SecurityException得到本类中的全部属性(包括私有属性):public Field getDeclaredFields() throws SecurityException以上方法返回的都是Field的数组,每一个Field对象就

26、表示类中的一个属性。属性操作:取得属性修饰符:public int getModifiers()取得属性类型:public Class<?> getType()取得属性名称:public String getName()示例如下:/ 猎取类中全部的属性Field field = Person.class.getDeclaredFields();for(Field f : field)/ 属性修饰符System.out.print(Modifier.toString(f.getModifiers() + " ");/ 属性类型System.out.print(f.

27、getType().getName() + " ");/ 属性名称System.out.println(f.getName();setter()及getter()方法是一个标准的属性的访问方法,假如一个类的属性被封装,则必需通过setter及getter方法设置和取得属性的值。实际上此方法的操作之所以要这样规定,主要缘由是由于反射机制可以赐予支持的。通过反射可以调用setter()及getter()方法。假如要操作一个类中的属性,则可以通过Field类来完成。而不必麻烦的通过setter()及getter()得到。取得公共属性:public Field getField(S

28、tring name) throws NoSuchFieldException, SecurityException取得本类属性(包括私有):public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException取得属性内容:public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException设置属性内容:public void set(Object obj, Object value)

29、throws IllegalArgumentException, IllegalAccessException设置属性可见(在访问私有属性的时候,必需让这个属性可见):public void setAccessible(boolean flag) throws SecurityException示例如下:Field f = Person.class.getDeclaredField("name");/name是本类中的私有属性f.setAccessible(true);/设置其可见f.set(obj, "李四");/设置属性System.out.prin

30、tln(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.getDeclaredConstructors();for(Cons

31、tructor<?> 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.getParameter

32、Types();for(int i = 0; i < paramTypes.length; i+)if(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

33、.getName();Class<?> retType = m.getReturnType();System.out.print(" ");String modifiers = Modifier.toString(m.getModifiers();if(modifiers.length() > 0)System.out.print(modifiers + " ");System.out.print(retType.getName() + " " + name + "(");Class<?&g

34、t; paramTypes = m.getParameterTypes();for(int i = 0; i < paramTypes.length; i+)if(i > 0)System.out.print(", ");System.out.print(paramTypesi.getName();System.out.println(");");public static void printFields(Class<?> cl)Field fields = cl.getDeclaredFields();for(Field f

35、: 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 + "")

36、;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.getSuperclas

37、s();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.

38、print("nn");printConstructors(cl);System.out.println();printMethods(cl);System.out.println();printFields(cl);System.out.println(""); catch (ClassNotFoundException e) / TODO Auto-generated catch blocke.printStackTrace();12.2.5 通过反射操作数组反射机制不光只能用在类中,也可以应用在任意的引用数据类型上。当然,这就包含了数组,数组使用

39、Array类完成。Class类中存在以下一个方法,用于返回一个数组对象的实例:public Class<?> getComponentType ()接下来可以利用java.lang.reflect包中的Array类的有些方法来操作:开拓新数组:public static Object newInstance(Class<?> componentType, int. dimensions) throws IllegalArgumentException, NegativeArraySizeException得到数组指定下标的内容:public static Object

40、get(Object array, int index) throws IllegalArgumentException, ArrayIndexOutOfBoundsException修改内容:public static void set(Object array, int index, Object value) throws IllegalArgumentException, ArrayIndexOutOfBoundsException示例如下:int arr = 1, 3, 5, 7, 9;Class<?> c = arr.getClass().getComponentTyp

41、e();/ 创建新数组对象,长度为10Object newArr = Array.newInstance(c, 10);/ 利用set修改指定下标的值Array.set(newArr, 0, 10);Array.set(newArr, 1, 20);/ 利用get返回指定下标的值System.out.println("数组下标为1的元素为:" + Array.get(newArr, 1);12.2.6 反射与Annotation一个Annotation要想让其变得有意义,则必需结合放射机制取得Annotation中设置的全部内容。在 Class类中存在以下几种与Annota

42、tion 操作有关的方法:实际应用ORM(实体关系映射orm 即Object-relational mapping)示例如下:package com.itjob;import java.lang.annotation.*;import java.lang.reflect.Field;/ 数据库中的类型列表enum dbType varchar,number/ 该注解指明字段的名称和对应的数据类型Target(value=ElementType.FIELD)Retention(value=RetentionPolicy.RUNTIME)interface ColumnAnnotation pub

43、lic String columnName();/ 数据库中字段的名称public dbType dbtype();/ 数据库中字段的类型/ 该注解指明数据库中表的名称Target(value=ElementType.TYPE)Retention(value=RetentionPolicy.RUNTIME)interface TableAnnotation public String tableName();/数据库中表的名称TableAnnotation(tableName="student")/ 表名称为studentclass Student / 对应表student

44、中字段名sname,类型varcharColumnAnnotation(columnName="sname", dbtype=dbType.varchar)private String name;/ 对应表student中字段名sage,类型numberColumnAnnotation(columnName="sage", dbtype=dbType.number)private int age;public Student(String name, int age) = name;this.age = age;public Stri

45、ng 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实例Cla

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论