day23 反射机制

1.什么是反射机制
     反射就是通过获取到该类的字节码文件对象---->Class类对象,通过Class类对象获取该类里面的一些属性(成员变量)、构造方法、成员方法。
  
  
  面试题:
   如何获取类的字节码文件对象,并且有几种方式呢?
  
 1)Object类中的getClass()方法,表示正在运行的那个类:Class类
 2)数据类型的class属性  举例:String.class,Student.class
 3)Class类中的特有方法:forName(String className):(重点,数据库加载驱动:Drivers)
  public static Class<?> forName(String className):获取字节码文件对象
 
  开发中常使用的方式,因为第三种里面的参数是一个字符串...,字符串的内容是一个类的全路径名称
  
  
  class Demo{
   private static Student s = new Student() ; //成员变量位置:实例字段
   private String name ;
  }
  
  
  
  Person p = new Person() ;
  

  System.out.println(p) ;

public class Demo {
	
	public static void main(String[] args) throws ClassNotFoundException {
		
		//创建Person对象
		Person p1 = new Person() ;
		Class c1 = p1.getClass() ;//---->得到Person.class字节码文件对象
		
		//创建对象
		Person p2 = new Person() ;
		Class c2 = p1.getClass() ;//------->Person.class字节码文件对象
		
		System.out.println(p1==p2);//false
		System.out.println(c1==c2);//true
		
		System.out.println("--------------------");
		
		//第二种方式:通过数据类型的Class属性
		Class c3 = Person.class ;//---->加载并且获得person.class字节码文件对象
		System.out.println(c3==c1);
		
		System.out.println("----------------------");
		
		//第三种方式获取类的字节码文件
		//注意:参数不是一个类名
//		Class c4 = Class.forName("Person") ;//java.lang.ClassNotFoundException
		//参数需要类路径:类的全路径名称
		Class c4 = Class.forName("org.westos.reflect_01.Person") ;
		//class org.westos.reflect_01.Person
//		System.out.println("c4:"+c4);
		System.out.println(c4==c1);
	}
}

public class Person {
	//成员变量
	private String name ;
	int age ;
	public String address ;
	
	public Person(){}
	
	private Person(String name) {
		this.name = name;
	}
	
	Person(String name,int age){
		this.name = name ;
		this.age = age ;
	}
	
	public Person(String name,int age,String address){
		this.name = name ;
		this.age =age ;
		this.address = address ;
	}
	
	//提供一些成员方法
	public void show(){
		System.out.println("show");
	}
	
	public void method(String s){
		System.out.println("method"+s);
	}
	
	public String getString(String s, int i) {
		return s + "---" + i;
	}
	
	private void function(){
		System.out.println("function");
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", address=" + address
				+ "]";
	}
	
	
}

2.通过反射获取构造方法并使用它



public class ReflectDemo {

	
	public static void main(String[] args) throws Exception {
		//获取一个类中的构造方法,首先找到这个类的class文件对象,通过反射
		//获取Person类的Class类对象
		Class c = Class.forName("org.westos.reflect_01.Person") ;
		
		//使用该Class类对象中的一些成员方法:
		//public Constructor<?>[] getConstructors(),返回的是一个构造方法所在数组
//		public Constructor<?>[] getDeclaredConstructors():获取的是当前字节码文件对象中所有的构造方法

		
		//表示的类的所有公共构造方法
		/**
		 * public org.westos.reflect_01.Person(java.lang.String,int,java.lang.String)
			public org.westos.reflect_01.Person()
		 */
//		Constructor[] con = c.getConstructors() ;
		
		//获取当前Pereson类中所有的构造方法
//		Constructor[] con = c.getDeclaredConstructors() ;
		//增强for
//		for(Constructor constructor:con){
//			System.out.println(constructor);
//		}
		
		//如何获取单个的构造方法:
		//public Constructor<T> getConstructor(Class<?>... parameterTypes)
      //  返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法
		//参数表示:参数数据类型的字节码文件对象:获取指定构造方法里面有参数,需要写上数据类型的字节码文件对象
//		假设   :String.class
		
		//没有学习的反射的时候
		//Person p = new Person()
		//System.out.println(p) ;
		
		//获取构造器对象:Constructor
		Constructor con = c.getConstructor() ;
//		System.out.println(con);
		
		//调用构造器对象里面的一个方法:newInstance()
		//public T newInstance(Object... initargs):传递的是实际参数
		//表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例
		Object obj = con.newInstance() ; //-->通过反射--->Person.class---->getConstructor() 
		
		System.out.println(obj);
	}
}

3.之前创建对象:
  给对象的成员属性赋值
   Person p = new Person("高圆圆",27,"户县")
   System.out.println(p) ;
  
      通过反射获取构造方法并且给成员属性赋值

public class ReflectDemo2 {
	
	public static void main(String[] args) throws Exception {
		
		//获取Person类的字节码文件对象
		Class c = Class.forName("org.westos.reflect_01.Person") ;
		
		//通过反射获取指定构造方法:getConstructor(Class ...parameterTyps)   参数:参数类型.class
		Constructor con = c.getConstructor(String.class, int.class,
				String.class);
		
		//创建构造器的实例对象,来给他指定的字节码文件对象里面的成员变量赋值
		Object obj = con.newInstance("高圆圆",27,"户县") ;//实际参数
		System.out.println(obj);
		
	}
}

4.通过反射获取私有的构造方法,并使用
   Person p = new Preson("高圆圆") ;
       System.out.println(p) ;

public class ReflectDemo3 {
	
	public static void main(String[] args) throws Exception {
		
		//1)获取Person类的字节码文件对象
		Class c = Class.forName("org.westos.reflect_01.Person") ;
		
		
		//2)如何获取私有的?
//		public Constructor<T> getConstructor(Class<?>... parameterTypes)
		//该方法获取当前指定的公共的构造方法
		//public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
		//表示获取类或者接口中的指定的构造方法
		Constructor con = c.getDeclaredConstructor(String.class) ;
		
		
		
		//public void setAccessible(boolean flag):在访问的时候取消java语言访问检查(强制性)
        //将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查
		//取消 Java 语言访问检查
		con.setAccessible(true) ;//在去给构造创建实例对象之前就应该取消检查
		//创建构造器的实例对象,可以去传递实际参数
		Object obj = con.newInstance("高圆圆") ;
		/**
		 * java.lang.IllegalAccessException: 非法的访问异常
		 * Class org.westos.reflect_02.ReflectDemo3 can not access a member of 
		 * 				class org.westos.reflect_01.Person with modifiers "private"
		 * 私有的构造方法是不能直接访问的
		 */
		
		System.out.println(obj);
	}
}

5.通过反射获取成员变量并使用

public class ReflectDemo {
	
	public static void main(String[] args) throws Exception {
		
//		1)通过反射获取字节码文件对象
		Class c = Class.forName("org.westos.reflect_01.Person") ;
		
		//2)获取所有的公共的成员变量public Field[] getFields():所有的公共的可访问的字段,返回的是Field对象数组
		//public Field[] getDeclaredFields():获取当前字节码文件对象中所有的公共的或者私有的字段
//		Field[] fields = c.getFields() ;
//		Field[] fields = c.getDeclaredFields() ;
//		for(Field f :fields){
//			//public java.lang.String org.westos.reflect_01.Person.address
//			System.out.println(f);
//		}
		
		
		//反射之前:给一个类的成员变量赋值:公共的字段
//		Person p  = new Person() ;
		//p.address = "北京" ;
		
		
		//获取到这个Field对象之前,还获取构造器对象(通过无参构造创建Person类的实例)
		Constructor con = c.getConstructor() ;
		//创建构造器实例
		Object obj = con.newInstance() ;//Person的实例对象
		System.out.println(obj);
		
		//反射:
		//获取单个成员变量(Field类对象)
		//给成员变量address赋值
		//public Field getField(String name):获取公共的指定的字段  参数为当前成员变量名称"address"
		Field addressFiled = c.getField("address") ;
		//有了Field对象,给当前obj实例对象设置一个参数
		//将指定对象变量上此 Field 对象表示的字段设置为指定的新值public void set(Object obj, Object value)
		//给obj实例对象里面的成员变量设置一个实际参数---->value
		addressFiled.set(obj, "北京") ;
		System.out.println(obj);
		
		System.out.println("-----------------------------");
		//给name赋值并使用
		//NoSuchFieldException :该成员变量是一个私有的
//		Field nameField = c.getField("name") ;
		//public Field getDeclaredField(String name):获取类或接口中已经声明的指定的字段
		Field nameField = c.getDeclaredField("name") ;
		//给name属性设置值
		//java.lang.IllegalAccessException
		nameField.setAccessible(true) ;//取消Java语言访问检查
		nameField.set(obj, "高圆圆") ;
		System.out.println(obj);
		
		System.out.println("-------------------------------");
		
		//给age字段赋值并使用
		Field ageField = c.getDeclaredField("age") ;
		
		//给ageFiled在当前实例对象obj设置一个参数值
		//取消访问检查
		ageField.setAccessible(true) ;//取消Java语言访问检查
		ageField.set(obj, 27) ;
		
		System.out.println(obj);
		

		
	}
}

6.通过反射获取成员变量并使用
 
  之前使用对象调用成员方法
  Person p = new Person() ;
  p.show() ;

public class ReflectDemo {
	
	public static void main(String[] args) throws Exception {
		
		//1)通过反射获取字节码文件对象并使用
		Class c = Class.forName("org.westos.reflect_01.Person") ;
		
		//获取成员方法(Method)
		//public Method[] getMethods():获取当前该字节码文件对象(Person.class)中自己本身以及它父类中所有的公共成员方法
//		Method[] methods = c.getMethods() ;
//		public Method[] getDeclaredMethods():获取当前字节码文件对象本身所有的成员方法
//		Method[] methods = c.getDeclaredMethods() ;
//		for(Method m :methods){
//			System.out.println(m);
//		}
		
		//获取构造器对象,通过构造器创建当前字节码文件的实例对象
		Constructor con = c.getConstructor() ;
		Object obj = con.newInstance() ; //Person对象
		
		//获取单个成员方法
		//public void show() {}
		/**
		 * public Method getMethod(String name,Class<?>... parameterTypes):指定公共成员方法
		 * 参数1:表示方法名
		 * 参数2:该方法的参数类型的Class对象(数据类型的class属性) String.class
		 */
		Method m1 = c.getMethod("show") ;
//		obj.m1() ;//错误的写法
		/**
		 * public Object invoke(Object obj, Object... args)
		 * 参数1:表示当前针对哪个以实例对象进行方法的调用
		 * 参数2:当前调用该方法的时候里面传递的实际参数
		 */
		m1.invoke(obj) ;
		
		System.out.println("-------------------------");
		
		//public void method(String s){}
		//调用Method方法
		Method m2 = c.getMethod("method", String.class) ;
		//调用
		m2.invoke(obj, "word") ;
		
		System.out.println("----------------------------");
		
		/*
		 * public String getString(String s, int i) {
				return s + "---" + i;
	}
		 * */
		
		//调用getString()方法
		Method m3 = c.getMethod("getString", String.class,int.class) ;
		//调用
//		Object objString = m3.invoke(obj, "hello",100) ;
//		System.out.println(objString);
		String objString = (String) m3.invoke(obj, "hello",100) ; //向上转型
		System.out.println(objString);
		
		System.out.println("--------------------------");
		//private void function(){
		//System.out.println("function");
		//}
		//调用function()方法
		//该方法是私有的,public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
		//获取的是已经声明的指定的方法
		//oSuchMethodException:
		Method m4 = c.getDeclaredMethod("function") ;
		//IllegalAccessException:
		//调用
		m4.setAccessible(true) ;//取消Java语言的访问检查
		m4.invoke(obj) ;
	}
}




反射的应用:

1.我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
  
  
  反射的应用:
   1)在集合中应用
   2)用来反射区读取配置文件来加载里面的内容(MySQL,Oracle等等,SQLServer,MangoDB)

public class ArrayListTest {
	
	public static void main(String[] args) throws 
	NoSuchMethodException,
	SecurityException, IllegalAccessException,
	IllegalArgumentException, 
	InvocationTargetException {
		
		
		//创建ArrayList对象
		ArrayList<Integer> array = new ArrayList<Integer>() ;
		
		//给集合中添加元素
//		array.add(100) ;
//		array.add("hello") ;
		
		//利用反射类来给集合中添加字符串数据
		//获取该ArrayList类的字节码文件对象
		Class c = array.getClass() ;
		//有了ArrayList.class字节码文件对象了
		//已经有了构造器对象:array
		//可以通过反射在获取公共的访问:add(E e) 
		Method m = c.getMethod("add",Object.class) ;
		//调用用底层invoke(当前字节码文件对象的实例,实际参数)
		m.invoke(array, "hello") ;
		m.invoke(array, "world") ;
		m.invoke(array, "java") ;
		
		System.out.println(array);
		
	}
}



2.


public class Student {
	
	public void love(){
		System.out.println("学生爱学习,爱Java");
	}
}
public class Teacher {
	
	public void love(){
		System.out.println("老师Java,爱高圆圆");
	}
}
public class Worker {
	
	public void love(){
		System.out.println("工人爱生活,爱老婆");
	}
}

public class Test {
	
	public static void main(String[] args) throws Exception {
		
		//反射之前的作用:
//		Student s = new Student() ;
//		s.love() ;
//		Teacher t = new Teacher() ;
//		t.love() ;
//		Worker w = new Worker() ;
//		w.love() ;
		
		//使用反射的做法:
		//文本文件是一种键值对象的形式...
		//需要将文本文件中的内容加载属性集合类中(键值对都是String类型)
		//创建一个属性集合类
		Properties prop = new Properties() ;
		//加载
		FileReader fr = new FileReader("class.txt") ;
		prop.load(fr) ;
		//关闭资源
		fr.close() ;
		
		//通过键获取值,使用它的特有功能getProperty("String key")
		String className = prop.getProperty("className") ;
		String methodName = prop.getProperty("methodName") ;
		
		//获取字节码文件对象
		Class c = Class.forName(className) ;
		
		//通过反射获取构造器对象,并且通过构造器对象创建该类的实例
		Constructor con = c.getConstructor() ;
		Object obj = con.newInstance() ;
		
		//获取成员方法
		Method m = c.getMethod(methodName) ;
		
		//调用
		m.invoke(obj) ;
	}
}


3.写一个方法,
public void setProperty(Object obj, String propertyName, Object value){},此方法可将obj对象中名为propertyName的属性的值设置为value

public class ToolDemo {
	
	public static void main(String[] args) throws NoSuchFieldException, 
	SecurityException, 
	IllegalArgumentException, 
	IllegalAccessException {
		
		//创建Person类对象
		Person p = new Person() ;
		Tool t = new Tool() ;
		//设置name属性
		t.setProperty(p, "name", "高圆圆") ;
		t.setProperty(p, "age", 27) ;
		
		System.out.println(p);
		
		Dog d = new Dog() ;
		t.setProperty(d, "gender",'公' ) ;
		t.setProperty(d, "price", 34.56F) ;
		System.out.println(d);
	}
	
	
}

public class Tool {
	public void setProperty(Object obj, String propertyName, Object value) throws 
	NoSuchFieldException, 
	SecurityException, 
	IllegalArgumentException,
	IllegalAccessException{
		
		//获取类的字节码文件对象
		Class c = obj.getClass() ;
		
		//通过字节码文件对象获取Field对象
		//为了防止可能后有一些私有的成员变量:getDeclaredField("字段名称")
		Field field = c.getDeclaredField(propertyName) ;
		
		//通过field对象给指定对象obj设置属性值
		//防止出现	IllegalAccessException:设置Java语言取消访问检查
		field.setAccessible(true) ;
		field.set(obj, value) ;
	}
}


4.

public class Test {
	
	public static void main(String[] args) {
		//创建用户操作的对象
		UserDao ud = new UserDaoImpl() ;
		ud.add() ;
		ud.delete();
		ud.update() ;
		ud.serach() ;
		
		System.out.println("------------------");
		//给ud对象设置代理对象
		//Proxy类中的方法创建动态代理类对象
		//public static Object newProxyInstance
		//(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
		//InvocationHandler是代理对象需要实现的接口---->需要自定义一个类实现这个接口
		//创建代理对象
		MyInvocationHandler handler = new MyInvocationHandler(ud) ;
		UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass().getClassLoader(), 
				ud.getClass().getInterfaces(),handler) ;
		//参数1:需要类加载器:首先获取当前目标对象的字节码文件对象,在去调用getClassLoser()
		//参数2:获取目标的字节码文件对象,调用方法得到给目标对象提供一组接口
		
		proxy.add();
		proxy.delete() ;
		proxy.update() ;
		proxy.serach() ;
		
		//登录注册,增删改查 等等...

	}
}

public interface UserDao {
	
	//增
	public abstract void add() ;
	//删
	public abstract void delete() ;
	//update:修改
	public abstract void update() ;
	//查
	public abstract void serach() ;
}

public class UserDaoImpl implements UserDao {

	@Override
	public void add() {
		System.out.println("增加功能");
	}

	@Override
	public void delete() {
		System.out.println("删除功能");
	}

	@Override
	public void update() {
		System.out.println("修改功能");
	}

	@Override
	public void serach() {
		System.out.println("查询功能");
	}

}

public class MyInvocationHandler implements InvocationHandler {
	
	//目标对象(需要给哪一个对象设置这个代理呢?)
	private Object target ; 
	
	//无参构造
	public MyInvocationHandler(Object target){
		this.target = target ;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//权限校验
		System.out.println("权限校验");
		Object result = method.invoke(target, args) ;
		//日志记录
		System.out.println("日志记录");
		return result; //返回值就是代理对象
	}

}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值