java反射机制解析

1.什么是反射

 * JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

 * 对于任意一个对象,都能够调用它的任意一个方法和属性;

 * 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。通俗点讲,通过反射,该类对我们来说是完全透明 的,想要获取任何东西都可以

*网上查阅得到理解

      如何理解反射?简单的一句话解释,将传统的开发思路反向逆转。

      传统的方式是通过类创建对象:类 ---> 对象。

      反射就是将这个过程逆转,通过对象得到类:对象 ---> 类。

     通过对象得到的这个类该如何表示?

     使用Class类来表示,此类是Java反射的源头,是用来描述其他类的类,Class类的每一个实例化对象就是对其他类的描述。

     在Object类中定义了以下的方法,此方法将被所有子类继承:

     public final Class getClass()。

     也就是说每一个类,都可以调用getClass()方法获取对应的Class对象,用来描述目标类,我们将这个Class类叫做目标类的运行时类。

* 要想解剖一个类,必须先要获取到该类的字节码文件对象。

* 而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象

*获取字节码对象的三种方式:

   ➢ a:Object类的getClass()方法,判断两个对象是否是同一个字节码文件

   ➢ b:静态属性class,锁对象

   ➢c:Class类中静态方法forName(),读取配置文件

2.反射演示

(1)

package com.hbsi.reflect;

import com.hbsi.demo.Person;

public class Demo1 {
	public static void main(String[] args) throws ClassNotFoundException {
     Class clazz1 = Class.forName("com.hbsi.demo.Person");//读取配置文件
     Class clazz2 = Person.class;//当做静态方法的锁对象
     Class clazz3 = new Person().getClass();//判断是否是同一个字节码对象
     System.out.println(clazz1==clazz2);
     System.out.println(clazz2==clazz3);
	}

}

(2)通过反射获取构造方法并使用

Class类的newInstance()方法使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了
Class类的getConstructor(String.class,int.class)方法

可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数,然后再调用Constructor类的newInstance("张三",20)方法创建对象

package com.hbsi.demo;
//无參构造方法 alt shift s c   有參alt shift s o     equal方法  alt shift s h
public class Person {
	private String name;
	private int age;
//其他省略不写
	public void eat(){
		System.out.println("今天吃了一顿金钱豹");
	}
	public void eat(int num){
		System.out.println("今天吃了"+num +"顿金钱豹");
	}
	
}
package com.hbsi.reflect;
//通过反射获取构造方法并使用
import java.lang.reflect.Constructor;

import com.hbsi.demo.Person;

/*	* Class类的newInstance()方法是使用该类无参的构造函数创建对象,
	如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)
	方法获取一个指定的构造函数然后再调用Constructor类的newInstance("张三",20)方法创建对象*/
public class Demo4 {
	public static void main(String[] args) throws Exception {
		Class clazz = Class.forName("com.hbsi.demo.Person");
		// Class类的newInstance()方法是使用该类无参的构造函数创建对象,
		// Person p = (Person) clazz.newInstance();
		// System.out.println(p);
		Constructor c = clazz.getConstructor(String.class, int.class);//获取有参构造
		Person p = (Person) c.newInstance("张三", 23);//通过有参构造创建对象
		System.out.println(p);
	}
}

(3)通过反射获取成员变量并使用

Class.getField(String)方法可以获取类中的指定字段(可见的)
Class.getDeclaedField(String)方法可以获取类中的指定字段(私有的)

通过set(obj, "李四")方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值

mport java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import com.hbsi.demo.Person;

//Field
//* Class.getField(String)方法可以获取类中的指定字段(可见的),
//如果是私有的可以用getDeclaedField("name")方法获取,通过set(obj, "李四")
//方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,
//用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值
//通过反射获取成员变量并使用
public class Demo5 {
	public static void main(String[] args) throws Exception {
		Class clazz = Class.forName("com.hbsi.demo.Person");
		Constructor c = clazz.getConstructor(String.class,int.class);
		Person p = (Person) c.newInstance("张三",11);
		//Field f = clazz.getField("name");//获取姓名字段  共有的
		Field f = clazz.getDeclaredField("name");//暴力反射获取私有字段
		f.setAccessible(true);//去除私有权限
		f.set(p,"李四");
		f.get(p);
		System.out.println(p);
	}
}

(4)通过反射获取方法并使用

getMethod(String name, 类<?>... parameterTypes)

返回一个 方法对象,它反映此表示的类或接口的指定公共成员方法 对象

getDeclaredMethod(String name, 类<?>... parameterTypes)

返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 对象

package com.hbsi.reflect;

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

import com.hbsi.demo.Person;

//通过反射获取方法
//Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)
//方法可以获取类中的指定方法,调用invoke(Object, Object...)可以调用该方法,Class.getMethod("eat") 
//invoke(obj) Class.getMethod("eat",int.class) invoke(obj,10)
public class Demo6 {
	public static void main(String[] args) throws Exception {
		Class clazz = Class.forName("com.hbsi.demo.Person");
		Constructor c = clazz.getConstructor(String.class,int.class);
		Person p = (Person) c.newInstance("张三",11);
		Method m =clazz.getMethod("eat");//获取eat方法、
		
		m.invoke(p);//执行eat方法
		Method m1 =clazz.getMethod("eat",int.class);//获取eat方法
		m1.invoke(p,10);//执行eat方法
	}
}

(5)通过反射越过泛型检查

      * ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢?

package com.hbsi.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

//* ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢?
//泛型只在编译期间有效,运行期会被擦出掉,字节码文件是运行期 所有不会报错
public class Demo7 {
	public static void main(String[] args) throws Exception {
     ArrayList<Integer> list = new ArrayList<>();
     list.add(111);
     Class clazz = Class.forName("java.util.ArrayList");//获取字节码对象
     Method m = clazz.getMethod("add", Object.class);//获取list的add方法
     m.invoke(list, "abc");
     System.out.println(list);
	}
}

(6)反射(动态代理的概述和实现)

* A:动态代理概述

    * 代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。

    * 举例:春节回家买票让人代买

    * 真实对象:被代理的对象

   *代理对象: 代理对象代理真实对象,达到增强真实对象功能的目的。 用户调用代理对象,代理对象调用真实对象。

   * 动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

   * 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象

    * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

    * 最终会调用InvocationHandler的方法

    * InvocationHandler Object invoke(Object proxy,Method method,Object[] args)

我们来举一个卖电脑的例子

➢接口SaleComputer

package com.hbsi.proxy;

public interface SaleComputer {
   public String sale(double money);
   public void show();
}

➢实现类

package com.hbsi.proxy;

public class Lenovo implements SaleComputer{

	@Override
	public String sale(double money) {
		// TODO Auto-generated method stub
		System.out.println("花了"+money+"元买了一台电脑");
		return "联想电脑";
	}

	@Override
	public void show() {
		// TODO Auto-generated method stub
		System.out.println("展示电脑.......");
	}

}

➢动态代理测试类(对sale()方法进行增强)

package com.hbsi.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理对象代理真实对象,达到增强真实对象功能的目的。
/**
 * 
 * @author lbq 静态代理:有一个类文件描述成代理模式 动态代理:在内存中形成代理类,并不能看到这个代理类文件
 */
public class ProxyTest {
	public static void main(String[] args) {
		// 1.代理对象和真实对象实现相同的接口
		// 2.通过Proxy.newProxyInstance() 获取代理对象
		// 3.使用代理对象调用方法
		// 4.增强方法
		//真实对象 目标类
		Lenovo lenovo = new Lenovo();
		// 代理类 将目标类(切入点) 和切面类(通知)结合 ------>切面
		//lenovo.getClass().getInterfaces()代理对象实现的接口们  和真实对象一样
		SaleComputer proxy_lenovo =(SaleComputer)Proxy.newProxyInstance(lenovo.getClass().getClassLoader(),
							lenovo.getClass().getInterfaces(), new InvocationHandler() {
			
			        //代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
					// proxy:代理对象
					// method:代理对象调用的方法,被封装为对象
					// args:代理对象调用的方法时,传递的实际参数
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						// TODO Auto-generated method stub
                     if(method.getName().equals("sale")){
                    	 //1.增强参数
                    	 double money  = (double)args[0];
                    	 money = money*0.85;
                    	 System.out.println("专车接送你");//2,增强方法体
                    	 //使用真实对象调用该方法
                    	
                    	 String obj = (String) method.invoke(lenovo, money);
                    	 System.out.println("免费送货");//增强方法体
                    	 //3.增强返回值
                    	return obj+"_鼠标垫";
                    	
                     }else{
                    	 Object obj = method.invoke(lenovo, args);
                    			 return obj;
                     }
						
					}

				});
		//代理对象调用方法
		String computer = proxy_lenovo.sale(8000);
		System.out.println(computer);
		        proxy_lenovo.show();
	}
}

结果展示:专车接送你
花了6800.0元买了一台电脑
免费送货
联想电脑_鼠标垫
展示电脑.......

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值