反射

反射的概念

什么是反射:
         反射就是通过获取类的字节码文件对象:Class
         创建该类的实例(通过构造方法:Constroctor类),调用成员方法(Method类),
         给成员变量赋值(Field类)
  
  关于面试题:获取字节码文件的方式有几种
  三种方式
  	1)Object类的getClass():表中正在运行的Java类(当前类字节码文件)
  	2)任意Java类型的.class属性
  	3)反射Class类中forName("类或者接口的全限定名称") ;
 				com.qianfeng.reflect_10.ReflectDemo
                    
 1.Java代码经历的三个阶段
		SOURCE阶段:源码阶段      javac---java源代码进行编译
		CLASS阶段:类的加载以及初始化阶段   ----xxx.class文件   (检查类的语法结构)
		运行阶段:输入  java  类名------ 产生结果...
            
 2.如何获取一个类的Constructor并创建该类实例呢?
		1)先获取当前类的Class对象(字节码文件对象)
		Class clazz = Class.forName("类的全限定名称") ;
		2)如果当前构造方法公共的: Constructor<T> getConstructor()
		如果当前公祖方法私有/默认/受保护的: Constructor<T> getDeclaredConstructor()
		3)通过构造器创建该类实例
		Constructor类 public Object newInstance() ;
			
3.如何获取一个类Method并调用该方法呢?
	1)先获取当前类的Class对象(字节码文件对象)
		Class clazz = Class.forName("类的全限定名称") ;
	方式1:直接通过当前字节码文件对象创建该类实例
		Object obj = clazz.newIntance() ;
	方式2:通过构造方法创建该类实例
		Constructor<T> getConstructor()
		public Object newInstance() ;
	2)获取Method并调用
			如果当前成员方法是公共的: Method<T> getMethod(String name,Class<T>...paramerters)
			果当前成员方法是私有的/受保护的/默认的修饰符:Method<T> getDeclaredMethod()
	Method  m = clazzz.getMethod("方法名称") ;
	3)调用方法
		m.invoke(obj) ;


4.如何读取src目录下面的xxx.properties文件?
		1)获取当前类的字节码文件对象同时获取该类的类加载器对象ClassLoader
		2)InputStream in = getResourceAsStream("src目录下配置文件") ;
		InutStream inputStream = 类名.class.getClassLoader().getResourceAsStream("src目录下配置文件") ;
		创建属性集合类
		Properties prop = new Properties() ;
		prop.load(inputStream) ;
		//通过反射的方式操作即可!
			
5.获取Field并使用
        Class clazz= Class.forName("类的全限定名称") ;
        //通过构造器 创建该类实例(构造方法是空参的并且公共的方法)
        Constructor con = clazz.getConstructor();
        Object obj = con.newInstance() ;
        //成员变量是公共属性
        Field field = clazz.getField("字段名称") ;
        file.set(obj,实际的值) ;
        //输出obj

使用反射获取构造方法并使用

之前的写法:
     Person p = new Person();通过无参构造方法创建对象
     Person p = new Person("高圆圆");  形参String---String类型字节码文件格式
                            java.lang.String
  
 使用反射获取构造方法并使用,(Constructor) 
 Class 类的实例表示正在运行的 Java 应用程序中的类和接口
 
     1.获取Person类的字节码文件对象
    //public static Class<?> forName(String className):Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
 
 
	 2.获取构造方法(构造器)对象
	//public Constructor<?>[] getConstructors():
        表示获取当前类中的所有的公共的构造方法
	//public Constructor<?>[] getDeclaredConstructors():
		获取当前类中所有的构造方法:包括私有的,公共的,默认,受保护的(proteted):
		Constructor[] cons = c.getConstructors() ;
		for(Constructor con: cons) {
			System.out.println(con);
			
		
	3.获取某一个构造方法所在对象:Constructor
	//public Constructor<T> getConstructor(Class<?>... parameterTypes)
		获取指定的公共构造方法
	//参数:parameterTypes可变参数  里面相当于数组
		参数是当前的字节码文件Class
	例:
		Person p = new Person();通过无参构造方法创建对象 
		直接输出p----->如果重写toString():成员信息的表达式 
		Constructor con = c.getConstructor() ;//Person类的无参构造方法
		
		
	4.通过构造器如何获取当前Person类的实例
	//Constructor创建该类的实例
	//public T newInstance(Object... initargs):参数为当前实际参数:
		Object obj = con.newInstance() ;
		System.out.println(obj);

创建该类的实例(Constroctor类)

 之前的写法:
  Person p = new Person("高圆圆") ;
  System.out.println(p) ; toString()
      
      
      
public class ReflectDemo {
	
	public static void main(String[] args) throws Exception{
		
		//获取Person类的字节码文件
		Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
		
		//获取单个的构造方法
		//Person(String) :是一个私有的,不是公共的
		//public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)	
		//获取指定的构造方法
		//Constructor con  = c.getDeclaredConstructor(String.class) ;
		
		//获取单三个参数的构造方法
		Constructor con = c.getConstructor(String.class,int.class,String.class) ;
		
		//public void setAccessible(boolean flag):参数为true,取消java语言访问检查
        //非法访问异常
		con.setAccessible(true);
        
		//创建该类实例
		Object obj = con.newInstance("高圆圆",27,"西安市鄠邑区") ;
		System.out.println(obj);
		//Person [name=高圆圆, age=27, address=西安市鄠邑区]

调用成员方法(Method类)

之前的写法:
  通过无参构造方法创建对象
  Person p = new Pereson() ;
  p.show();


使用反射获取Person类的字节码文件对象,并获取成员方法Method并使用
@SuppressWarnings("all") //压制警告
public class ReflectDemo3 {
	
	public static void main(String[] args) throws Exception {
        
		//获取Person类的字节码文件对象
		Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
		//获取该类的无参构造方法
		Constructor con = c.getConstructor() ;
		//创建该类的实例
		Object obj  = con.newInstance() ;
		
		//通过获取成员方法
		//public Method[] getDeclaredMethods():获取所有的方法:仅限本类,不包括继承的
		//public Method[] getMethods():获取所有的公共的成员方法:不仅有本类的,还有它父类的
		//Method[] methods = c.getDeclaredMethods() ;
		/*
		Method[] methods = c.getMethods() ;
		for (Method method : methods) {
			System.out.println(method);
		}
		*/
		
		//public Method getDeclaredMethod(String name,
        	//Class<?>... parameterTypes)获取指定的方法
		//public Method getMethod(String name,Class<?>... parameterTypes)获取公共的成员方法
		//参数1:方法名
		//参数2:当前如果该方法有形式参数,跟上行驶时参数类型的Class
		Method m = c.getMethod("show") ;
		//Method类:底层调用方法
		//public Object invoke(Object obj, Object... args)
		//参数1:当前类的实例
		//参数2:跟的实际参数
		m.invoke(obj) ; // 相当于 之前:使用对象名p.show();:使用方法method和function方法
		/**
		 * public String method(int num) {
					return "helloJavaEE"+num ;
			}
		 */
		Method m2 = c.getMethod("method", int.class) ;
		Object object	 = m2.invoke(obj, 100) ;
		System.out.println(object);
		
		System.out.println("-------------------------------------");
		/**
		 * private  void function(String str) {
				System.out.println(str);
			}
		 */
		Method m3 = c.getDeclaredMethod("function", String.class) ;
		//取消Java语言访问检查
		m3.setAccessible(true);
		m3.invoke(obj, "hello,张佳宁") ;

给成员变量赋值(Field类)

之前的写法:
  Person p = new Person() ;
  p.字段名(属性名) = "赋值";
  通过反射获取成员变量Field并使用
 
public class ReflectDemo2 {
	
	public static void main(String[] args) throws Exception {
		
		//获取Person类字节码文件对象
		Class c = Class.forName("com.qianfeng.reflect_01.Person") ;
		
		//获取构造器:Constructor:无参构造方法
		Constructor con = c.getConstructor() ;
		
		//创建该类实例
		Object obj = con.newInstance() ; //p对象
		
		//获取成员变量
		//public Field[] getDeclaredFields():获取所有的Field成员变量(公共的,私有的,默认的,受保护的)
		//public Field[] getFields():获取所有的公共的字段
		//Field[] fields = c.getDeclaredFields() ;
		/*
		Field[] fields = c.getFields() ;
		for(Field f : fields) {
			System.out.println(f);
		}
		*/
		
		//给name进行赋值  private String name;
		//public Field getDeclaredField(String name)
		//参数为:字段名(属性)
		Field field = c.getDeclaredField("name") ;
		//取消Java语言访问检查
		field.setAccessible(true);
		
		//public void set(Object obj,Object value)
		//参数1:当前该Person类的实例
		//参数2:给当前成员字段"name"设置的内容
		
		field.set(obj, "高圆圆"); // 相当于:p.name = "高圆圆"
		System.out.println(obj);
		//Person [name=高圆圆, age=0, address=null]

反射的应用

利用Class.forName("类的全限定名") ;将类的全限定名放置在配置文件中
 * xx.txt 文本文件
 * xx.properties文件
 
 @SuppressWarnings("all")
public class Test {
	
	public static void main(String[] args) throws  Exception {
		
		//创建一个学生类
		Student s = new Student() ;
		s.love();
		System.out.println("-------------------");
		Worker w = new Worker() ;
		w.love();
		//在没有使用反射之前,需求变化:修改代码
		//使用反射
		System.out.println("--------------------------------");
		//创建属性集合类对象
		Properties prop = new Properties() ;
		
		//将文本文件中加载到属性集合类中
		Reader r = new FileReader("class.txt") ;
		prop.load(r);
		r.close();
		
		System.out.println(prop);
		
		//getProperty(String key)---获取值
		String className = prop.getProperty("className") ; //当前类的全限定名
		String methodName = prop.getProperty("methondName") ;//获取方法名
		
		//反射获取当前类Class对象
		Class  clazz = Class.forName(className) ;
		
		//字节码文件对象---Constructor ----newInstance():通过构造器创建
		//Class类中---public T newInstance():直接创建
		Object obj = clazz.newInstance() ;
		
		//获取成员Method
		Method m = clazz.getMethod("love") ;
		
		//Student s = new Student() ; s.love();
		m.invoke(obj) ;
	}
}


如何读取src目录下的properties配置文件
public class Test2 {
	
	public static void main(String[] args) throws Exception {
		
		//1)读取src下面的class.properties配置文件
		//获取当前类的类加载器
		//Class
		//public ClassLoader getClassLoader()
		ClassLoader classLoader = Test2.class.getClassLoader() ;
		//public InputStream getResourceAsStream(String name)
		//读取指定资源的输入流   
		//参数是文件名称  文件必须是在src目录下(类路径)
		//方式1
		InputStream inputStream = classLoader.getResourceAsStream("class.properties") ;
		//方式2:通过类加载器获取网络资源地址对象:URL
		//public URL getResource(String name)
		//public String getPath()
		
		//创建属性集合类对象
		Properties prop = new Properties() ;
		//将流中的数据加载到属性集合类中
		prop.load(inputStream);
		
		//System.out.println(prop);//className=com.qianfeng.reflect_03.Worker, methondName=love}
		//通过键的名称获取值
		String className = prop.getProperty("className") ;
		String methodName = prop.getProperty("methondName") ;
		
		//获取当前类的Class
		Class c	 = Class.forName(className) ;
		
		//直接获取该类实例
		Object obj = c.newInstance() ;
		//获取Method成员方法
		Method m = c.getMethod(methodName) ;
		
		m.invoke(obj) ;
	}
}

反射的应用2

需求:
  	有一个ArrayList<Integer>集合,需要给里面添加String类型的数据,如何实现呢?
  	public class Test3 {

	public static void main(String[] args) throws Exception{
		
		//创建ArrayList<Integer>集合
		ArrayList<Integer> array = new ArrayList<Integer>() ;
		
		//添加元素
		array.add(100) ;
		array.add(200) ;
		//array.add("javaee") ;
		//array.add("hello") ;
		
		//获取类的字节码文件对象有三种
		//直接获取arrayList集合的字节码文件对象
		Class clazz = array.getClass() ;
		//System.out.println(c);//class java.util.ArrayList
		
		//获取当前Method类对象:成员方法
		//public boolean add(Object e) 
		Method m = clazz.getMethod("add", Object.class) ;
		
		//调用add方法
		m.invoke(array, "hello") ;
		m.invoke(array, "world") ;
		
		System.out.println(array);
		
	}
}

代理模式

设计模式:
  	结构型设计模式:
  		代理模式
  			静态代理
  			动态代理
  				jdk动态代理
  				CGlib动态代理
  
  
  静态代理:--------Thread 的实现方式2  implements Runnable接口
  		真实角色:专注于自己的功能
  		代理角色:帮助真实角色对实际的方法进行增强
  			都需要实现指定的接口'
  
  动态代理:在程序的运行过程中产生的代理类
  		JDK动态代理
  		Proxy 提供用于创建动态代理类和实例的静态方法
 
静态方法:
	public static Object newProxyInstance
		(
			ClassLoader loader,
		    Class<?>[] interfaces,
            InvocationHandler h
         )
         
     参数1:表示类的加载器
     参数2:获取类的接口列表的Class字节码文件
     参数3:代理实例的处理程序		接口:InvocationHandler
     		
 JDK动态代理:在程序运行过程中,通过反射的产生的代理类(Proxy以及它里面代理的处理程序:InvocationHandler)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值