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

---------------------- 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 stub
		String 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 stub
		ReflectPoint 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值