黑马程序员 学习日记(五)

来源:互联网 发布:使用线程池的java实例 编辑:程序博客网 时间:2024/05/17 21:43
---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------

Java中的反射机制

JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。

1.概述

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

2.Class

这个Class,注意首字母是大写的,而不是声明一个类的时候的那个关键字。我们都知道一个类包含的内容有很多,有名字、访问属性、方法等,这些属性方法其实也是一个类,描述类的一部分的类都属于一个类Class。听起来很别扭,也不太好理解,没关系,还是要通过例子来看看Class到底是什么,因为学习反射,首先就必须立即Class!

每一个类都是唯一的,实例化的对象可以千变万化,但是类,对于它的描述只有一种

class Person{    int age;}

像这个Person类,名字是Person,属性有年龄,你只能这么去描述它。生成的对象呢,你可以说张三21岁,李四12岁.....想说多少就有多少。

所以Person类本身在计算机里的字节码是唯一的。

Class c1 = Person.class ;

此时c1就获得Person 类本身的字节码。查询API可以知道还能通过实例化的对象去获得该类的字节码。无论你通过什么途径,他们的值都是一样的!

Class c1 = Person.class;Class c2 = new Person().getClass();Class c3 = Class.forName("Person") ;
这里c1 == c2 == c3  。

那么,现在应该知道Class的作用了,在编译时得到一个类的字节码,当你在编译时不知道运行后会获得什么类(forName()里面可以说字符串变量),这将非常有用!

另外,Class不能直接new,因为它代表的是字节码,内存中已经存在的对象(即代表某个类的字节码),所以无需new。

[boolean, byte, short, long, int, char, float, double] 这八个是预定义的Class的实例,int.class 就能得到Class的实例,

如果你知道什么是自动装箱,那么有必要知道 int.class == Integer.TYPE

可能你现在会困惑,现在有基本类型(如int等八个)、有类,那我拿到一个Class的实例怎么知道是不是基本类型

int.class.isPrimitive() ;//返回boolean型
用这句就可以判断是不是基本类型。此句返回值是true。


3.构造方法的反射

了解了Class以后,就可以开始研究反射了。现在就要通过Class去得到未知类名的类的构造方法。

通过查询API可以知道Class有以下两个方法:

getConstructor()  //返回构造方法,参数可以传递若干个Class对象,Java5的新特性,可变参数

getConstructors()//返回构造方法数组

Class.forName(str).getConstructor(int.class) ;
str是一个字符串变量,依次找到未知名的类的构造方法。

下面请看完整代码

import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class ReflectTest {public static void main(String[] args) throws Exception {// TODO Auto-generated method stubString str = "java.lang.String" ;Class strClass = Class.forName(str) ;Constructor cst = strClass.getConstructor(StringBuffer.class) ;String s = (String)cst.newInstance(new StringBuffer("Hello World!")) ;System.out.println(s);}}

输出结果:Hello World!

getConstructor后面的参数决定调用的构造方法。如果是无参构造方法,直接调用Class的newInstance()方法即可

String s = (String)Class.forName(str).newInstance() ;

4.成员变量的反射

首先写一个有成员变量的类。

public class ReflectPoint {private int x ;public int y ;public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}}

然后再写一个主类去调用。

import java.lang.reflect.Field;public class ReflectTest {public static void main(String[] args) throws Exception {// TODO Auto-generated method stubReflectPoint rf = new ReflectPoint(1,2) ;Field fieldY = ReflectPoint.class.getField("y") ;Field fieldX = ReflectPoint.class.getDeclaredField("x") ;fieldX.setAccessible(true);System.out.println(fieldX.get(rf));System.out.println(fieldY.get(rf));}}

Field 专门用去获取Class对象里的成员变量。

如果想访问private修饰的变量,需要getDeclaredField,然后设置 setAccessible(true) 强行获取变量值。


5.成员方法的反射

Method是获取方法的关键字。

import java.lang.reflect.Method;public class ReflectMethod {public static void main(String args[]) throws Exception{String s = "abc" ;Method charAt = String.class.getMethod("charAt", int.class) ;System.out.println(charAt.invoke(s, 1)) ;}}

输出结果是:‘b’

getMethod(方法名,识别要调用的方法的参数),一个方法名可能有很多次重载,通过传递int.class  调用参数只有一个int的charAT方法。

获得字节码并不能直接调用方法,通过Class提供的invoke()方法去调用,参数保持获取时的一致。


6.总结

反射要学好,就得建立与原先Java不同的另一种思维去理解。我学的也不是太透彻,以上是我个人理解,难免有错,非常欢迎留言指正。大家互相学习互相进步。

以后如果还有新的心得我会追加更新。



---------------------- ASP.Net+Unity开发、.Net培训、期待与您交流! ----------------------
0 0
原创粉丝点击