您的位置:首页 > 编程语言 > Java开发

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

2015-03-29 19:33 911 查看
首先明确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)方法:
Field
getField(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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: