黑马程序员学习笔记之八(Java 反射机制)

---------------------- android培训java培训、期待与您交流! ----------------------


 

一、Java的反射机制

        Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤methods。Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。 换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。

 

二、JDK中提供的Reflection API

Java反射相关的API在包java.lang.reflect 包中,JDK 1.6.0的reflect包如下图:

Constructor类

提供一个类的构造函数的信息以及访问类的构造函数的接口。

Field类

提供一个类的域的信息以及访问类的域的接口。

Method类

提供一个类的方法的信息以及访问类的方法的接口。

Modifier类

提供了 static 方法和常量,对类和成员访问修饰符进行解码。

Proxy类

提供动态地生成代理类和类实例的静态方法。

 

三、Java反射机制的功能

Java反射机制提供如下功能:

在运行时判断任意一个对象所属的类

在运行时构造任意一个类的对象

在运行时判段任意一个类所具有的成员变量和方法

在运行时调用任一个对象的方法

在运行时创建新类对象

在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。

定义一个测试类:

public class ReflectPoint {

	private int x;
	public int y;
	
	public ReflectPoint(){}

	public ReflectPoint(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	private void print()
	{
		System.out.println("point"+x+"..."+y);
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}
}

 

1、获取类的Class对象

示例代码:

class ReflectTest 
{
	public static void main(String[] args) throws Exception
	{
		// 调用getClass
		ReflectPoint point = new ReflectPoint(3,5);
		Class clazz = point.getClass();
		System.out.println(clazz);

		// 运用.class 语法
		Class clazz2 = ReflectPoint.class;
		System.out.println(clazz2);

		// 运用静态方法 Class.forName()
		Class clazz3 = Class.forName("java.lang.Integer");
		System.out.println(clazz3);
	}
}

 

2、获取类的Fields

可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。

import java.lang.reflect.*;

class ReflectTest2
{
	public static void main(String[] args) 
	{
		Class clazz = ReflectPoint.class;
	             
		// 使用getFields获取属性 
		Field[] fields = clazz.getFields(); 
		for (Field f : fields) 
		{     
			System.out.println(f); 
		}   
			
		System.out.println();               
		// 使用getDeclaredFields获取属性 
		fields = clazz.getDeclaredFields(); 
		for (Field f : fields) {    
			System.out.println(f); 
		} 

	}
}

【运行结果】

注意:getFields和getDeclaredFields区别:

getFields返回的是申明为public的属性,包括父类中定义,

getDeclaredFields返回的是指定类定义的所有定义的属性,不包括父类的。

 

3、获取类的Method

通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法

Class<T>类提供了几个方法获取类的方法。

 MethodgetMethod(String name,Class<?>... parameterTypes)
          返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
 Method[]getMethods()
          返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共member 方法。

 MethodgetDeclaredMethod(String name,Class<?>... parameterTypes)
          返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
 Method[]getDeclaredMethods()
          返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

 

import java.lang.reflect.*;

class  ReflectTest3
{
	public static void main(String[] args) 
	{
		// 使用getMethods获取函数  
		Class clazz = ReflectPoint.class;
		Method[] methods = clazz.getMethods(); 
		for (Method m : methods) {     
			System.out.println(m); 
		}  
		System.out.println("--------------------------");   
		// 使用getDeclaredMethods获取函数  
		methods = clazz.getDeclaredMethods(); 
		for (Method m : methods) {     
			System.out.println(m);
		} 

	}
}

【运行结果】

 

4、获取类的Constructor

通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例 

Class<T>类提供了几个方法获取类的构造器。

 Constructor<T>getConstructor(Class<?>... parameterTypes)
          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
 Constructor<?>[]getConstructors()
          返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
 Constructor<T>getDeclaredConstructor(Class<?>... parameterTypes)
          返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
 Constructor<?>[]getDeclaredConstructors()
          返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。

import java.lang.reflect.*;

class  ReflectTest4
{
	public static void main(String[] args) 
	{
		Class clazz = ReflectPoint.class;
		// 使用getConstructors获取构造器   
		Constructor[] constructors = clazz.getConstructors(); 
		for (Constructor m : constructors) {     
			System.out.println(m); 
		}    
		
		System.out.println("----------------------------");    
			
		// 使用getDeclaredConstructors获取构造器    
		constructors = clazz.getDeclaredConstructors(); 
		for (Constructor m : constructors) {     
			System.out.println(m);
		} 
	}
}

【运行结果】

 

5、新建类的实例

通过反射机制创建新类的实例,有几种方法可以创建:

import java.lang.reflect.*;

class  ReflectTest5
{
	public static void main(String[] args) throws Exception
	{
		// 调用类的Class对象的newInstance方法,该方法会调用对象的默认构造器,如果没有默认构造器,会调用失败.
		Class clazz = ReflectPoint.class;

		Object obj = clazz.newInstance();

		System.out.println(obj);

		//调用默认Constructor对象的newInstance方法 
		Constructor constructor1 = clazz.getConstructor(); 

		Object inst = constructor1.newInstance(); 

		System.out.println(inst); 

		// 调用带参数Constructor对象的newInstance方法 
		Constructor constructor2 = clazz.getDeclaredConstructor(int.class, int.class); 

		Object inst1 = constructor2.newInstance(3, 5); 

		System.out.println(inst1); 	

	}
}

【运行结果】


6、调用类的函数

通过反射获取类Method对象,调用Method的Invoke方法调用函数。

import java.lang.reflect.*;

class  ReflectTest6
{
	public static void main(String[] args) throws Exception
	{
		Class clazz = ReflectPoint.class;
		Object inst = clazz.newInstance();

		Method method = clazz.getMethod("setY",int.class);
		method.invoke(inst,3);
		
		ReflectPoint point = (ReflectPoint)inst;
		System.out.println(point.y);
	}
}

【运行结果】

 

7、设置/获取类的属性值

通过反射获取类的Field对象,调用Field方法设置或获取值

import java.lang.reflect.*;

class  ReflectTest7
{
	public static void main(String[] args) throws Exception
	{
		Class clazz = ReflectPoint.class;
		
		Object obj = clazz.newInstance();

		Field  fieldY = clazz.getField("y");

		fieldY.setInt(obj,15);

		int retVal = fieldY.getInt(obj);

		System.out.println(retVal);
	}
}

【运行结果】

 

注意:如果要访问类中的private成员变量,需要加上 setAccessible(true)



 

四、动态创建代理类

代理模式:代理模式的作用=为其他对象提供一种代理以控制对这个对象的访问。

代理模式的角色:

抽象角色:声明真实对象和代理对象的共同接口

代理角色:代理角色内部包含有真实对象的引用,从而可以操作真实对象。

真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

动态代理:

java.lang.reflect.Proxy

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类

InvocationHandler

是代理实例的调用处理程序 实现的接口,每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

 

动态Proxy是这样的一种类:

它是在运行生成的类,在生成时你必须提供一组Interface给它,然后该class就宣称它实现了这些interface。你可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

在使用动态代理类时,我们必须实现InvocationHandler接口

1、定义抽象角色

import java.lang.reflect.Method;

public interface Advice {
 void beforeMethod(Method method);
 void afterMethod(Method method);
}

2、定义真实角色

import java.lang.reflect.Method;

public class MyAdvice implements Advice {
 long beginTime = 0;
 public void afterMethod(Method method) {
  // TODO Auto-generated method stub
  System.out.println("元素添加成功啦!");  
  long endTime = System.currentTimeMillis();
  System.out.println(method.getName() + " running time of " + (endTime - beginTime));

 }

 public void beforeMethod(Method method) {
  // TODO Auto-generated method stub
  System.out.println("开始向集合中添加元素啦!");
  beginTime = System.currentTimeMillis();
 }

}

 

import java.util.*;
import java.lang.reflect.*;

class  ProxyDemo
{
 public static void main(String[] args) 
 {
    final ArrayList target = new ArrayList();   
  Collection proxy3 = (Collection)getProxy(target,new MyAdvice()); //调用自定义的getProxy方法
  proxy3.add("zxx");
  proxy3.add("lhm");
  proxy3.add("bxd");
  System.out.println(proxy3.size());
  System.out.println(proxy3.getClass().getName());
 }

 private static Object getProxy(final Object target,final Advice advice) {
  Object proxy3 = Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    new InvocationHandler(){
    
     public Object invoke(Object proxy, Method method, Object[] args)
       throws Throwable {

      advice.beforeMethod(method);
      Object retVal = method.invoke(target, args);
      advice.afterMethod(method);
      return retVal;      
      
     }
    }
    );
  return proxy3;
 }
}

【运行结果】


 

---------------------- <a href="http://edu.csdn.net/heima" target="blank">android培训</a>、<a href="http://edu.csdn.net/heima" target="blank">java培训</a>、期待与您交流! ----------------------

 

 

 

---------------------- android培训java培训、期待与您交流! ----------------------

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值