黑马程序员 学习日记(五)
来源:互联网 发布:使用线程池的java实例 编辑:程序博客网 时间:2024/05/17 21:43
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不同的另一种思维去理解。我学的也不是太透彻,以上是我个人理解,难免有错,非常欢迎留言指正。大家互相学习互相进步。
以后如果还有新的心得我会追加更新。
- 黑马程序员 学习日记(五)
- 黑马程序员 学习日记(五)
- 黑马程序员学习日记五
- 黑马程序员 日记(五)
- 黑马程序员--学习日记(五)IO流(一)
- 黑马程序员-C语言学习日记(五)复杂类型
- 黑马程序员 自学日记(五)线程
- 黑马程序员--学习日记
- 黑马程序员 日记五:反射机制学习总结
- 黑马程序员--【学习日记五】——多线程
- 黑马程序员-OC学习日记五之多态
- 黑马程序员——java学习日记五
- 黑马程序员-iOS学习日记(五)面向对象-self和super关键字
- 黑马程序员-C语言学习日记(五)预编译、类型定义及static
- 黑马程序员学习日记----多线程(一)
- 黑马程序员学习日记----多线程(二)
- 黑马程序员-学习日记17( GUI )
- 黑马程序员 学习日记(一)
- 不要学习代码,要学会思考
- uva 846(数学)
- Caffe在转化图片到levelDB中遇到问题Check failed: data.size() == data_size
- 手机浏览器判断,窗口宽度,获取当前页面的顶端到页面顶端的距离
- [转载]如何做一个出色的程序员
- 黑马程序员 学习日记(五)
- Myclipse初学使用教程
- 《effective c++》读书笔记【一】
- JFreeChart 来创建基于 web 的图表
- POJ3181 Dollar Dayz 动态规划,多重背包
- CSS3 伪类选择器 nth-child()说明
- poj 抓小偷
- 凸多边形碰撞检测算法——分离坐标轴方法
- uva 10499(数学)