反射详解


基本概念

一.反射概念

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

二.字节码

   字节码(Byte-code)是一种包含执行程序、由一序列 op 代码/数据对组成的二进制文件。字节码是一种中间码,它比机器码更抽象。它经常被看作是包含一个执行程序的二进制文件,更像一个对象模型。字节码被这样叫是因为通常每个 opcode 是一字节长,但是指令码的长度是变化的。每个指令有从 0 到 255(或十六进制的: 00 到FF)的一字节操作码,被参数例如寄存器或内存地址跟随。

三.Class类

   Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(booleanbytecharshortintlongfloat 和double)和关键字 void 也表示为 Class 对象。
   Class类是反射的基石。

四.Constructor

Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。

五.Method 

Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。

六.Field 

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

实例及动态应用

一.如何获取字节码对应的实例对象

   Class的赋值不能用new来赋值,因为这个值是存在于内存中的字节码.
   Class的赋值方式有3种,见如下代码
<span style="font-family:SimSun;font-size:18px;">package test;

public class T1 {

	public static void main(String[] args) throws Exception {
		
		String str="java";
		
		Class cls = String.class;
		Class cls1 = str.getClass();
		Class cls2 = Class.forName("java.lang.String");
		
		System.out.println(cls);
		System.out.println(cls1);
		System.out.println(cls2);
		
		
	}
}
//最后输出的结果都为:java.lang.String</span>
 

二.九个预定义Class实例对象

   基本的 Java 类型(booleanbytecharshortintlongfloat 和double)和关键字 void已经被预定义为卷
   
<pre name="code" class="java"><span style="font-family:SimSun;font-size:18px;">package test;

public class T1 {

public static void main(String[] args) throws Exception {
<span>	</span>String str="java";</span>
<span style="font-family:SimSun;font-size:18px;">
<span>	</span>Class cls = String.class;
<span>	</span>Class cls1 = str.getClass();
<span>	</span>Class cls2 = Class.forName("java.lang.String");</span>
<span style="font-family:SimSun;font-size:18px;">
<span>	</span>System.out.println(cls);
<span>	</span>System.out.println(cls.isPrimitive());
<span>	</span>System.out.println(cls1);
<span>	</span>System.out.println(cls2);
}
//输出结果为:</span><span style="font-family: SimSun; font-size: 18px;">java.lang.String</span><span style="font-family: SimSun; font-size: 18px;">,true,</span><span style="font-family: SimSun; font-size: 18px;">java.lang.String,</span><span style="font-family: SimSun; font-size: 18px;">java.lang.String</span>
 
 
补充一些可能用到的方法:boolean  isPrimitive() 判定指定的 Class 对象是否表示一个基本类型。
booleanisAnnotation() 如果此 Class 对象表示一个注释类型则返回 true。             
booleanisArray() 判定此 Class 对象是否表示一个数组类。
booleanisInterface() 判定指定的 Class 对象是否表示一个接口类型。。

三.构造方法的反射应用

<span style="font-family:SimSun;font-size:18px;">package test;

import java.lang.reflect.Constructor;

public class T1 {

	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Exception {

		Class cls = String.class;
		
		//通过getConstructors()获取所有的构造参数
		Constructor constructors[] = cls.getConstructors();
		//输出结果
		for(Constructor constructor : constructors){
				System.out.println(constructor);
		}
		
		//通过参数类型和个数来获得构造函数
		Constructor constructor0 = cls.getConstructor(StringBuffer.class);
		//输出结果
		System.out.println(constructor0);
		
		//一般方式和通过constructor来创建对象
		String str1 = new String("abc");
		String str = (String)constructor0.newInstance(new StringBuffer("abc"));
		//输出下标为2的字符
		System.out.println(str.charAt(2));
	
	}
}
输出结果:public java.lang.String(byte[],int,int)
public java.lang.String(byte[],java.nio.charset.Charset)
public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(byte[],int,int,java.nio.charset.Charset)
public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
public java.lang.String(java.lang.StringBuilder)
public java.lang.String(java.lang.StringBuffer)
public java.lang.String(byte[])
public java.lang.String(int[],int,int)
public java.lang.String()
public java.lang.String(char[])
public java.lang.String(java.lang.String)
public java.lang.String(char[],int,int)
public java.lang.String(byte[],int)
public java.lang.String(byte[],int,int,int)
public java.lang.String(java.lang.StringBuffer)
c</span>
注意点:getConstructor()的参数可以是一个也可以是多个;
通过newInstance()创建实例对象时要用到强制类型转换,因为虚拟机在执行构造函数时才会知道函数的返回类型;
调用获得方法是要用到上面相同类型的实例对象;

四:成员变量的反射


<span style="font-family:SimSun;font-size:18px;">package test;

import java.lang.reflect.Field;

class Person{
	private  int x;
	public   int y;
	public   String str;
	public   String str1;
	public   String str2;
	public  static   int z;
	Person()
	{
		x = 3;
		y = 4;
		z = 5;
		str = "abc";
		str2 = "abcf";
		str1 = "abce";
	} 
}
public class T1 {
	
	public static void main(String[] args) throws Exception {
		Person pe = new Person();
		Class cls = pe.getClass();
		
		//私有成员不可访问
//		Field fieldx = cls.getField("x");
//		System.out.println(fieldx);
		//可以通过以下下方式访问
		Field fieldx = cls.getDeclaredField("x");
		fieldx.setAccessible(true);
		System.out.println(fieldx.get(pe));
		//获取y的值并输出
		Field fieldy = cls.getField("y");
		System.out.println(fieldy.get(pe));
		//获取z的值并输出
		Field fieldz = cls.getField("z");
		System.out.println(fieldz.get(pe));
		//获取str的值并输出
		Field fieldstr = cls.getField("str");
		System.out.println(fieldstr.get(pe));
		
		changeStringValue(pe);
		//输出省略
	
	}
	private static void changeStringValue(Object obj) throws Exception{
		Field[] fields = obj.getClass().getFields();
		for(Field field : fields){
			if(field.getType() == String.class)
			{
				String oldValue = (String)field.get(obj);
				String newValue = oldValue.replace('c', 'd');
				field.set(obj, newValue);
			}
		}
		
		
	}
}
   </span>
注意点:私有成员的访问要更改权限才可以操作

五.成员方法的反射

 package test;

import java.lang.reflect.Method;

public class CopyOfT1 {
	
	public static void main(String[] args) throws Exception {
		String str = new String("abbcd");
		
		Method methodCharAt=String.class.getMethod("charAt", int.class);
		
		System.out.println(methodCharAt.invoke(str, 3));
	}
}
   
注意:JDK1.4和JDK1.5invoke方法的区别
JDK 1.4  public Objiect invoke(Objiect obj,Objiect... args[]);
JDK 1.5  public Objiect invoke(Objiect obj,Objiect[]args);

    




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值