java_web初学笔记之<java的反射机制>

来源:互联网 发布:mac maven 环境变量 编辑:程序博客网 时间:2024/06/07 09:48

首先明确java类中有什么信息?

①构造方法(构造器)Constructor

②属性(也成为字段)Field

③方法 Method

④包名

⑤修饰符...等信息

①②③这几个每一个都有public和非public之分。

Class类代表java类,一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这个一个个的空间可分别用一个个的对象来表示。

Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件即字节码文件(.class文件)从硬盘读取到内存中。类装载方式有两种:①隐式装载,程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。②显示装载,通过class.forname()等方法,显式加载需要的类(这就是反射里要用到的)。类装载完以后需要解析字节码文件,解析完以后,JVM中都有一个对应的java.lang.Class对象,提供了类结构信息的描述,此时才能操作所有的信息。数组,枚举及基本数据类型,甚至void都拥有对应的Class对象。Class类没有public的构造方法,Class对象是在装载类时由JVM通过调用类装载器中的defineClass()方法自动构造的。

具体看下面的图:


接着来了解一下反射,那么何为反射呢?

JAVA反射机制是在运行状态中,对于任意一个,都能够知道这个类的所有属性和方法(包括构造方法);对于任意一个对象,都能够调用它的任意一个方法和属性(不管public或者非public);这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

☆☆☆反射就是把Java类中的各种成分映射成一个个的java对象,反射就像解剖,把一个类中的所有成分都映射为一个个的对象,直接可以操作它们。


—————————————————————————————————————————————————————————

—————————————————————————————————————————————————————————



Class是Reflection故事起源。针对任何您想探勘的类,唯有先为它产生一个Class 对象,接下来才能经由后者(即Class对象,因为是要解剖类Class的,所以要现有Class对象,这样才可以解剖)唤起为数十多个的Reflection API(即Class对象的大部分方法返回的都是java.lang.reflect包下的类,如Field,Method,Constructor等类)




Class<T>类:T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是 Class<String>如果将被建模的类未知,则使用 Class<?>

获取Class类对象的方法

①类名.class     将被建模的类在编译时即可知,比如String.class 返回的是Class<String>

②对象.getClass()   将被建模的类在编译时即可知,比如"abc".getClass()返回的是Class<? extends String> 即返回的是String类或其子类(看?是什么返回的就是什么)

③Class.forName(String className)     一般推荐使用该方法

Class类中有一个静态方法:public static Class<?> forName(String className)
返回的类未知,因为只有运行的时候才能知道,所以在定义的时候是Class<?> c = Class.forName("java.lang.String");

—————————————————————————————————————————————————————————

—————————————————————————————————————————————————————————

Class对象的方法(用于解剖):(一个类被封装在Class对象中,类中的方法,构造方法,成员变量都被封装在该Class对象的成员变量或方法中)

①返回Constructor类对象的:(它有泛型)

返回此 Class 对象所表示的类的指定公共(public)构造方法: Constructor<T> getConstructor(Class<?>... parameterTypes);  

返回此Class对象所表示的类的所有的(包括非public)构造方法: Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes);

②返回Method类型对象的:

返回此 Class 对象所表示的类的指定公共(public)方法: Method  getMethod(String name, Class<?>... parameterTypes);

name - 方法名parameterTypes - 参数类型数组

返回此Class对象所表示的类的所有的(包括非public)方法:Method getDeclaredMethod(String name, Class<?>... parameterTypes);

③返回Field类型对象的:

返回此 Class 对象所表示的类的指定公共(public)方法: FieldgetField(String name,); 

返回此Class对象所表示的类的所有的(包括非public)方法: Field  getDeclaredField(String name);

......还有很多其他方法,需要时可以查阅JDK API 1.6

public方法和非public方法的区别在于get后面多一个Declared。

java.lang.reflect包下的类:

Constructor<T>类:T - 在其中声明构造方法的类。

T newInstance(Object... initargs);使用此Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数initargs初始化该实例。

其他方法用到时看JDK API 1.6

Method类:

Objectinvoke(Object obj,Object... args) 对带有指定参数的指定对象调用由此Method 对象表示的底层方法。

其他方法用到时看JDK API 1.6

Field类:

void set(Object obj,Object value) 将指定对象变量上此Field 对象表示的字段设置为指定的新值。

其他方法用到时看JDK API 1.6

这些类都继承于AccessibleObject 类,该类有一个方法在访问非public成员时会用到。

setAccessible(boolean flag) 将此对象的accessible 标志设置为指示的布尔值。当flag置true,表示可访问非public成员,否则不可以访问即在访问非public之前必须由反射对象设置可访问性,对于public的可以不设置。默认flag为false。

综上,使用反射的步骤为

①获取Class对象,大部分都通过Class.forName(String name);获取,有泛型

②通过Class对象得到java.lang.reflect包下的类的对象,如ConStructor 对象 con

③如果是非public的,设置可访问性。如con.setAccessible(true);

④调用java.lang.reflect包下的类的对象的方法。如con.newInstance();

注意有时候需要向下转型,因为有些返回的是Object类型。

示例代码:

<span style="font-size:14px;">package com.qq.java.reflect;import java.lang.reflect.Constructor;public class ReflectDemo2{public static void main(String[] args) throws Exception{/*//获取Class对象,该对象提供了类结构的信息<span style="white-space:pre"></span>Class<?> c = Class.forName("com.qq.java.reflect.Student");<span style="white-space:pre"></span>//通过Class对象获取Constructor对象,如果构造方法无参数,则不用写<span style="white-space:pre"></span>Constructor<?> con = c.getConstructor();<span style="white-space:pre"></span>//调用反射对象的方法,通过构造方法对象的newInstance方法获取创建对象<span style="white-space:pre"></span>Student s = (Student) con.newInstance();<span style="white-space:pre"></span><span style="white-space:pre"></span>s.show(); 这个是创建了对象后调用的,不推荐*/<span style="white-space:pre"></span><span style="white-space:pre"></span>Class<?> c = Class.forName("com.qq.java.reflect.Student");<span style="white-space:pre"></span>Constructor<?> con = c.getDeclaredConstructor(String.class);<span style="white-space:pre"></span>con.setAccessible(true);<span style="white-space:pre"></span>Student stu = (Student)con.newInstance("Rose");<span style="white-space:pre"></span>Field f = c.getDeclaredField("name");<span style="white-space:pre"></span>f.setAccessible(true);<span style="white-space:pre"></span>f.set(stu, "Jack");<span style="white-space:pre"></span>Method m = c.getDeclaredMethod("show");//如果方法没有参数,则不写,均不要写null<span style="white-space:pre"></span>m.setAccessible(true);<span style="white-space:pre"></span>m.invoke(stu);}}</span>


Student类

<span style="font-size:14px;">package com.qq.java.reflect;public class Student{private String name;private Student(String name){this.name = name;System.out.println("Student constructor"+":"+name);}public String getName(){return name;}public void setName(String name){this.name = name;}private void show(){System.out.println("I love java "+name);}}</span>


0 0
原创粉丝点击