黑马程序员------------反射、内省、类加载、动态代理

------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
一、反射
一、你整么理解反射?
    程序运行过程中,动态的获取另外一个未知类中所有的成员,并能实现调用。
二、作用:
     解耦,提高了程序的扩展性,更符合面向对象的思想。

三、获取Class对象的三种方式

        加载XX.class文件进内存时就被封装成了对象,该对象就是字节码文件对象。如何获取Class对象呢?

方式一:对象.getClass()

        通过对象的getClass方法进行获取。

        如:Class clazz=new Person().getClass();//Person是一个类名

        麻烦之处:每次都需要具体的类和该类的对象,以及调用getClass方法。

方式二:类名.class

        任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。

        如:Class clazz=Person.class;//Person是一个类名

        比第一种较为简单,不用创建对象,不用调用getClass方法,但是还是要使用具体的类,和该类中的一个静态属性class完成。

方式三:Class.forName("路径");

        这种方式较为简单,只要知道类的名称即可。不需要使用该类,也不需要去调用具体的属性和行为。就可以获取到Class对象了。

        如:Class clazz=Class.forName("包名.Person");//Person是一个类名

        这种方式仅知道类名就可以获取到该类字节码对象的方式,更有利于扩展。

四、 Class 类中的方法    
1.创建对象

         Object  newInstance()

        创建此Class对象所表示的类的一个新实例。

2.获取Class对象

       static Class forName(String className)

        返回与给定字符串名的类或接口的相关联的Class对象。

3. 获取Constructor对象       

        Constructor getConstructor()

        返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。

 4.   返回一个Method对象     

        Method getMethod(String name,Class parameterTypes)

        返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法

        Method对象中的方法invoke(调用该方法的对象,传入的参数值);

  5.  Field getField(String name)

        返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。

 6.  获取实体类名。

         String getName()

        以String形式返回此Class对象所表示的实体名称。

代码实例:

package cn.reflect;

public class Person {
	public  static String name = "李多";
	public int age;
	public Person(){
		System.out.println( "this");
	}
	
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
		System.out.println(this.name);
	}
	// 非静态,无参
	public void show(){
			System.out.println("show   姓名:"+this.name+"年龄:"+this.age);
	}
	public void showNo(String name){
		System.out.println("show姓名:"+name);
}
	//静态,不带参
	public static void staticShow(){
			System.out.println("show姓名:");
	}
	//静态,带参
	public static void staticPar(String name ,int age){
		System.out.println("姓名:"+name+"--------年龄:"+age);
  }
}

package cn.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectMethodDemo {

	public static void main(String[] args) throws Exception {
		//	一、访问非静态,不带参方法
	//	method();
		//二、访问静态,不带参
	//	method2();
		// 三、访问非静态,带参方法
		method3();
		//四、访问静态带参
		method4();
	}


	private static void method4() throws Exception{
		String s = "cn.reflect.Person";
		Class clazz = Class.forName(s);
		
		Method m = clazz.getMethod("staticPar", String.class,int.class);
		m.setAccessible(true);
		m.invoke(null, "李瑁4",24);
	}


	private static void method3() throws Exception {
		String str = "cn.reflect.Person";
		//获取字节码文件对象
		Class clazz = Class.forName(str);
		//创建构造
		//Constructor con = clazz.getConstructor();
		//实例化对象
		Object obj = clazz.newInstance();
		//传入方法名,参数类型
		Method m = clazz.getMethod("showNo", String.class) ;
		m.invoke(obj, "李瑁2");
	}


	private static void method2() throws Exception {
		String str = "cn.reflect.Person";
		//获取字节码文件对象
		Class clazz = Class.forName(str);
		Method m = clazz.getMethod("staticShow", null);
		m.invoke(null, null);
	}


	private static void method() throws Exception {
		
		String str = "cn.reflect.Person";
		//获取字节码文件对象
		Class clazz = Class.forName(str);
		//创建构造
		Constructor con = clazz.getConstructor(String.class,int.class);
		//实例化对象
		Object obj = con.newInstance("李瑁",24);
		//传入方法名,参数类型
		Method m = clazz.getMethod("show", null) ;
		m.invoke(obj, null);
		
	}
}


package cn.reflect;

import java.lang.reflect.Field;

public class ReflectFieldDemo {

	public static void main(String[] args) throws Exception{
//		    普通的属性
//		    私有的属性
//		     静态的属性
		fieldMethod();
	}
	private static void fieldMethod() throws Exception {
		//获取字节码文件对象
		Class clazz = Class.forName("cn.reflect.Person");
		//Object obj = clazz.newInstance();
		//获取对应属性的对象
		Field f = clazz.getField("name"); //访问公共
		//Field f = clazz.getDeclaredField("name");// 可以访问公共、保护、默认、私有。
		
		//f.setAccessible(true);
		
		
		String name = (String) f.get(null);
		System.out.println(name);
	}
}

二、内省

对程序类部进行检查,主要用来操作JavaBean

javaBean是一种特殊的Java类,主要用来传递数据信息。体现:将类中的属性为私有的,对外提供公共的访问方法。

一个标准的JavaBean代码:

package com.itheima;

public class Person {
	private String name;
	private int age;
	public Person (String name, int age ) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
	
}

简单的内省:

package com.itheima;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class IntroSpectorTest {

	/**
	 * 简单的内省操作。
	 * @param args
	 * @throws IntrospectionException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 * @throws IllegalAccessException 
	 */
	public static void main(String[] args) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Person p = new Person("limao", 24);
//		属性的名字
		String propertyName = "name";
//		创建内省对象
		getProperty(p, propertyName);
		String propertyAge = "age";
		Object newAge = 21;
		setProperty(p, propertyAge, newAge);
	}
// 	操作set方法
	private static void setProperty(Person p, String propertyAge,Object age)
			throws IntrospectionException, IllegalAccessException,
			InvocationTargetException {
		PropertyDescriptor pd = new PropertyDescriptor(propertyAge, p.getClass());
		Method setAge= pd.getWriteMethod();
		setAge.invoke(p, age);
		System.out.println(p.getAge());
	}
//	操作get方法
	private static void getProperty(Object obj, String propertyName)
			throws IntrospectionException, IllegalAccessException,
			InvocationTargetException {
		PropertyDescriptor pd = new PropertyDescriptor(propertyName, obj.getClass());
//		获取name的get方法
		Method getName = pd.getReadMethod();
		Object ob = getName.invoke( obj );
		System.out.println(ob);
	}

}

BeanUtils等工具包封装了内省的操作:我们开发的时候只需要导入BeanUtils包,就可以使用setProperty这些方法。

里面提供的功能更加的全面,数据类型的自动转换。

BeanUtils工具包中还有一个工具类PropertyUtils,用法跟BeanUtils一样。区别:

        1)BeanUtils会对JavaBean的属性的类型进行转换,如属性本身是integer,会转换为String。

        2)PropertyUtils以属性本身的类型进行操作。

三、类加器
类加载器负责加载 Java 类的字节代码到 Java 虚拟机中。

当我们使用一个类,如果这个类还未加载到内存中,系统会通过加载、连接、初始化对类进行初始化。

1、类加载:指的是将类的class文件读入JVM,并为之创建一个Class对象。

2、类连接:指的是把类的二进制数据合并到JRE中,这又分为3个阶段:

a)、校验:检查载入Class文件数据的正确性。

b)、准备:给类的静态变量分配存储空间,并进行默认初始化。

c)、解析:将类的二进制数据中的符号引用替换成直接引用。

3、初始化:对类的静态变量、静态初始化块进行初始化。

注意:使用ClassLoader()方法,只是加载该类,并未初始化

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class类的一个实例。
Java 中的类加载器大致可以分成两类,一类是系统提供的,另外一类则是由 Java 应用开发人员编写的。

系统提供的类加载器主要有下面三个:

  • 引导类加载器(bootstrap class loader):它用来加载 Java 的核心库,是用原生代码来实现的,并不继承自 java.lang.ClassLoader
  • 扩展类加载器(extensions class loader):它用来加载 Java 的扩展库。Java 虚拟机的实现会提供一个扩展库目录。该类加载器在此目录里面查找并加载 Java 类。
  • 系统类加载器(system class loader):它根据 Java 应用的类路径(CLASSPATH)来加载 Java 类。一般来说,Java 应用的类都是由它来完成加载的。可以通过 ClassLoader.getSystemClassLoader()来获取它。

四、动态代理:

当我们需要在不改变某一个类的源代码时候,给他生成一个代理类,在代理类中修改这个类,在原来的那个类中前面添加方法,或后面添加方法。动态的改变。
动态代理中有两个重要的类,InvocationHandler接口,Proxy类,一个类和接口是实现动态代理所必须用到的。
一、InvocationHandler
每一个动态代理类都必须实现InvocationHandler接口, InvocationHandler这个接口的唯一一个方法  invoke  方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy:  指代我们所代理的那个真实对象method:  指代的是我们所要调用真实对象的某个方法的Method对象args:  指代的是调用真实对象某个方法时接受的参数
二、Proxy
Proxy这个类的作用就是用来动态创建一个代理对象的类。

代码:
package com.itheima.Refeclt;

import java.lang.reflect.Proxy;

public class DynamicProxy {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		RealSubject  sub = new RealSubject();
		
		SubInterface  pro = (SubInterface )Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
				new Class[] {Subject.class, SubInterface.class},
				new ProxyHandler( sub ) );
		pro.Hello();
		
//		pro.Hello();
		
		
	}

}

package com.itheima.Refeclt;

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

public class ProxyHandler implements InvocationHandler{
	private Object obj = null;
	
	public ProxyHandler(Object obj) {
		this.obj = obj;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
			long startTime = System.currentTimeMillis();
			Thread.sleep(10);
			method.invoke(obj, args);
			long endTime = System.currentTimeMillis();
			System.out.println("代理类执行的时间:    "+(endTime-startTime));
		return null;
	}
	
}

package com.itheima.Refeclt;

interface Subject {
	void dosomething();
}

package com.itheima.Refeclt;

public interface SubInterface {
	
	void Hello();
	
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值