反射技术

    一、引言及java.lang.Class的介绍      

    反射技术作为一项高新技术,其宗旨沿用了Java的设计思想:万物皆对象。不过这次的对象不是别人,而是类本身。我们都知道Java中的类是对象的共性的代表。所有的.class文件被加载后都会获得一个对应的Class实例对象,通过这个对象,我们就可以获取当前类的所有信息!

          首先我们来看下类被加载如内存中的过程:

          .java文件====①====.class文件====②====被调用的加载入内存
          ①    每个类对应一个.class文件
          ②    Step1:加载不同的.class文件,获取到java.lang.Class实例。
           Step2: 连接
           Step3: 初始化

  注:类的加载器分为:启动加载器和用户自定义的加载器,不同的类加载器加载。

程序实例(ClassLoader)

@Test
	public void ClassLoader() throws Exception{
		//系统加载器
		ClassLoader systemClassLoader=ClassLoader.getSystemClassLoader();
		System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@ad3ba4
		
		//系统加载器的上级是扩充加载器
		ClassLoader extClassLoader=systemClassLoader.getParent();
		System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@126b249
		
		//扩充加载器的上级是启动加载器
		ClassLoader bootstrapClassLoader=extClassLoader.getParent();
		System.out.println(bootstrapClassLoader);//null
//		由于没有足够权限访问由c/c++编写的启动加载器,故返回null
		
		//查看自定义类的加载器
		Class clazz1=Student.class;
		ClassLoader extLoader=clazz1.getClassLoader();
		System.out.println(extLoader);//sun.misc.Launcher$AppClassLoader@1372a1a
		//从输出对比可以知晓:自定义类是由系统加载器加载的
		
		Class clazz=String.class;
		ClassLoader loader=clazz1.getClassLoader();
		System.out.println(loader);//sun.misc.Launcher$AppClassLoader@1372a1a
		//从输出对比可以知晓:自定义类是由系统加载器加载的
		
		/**
		 * ClassLoader重点方法:读取文件夹下的文件
		 */
		/*ClassLoader classLoader=this.getClass().getClassLoader();
		InputStream is=classLoader.getResourceAsStream("com\\heima\\jdbc.properties");
		Properties properties=new Properties();
		properties.load(is);
		String user=properties.getProperty("user");
		System.out.println(user);*/
		/**
		 * 只能读取工程目录下的文件
		 */
		FileInputStream fis=new FileInputStream(new File("jdbc.properties"));
		Properties properties=new Properties();
		properties.load(fis);
		String user=properties.getProperty("user");
		System.out.println(user);
		
	}

        在获取java.lang.Class实例之后,我们便可以解析类中的所有成分。那么接下来我们一起看看类的共性有哪些吧?

      我们要明确Class类是类的共性的一种描述,一般一个类的全部结构为:
 所在的包

注解

修饰符 类名 extends superclass<T> implements Interfaces{
        数据成员、方法、注解、构造器、内部类、实现的接口
}

类加载器:
ClassLoader getClassLoader()

包名:
 Package getPackage()

修饰符
 Modifier.toString( getModifiers() )
 
 
类名:
String getName()  

superClass(父类):
Class<?superT>getSuperclass()

父类的类型:
/**
     *
     * 获取父类的泛型
     * @throws Exception
     * @throws InstantiationException
     */
    @Test
    public void testGeneric() throws  Exception{
        Class clazz=Student.class;
        Student stu=(Student) clazz.newInstance();
        ParameterizedType type=(ParameterizedType) clazz.getGenericSuperclass();
        Type[] types=type.getActualTypeArguments();
        System.out.println(types[0]);
        
    }
    
数据成员

//获取所用数据成员时使用

Field[] getDeclaredFields() 

Field[] getFields() 
//调用数据成员时使用

Field getDeclaredField(String name)  
Field[] getDeclaredFields()
Field getField(String name)

 
成员方法

//调用方法时使用

 Method getDeclaredMethod(String name, Class<?>... parameterTypes)

  Method getMethod(String name, Class<?>... parameterTypes)

method.invoke
 

//获取所用方法时使用

  Method[] getDeclaredMethods()  
 
 Method[] getMethods()
 
 
 构造器:

//调用构造器时使用

 Constructor<T> getConstructor(Class<?>... parameterTypes)
 
 //获取所有构造器时使用
  Constructor<?>[] getConstructors()  
 
 
  注解
 
  <A extends Annotation>
A
 getAnnotation(Class<A> annotationClass)
 
 Annotation[] getAnnotations() 


这样一来以Class类的一个反射技术就显现了出来,我们来看看本技术点需要掌握的内容吧!


图片

                                                                                        图:反射技术重要知识点

第一个知识点java.lang.Class的介绍上面已经讲过了,这里就不赘述了。整个一个反射就是生成Class对象,解析类生成对应类的对象实例(Class的newInstance或者Constructor的newInstance),然后通过解析类的各个组成部分,并对他们进行调用

下面我们来看看生成Class对象和对应类的实例的方法有哪些吧。

二、实例化对象

通过java.lang.Class生成类的实例化对象有四种方案:
①调用从Object类中继承的getClass()方法,通过clazz.newInstance()方法生产指定类的实例
②类.class,通过clazz.newInstance()方法生产指定类的实例
③调用java.lang.Class.forName( className),通过clazz.newInstance()方法生产指定类的实例
通过类的加载器来获取
//        通过类加载器获得
        ClassLoader classLoader=this.getClass().getClassLoader();
        Class clazz4=classLoader.loadClass("com.heima.Student");
        System.out.println(clazz4.getName());

通过以上三种方式获取到了clazz实例后通过getConstructors() 获取Constructor,然后通过newInstance()获取指定雷的实例


三、解析类的成员并调用

前面已经提到过,类的通用结构

所在的包

注解

修饰符 类名 extends superclass<T> implements Interfaces{
        数据成员、方法、注解、构造器、内部类、实现的接口
}


这里注意java中一切皆对象,也就是说类中的所有成员都可以被抽象出一些共性来,并且还有一些访问这些共性的方法。

//解析的总结
因此我们要解析出类的完整的结构,在这里就是通过Class的方法获取一系列类的实例。

//调用的总结
那么调用类的成员首先要明确不同成员的功能:构造器生成对象(newInstance),方法用来调用(invoke),field用来存值和获取值(设值:
void set(Object obj, Object value)  
和取值: Object get(Object obj)  )


java.lang.reflect.Constructor

Constructor是抽取了构造器的共性。作为原先对象的构造器,它的作用是生成对象。

//解析构造器结构
它的一般结构:
注解
修饰符 构造器名(参数){
    。。。。。
}
获取修饰符的属性:
int getModifiers()  
 Modifier.toString()
 
 获取构造器的名称:
  String getName()  
 
获取注解:
T
 getAnnotation(Class<T> annotationClass)  
 
 Annotation[] getDeclaredAnnotations()  
 
 
 获取形参类型:
  Class<?>[] getParameterTypes()
 
 
 
 //调用
  T newInstance(Object... initargs) 


java.lang.reflect.Field

Field是抽取了成员变量的共性。作为原先对象的数据成员,它的作用是存值和取值

//解析成员变量的结构
它的一般结构:
修饰符 类型 成员变量名

//获取修饰符
int getModifiers()  
Modifier.toString(getModifiers())

//获取成员变量名
String getName()
 
 
//获取成员变量类型
Class<?> getType()


//调用对象的方法
//设置成员变量和获取成员变量值
setXxx和getXxx


//设置和获取指定对象该字段的值
 Object get(Object obj)
 
 void set(Object obj, Object value) 



java.lang.reflect.Method


Method是抽取了方法的共性。作为原先对象的方法,它的作用是被类或者对象调用

//解析成员变量的结构
它的一般结构:
注解
修饰符 类型 方法名(形参) 异常{
}

//解析类的结构
//获取注解
 Annotation[] getDeclaredAnnotations()  
 
 <T extends Annotation>
T
 getAnnotation(Class<T> annotationClass)  
 
 //获取修饰符
 Modifier.toString( int getModifiers()
 )
 
 //获取返回值类型
  Class<?> getReturnType()  
 
 
  //获取方法名
   String getName()
 
 
//获取参数类型
 Class<?>[] getParameterTypes()
 
 
 //获取异常类型
 Class<?>[] getExceptionTypes()
 
 
 
 //调用方法
  Object invoke(Object obj, Object... args)


代码实例

package com.heima;

import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Properties;

import org.junit.Test;

public class ClassTest {

	@Test
	public void test() throws Exception {
		//生成对象化实例
		Class clazz=Student.class;
		Student stu=(Student) clazz.newInstance();
		
		/*Method method=clazz.getMethod("setId",Integer.class);
		method.invoke(p, 12);*/
		//访问public访问权限的field
		Field field=clazz.getField("id");
		field.setInt(stu, 20000121);
		int id=field.getInt(stu);
		
		//访问private访问权限的field
		Field field1=clazz.getDeclaredField("name");
		field1.setAccessible(true);
		field1.set(stu, "tang");
		System.out.println(field1.get(stu));
		
		
//		调用方法
		Method method=clazz.getMethod("display");
		method.invoke(stu);
		
	}
	
	/**
	 * 获取java.lang.Class的四种方法
	 * @throws Exception
	 */
	@Test
	public void newClass() throws Exception{
		//通过调用类的字节码获取
		Class clazz1=Student.class;
		System.out.println(clazz1.getName());
		
//		通过加载类名获取
		Class<?> clazz2=Class.forName("com.heima.Student");
		System.out.println(clazz2.getName());
		
		//通过getClass获取
		Student stu=new Student();
		Class clazz3=stu.getClass();
		System.out.println(clazz3.getName());
		
//		通过类加载器获得
		ClassLoader classLoader=this.getClass().getClassLoader();
		Class clazz4=classLoader.loadClass("com.heima.Student");
		System.out.println(clazz4.getName());
//		classLoader.loadClass("Student");
	}
	
	@Test
	public void ClassLoader() throws Exception{
		//系统加载器
		ClassLoader systemClassLoader=ClassLoader.getSystemClassLoader();
		System.out.println(systemClassLoader);//sun.misc.Launcher$AppClassLoader@ad3ba4
		
		//系统加载器的上级是扩充加载器
		ClassLoader extClassLoader=systemClassLoader.getParent();
		System.out.println(extClassLoader);//sun.misc.Launcher$ExtClassLoader@126b249
		
		//扩充加载器的上级是启动加载器
		ClassLoader bootstrapClassLoader=extClassLoader.getParent();
		System.out.println(bootstrapClassLoader);//null
//		由于没有足够权限访问由c/c++编写的启动加载器,故返回null
		
		//查看自定义类的加载器
		Class clazz1=Student.class;
		ClassLoader extLoader=clazz1.getClassLoader();
		System.out.println(extLoader);//sun.misc.Launcher$AppClassLoader@1372a1a
		//从输出对比可以知晓:自定义类是由系统加载器加载的
		
		Class clazz=String.class;
		ClassLoader loader=clazz1.getClassLoader();
		System.out.println(loader);//sun.misc.Launcher$AppClassLoader@1372a1a
		//从输出对比可以知晓:自定义类是由系统加载器加载的
		
		/**
		 * 重点方法:读取文件夹下的文件
		 */
		/*ClassLoader classLoader=this.getClass().getClassLoader();
		InputStream is=classLoader.getResourceAsStream("com\\heima\\jdbc.properties");
		Properties properties=new Properties();
		properties.load(is);
		String user=properties.getProperty("user");
		System.out.println(user);*/
		/**
		 * 只能读取工程下的文件
		 */
		FileInputStream fis=new FileInputStream(new File("jdbc.properties"));
		Properties properties=new Properties();
		properties.load(fis);
		String user=properties.getProperty("user");
		System.out.println(user);
		
	}
	/**
	 * 解析类中的成员
	 */
	@Test
	public void parseFields(){
		Class clazz=Student.class;
		//getFields()获取本身及其父类的public类型数据成员
		Field[]  fields=clazz.getFields();
		for(Field field:fields){
			System.out.println(field.getName());
		}
		System.out.println("\r\n");
		System.out.println("\r\n");
		System.out.println("\r\n");
		//getDeclaredFields()获取本身的所有被声明的成员
		fields=clazz.getDeclaredFields();
		for(Field field:fields){
			System.out.println(Modifier.toString(field.getModifiers())+" "+field.getName());
		}
		
		//获取数据成员的修饰符
		
	}
	
	
	/**
	 * 
	 * 获取父类的泛型
	 * @throws Exception 
	 * @throws InstantiationException 
	 */
	@Test
	public void testGeneric() throws  Exception{
		Class clazz=Student.class;
		Student stu=(Student) clazz.newInstance();
		ParameterizedType type=(ParameterizedType) clazz.getGenericSuperclass();
		Type[] types=type.getActualTypeArguments();
		System.out.println(types[0]);
		
	}
	
	
	
	
	
	/*==============================调用指定的成员=====================================*/
	
	/**
	 * 调用方法和属性值
	 * @throws Exception 
	 * @throws SecurityException 
	 */
	@Test 
	public void testInvoke() throws SecurityException, Exception{
		//调用静态方法
		Class clazz=Student.class;
		Student stu=(Student) clazz.newInstance();
		Method method=clazz.getDeclaredMethod("hello");
		method.setAccessible(true);
		method.invoke(stu);
		
		//调用私有数据成员
		Field name=clazz.getDeclaredField("name");
		name.setAccessible(true);
		name.set(stu, "tang");
		System.out.println(stu.toString());
		
		//调用私有构造器
		
		Constructor constructor=clazz.getConstructor(String.class,int.class,int.class);
		constructor.setAccessible(true);
		Object obj=constructor.newInstance("tang",25,25);
		System.out.println(obj);
	}

}

到这里为止,反射的大致情况我们已经清晰了,下面我们介绍一个由反射产生的设计模式——动态代理

在介绍动态代理之前,我们先来了解下它的前身:静态代理,从中总结下代理的规律!!!

图片

图为静态代理的原理

实现代码:

package com.heima;

//公共接口
interface ClothFactory{
	public void product();
}
//被代理类
class NikeFactory implements ClothFactory{

	public void product() {
		System.out.println("nike");
	}
	
}
//代理类
class ProxyFactory implements ClothFactory{
	//包装被代理对象,这样就可以控制被代理对象的调用和时机
	public ClothFactory  clothFactory;
	
	public ProxyFactory(ClothFactory clothFactory) {
		super();
		this.clothFactory = clothFactory;
	}
	public void product() {
		System.out.println("this is proxy");
		clothFactory.product();
	}
	
}

/**
 * 静态代理设计模式测试
 * @author John
 */
public class StaticProxy {

	public static void main(String[] args) {
		ClothFactory clothFactory=new NikeFactory();
		ProxyFactory proxy=new ProxyFactory(clothFactory);
		proxy.product();
	}
}

好了,从上面的例子我们可以看到,代理类的建立依据于被代理类和公共接口。首先代理类通过被代理类生成代理对象,然后通过代理对象去调用与被代理对象同名的方法。

实例代码:

package com.heima;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//共同的接口,用于测试
interface Man{
	public void eat();
	public void walk();
}

//被代理类,用于测试
class Proxyed implements Man{

	public void eat() {
		System.out.println("吃饭!!!");
		
	}

	public void walk() {
		System.out.println("走路!!!");
	}
	
}


//根据公共接口和需要被代理的类动态地生成代理类
class MyProxy  implements InvocationHandler{
	

	private Object obj;
	
	
	public MyProxy(Object obj) {
		super();
		this.obj = obj;
	}
	//根据公共接口和需要被代理的类动态地生成代理类
	public Object blinder(){
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
	}
	//通过代理类加入到被代理类的方法中去
	public void logIn(){
		System.out.println("==================日志记录===================");
		System.out.println("==================用户登入===================");
	}
	//通过代理类加入到被代理类的方法中去
	public void logOut(){
		System.out.println("==================用户登出===================");
	}
	/**
	 * 当代理类对象调用方法时,会自动调用此方法,从而控制了方法的调用时机和调用结果
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		logIn();
		Object object=method.invoke(obj, args);
		logOut();
		return object;
	}
	
}

/**
 * 动态代理设计模式:
 * 涉及到的重点的类
 * @author John
 *
 */
public class DynamicProxy {
	public static void main(String[] args) {
		//生成被代理对象
		Man man=new Proxyed();
		//通过被代理对象获取代理对象,获取依据:公共接口和被代理类对象
		Man myProxy=(Man) new MyProxy(man).blinder();
		//当调用代理类的这个方法是默认去调用了invoke
//		myProxy.eat();
		myProxy.walk();
	}
}





 










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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值