反射


一、Class 类

1、概述:

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。每个java类都是Class的一个实例对象,它们的内容不同,但是,它们的特征相同,譬如,都有方法,有字段,有父类,有包。对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。

一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的。

2、如何得到各个字节码对应的实例对象( Class类型)

类名.class,例如,System.class

/*Class x1 = Vector类在内存里的字节码

 Class x2 = Date类在内存里的字节码*/

Class x1 = Vector.class;

Class x2 = Date.class;

3、如何得到各个字节码对应的实例对象( 以String类型为例)

String str1 = "abc";

Class cls1 = str1.getClass();

Class cls2 = String.class;

Class cls3 = Class.forName("java.lang.String");

总之,只要是在源程序中出现的类型,都有各自的Class实例对象。 

二、反射机制概述

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

Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

三、Constructor类

1、概述:Constructor类代表某个类中的一个构造方法

2、得到某个类所有的构造方法:

例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();

3、得到某一个构造方法:通过要用到类型来获得对应的方法。

例子:      Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

4、创建实例对象:

通常方式:String str = new String(new StringBuffer("abc"));

反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));

//调用获得的方法时要用到上面相同类型的实例对象

5、Class.newInstance()方法:该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。

例子:String obj = (String)Class.forName("java.lang.String").newInstance();

四、Field类

1、概述:Field类代表某个类中的一个成员变量。

2、在访问类中的成员变量时,一定要注意的是当成员变量为私有变量时,直接使用getField( )是不能访问的,这时就需要使用暴力反射getDeclaredField( );并将该字段设置成为可处理状态 setAccessible(true);

3、获取类中的成员变量及暴力反射演示示例:

import java.lang.reflect*;
	public class ReflectClass
{
     public static void main(String[] args) throws Exception
	{
        ReflectPoint pt1 = new ReflectPoint(3, 5);
			Field fieldy = pt1.getClass().getField("y");
		/* 
		 *    
		该怎么正确理解field_Y这个字段?这里的field_Y只是Filed类字节码身上的变量,并不是指对象.
		我们可以创建很多个ReflectPoint类的对象而且每个对象都会有相应的field_Y字段,
		也就是说该字段并不代表某个对象具体的值,只是一个变量.
		而如果要拿出field_Y变量在某个对象身上的值那就用fieldY.get(具体的对象)
		*/
      System.out.println(fieldy.get(pt1)); 
//暴力反射,ReflectPoint中的x是私有的,按照上面fieldy的方法去获取是不可以的
		//必须使用getDeclaredField();还要将fieldx设置成可访问的 setAccess(true)
Field fieldx = pt1.getClass().getDeclaredField("x");
			fieldx.setAccessible(true);
System.out.println(fieldy.get(pt1));

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

4、示例:运用反射获取来中的成员变量,将String类型的变量值中所有b换为a

import java.lang.reflect*;
	public class ReflectClass
{
     public static void main(String[] args) throws Exception
	{
changeStringValue(pt1);
			System.out.println(pt1);
		}
	//扫描下面方法ReflectPoint中所有String类型变量的值,如果值中有"b"则将改为"a"
	private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException 
	{
		//得到所有的字段
		Field[] fields = obj.getClass().getFields();
		//迭代所有的字段
		for (Field field : fields)
		{
			//获得String类型的字段
			//field.getType().equals(String.class) 字节码只有一份,比较时直接用"==",不用equals
			if (field.getType() == String.class)
			{
				//获取传入对象中String类型的值
				String oldValue = (String)field.get(obj);
				//将这些值中有"b"的替换为"a"
				String newValue = oldValue.replace("b", "a");
				//将替换后的字段set给 原有对象
				field.set(obj, newValue);
			}
		}
	}
}
class ReflectPoint
{
	private int x;
	public int y ;
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 = "cat";
	public ReflectPoint(int x, int y)
	{
		super();
		this.x = x;
		this.y = y;
	}
	//重写tostring
	@Override
	public String toString()
	{
		return str1 + "::"+ str2  + "::"+ str3;
	}
}

五、Method类

1、Method类代表某个类中 的一个成员方法。

2、得到类中的某一个方法:

Method charAt = ClassforName(“java.lang.String”)getMethod(“charAt”.int.class);

3、调用方法

通常方式:System.out.println(str.charAt(1));

反射方式:System.out.println(charAt.invoke(str,1));

注意:如果传递给Method对象的invoke()方法中第一个参数是null,说明该Method对象对应的是一个静态方法。

 

六、数组

1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(具有相同的字节码)。

例:int[] a1 = new int[3];  int[] a2 = new int[5]; 

System.out.println(“a1.getClass() = a2.getClass()”); //输出为true。说明它们的字节码相同。

2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

int[] a1 = new int[3];

int[] a2 = new int[5];

int[][] a3 = new int[3][7];

String[] a4 = new String[5];

Object aObj = a1;

//Object[] aObj2 = a1; 是不可以的

Object[] aObj3 = a3;

Object[] aObj4 = a4;

3、Arrays类是对数组进行操作的工具,可以直接打印数组内容。对于字符串来说可以直接打印成字符串,但整型是不可以的。因为JDK1.4Arrays.asList(Object[] a)传的是一个object数组,而整型不是,不适合JDK1.4语法,只适合JDK1.5asList(T ...a)。但JDK1.5中传的是一个对象,因此打印出来的就是一个对象。

例: int[] a1 = new int[]{1,2,3;

String[] a4 = new String[]{“a”,”b”,”c“};

System.out.println(Arrays.asList(a1));

//结果:[[I@5bb77832]

System.out.println(Arrays.asList(a4));//结果:[a, b, c]



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值