SE——反射的理解和应用

使用new创建对象的弊端

    1)使用new创建对象必须得使用new关键字,必须得再内存中开辟空间。

    2)这个类必须存在,会访问这个类的无参构造,负责编译不能通过。

    3)可能需要导包。(创建其他类的对象)

引入Class类

    表示正在运行的Java应用程序中的类或者接口。

    使用Java提供的反射机制可以获取这个类的Class对象,这个Class类可以调用这个类中的属性和方法。Class相当于这个类的一个影子,虽然Class对象并不是这个类,但是它和这个类是一样的。可以动态获取类结构 。

创建Class对象的三种方式

    1) 使用getClass()方法:

                    Object str = new Object() ;

                    Class c = str.getClass() ;

            这种方式的弊端是:需要先创建对象,后才能调用方法。就是说在创建影子对象之前已经创建本类的对象。

    2)使用.class属性

                    直接调用.class属性,不是类独有的,甚至基本类型也有 。

                    无需创建对象,被调用的类型必须存在,不存在的类型不能使用。

    3) 使用Class类的静态方法: forName()方法

                    在forName("这里写类的全名")方法中写某个类的全名可以获得对象了。

                    优点:无需创建对象,也无需 考虑这个类是否存在。   如果不存在会抛出异常。                

Demo:

package day22.Class;
/**
 * 创建对象的三种方法
 * @author malaganguo
 *
 */
public class ThreeMethodToCreatReflect {

	public static void main(String[] args) {
		
		//第一种
		Object obj = new Object() ;
		Class<? extends Object> c1 = obj.getClass();
		System.out.println("c1 hashcode:"+c1.hashCode());
	
		//第二种
		Object c2 = Object.class  ;
		Class<Integer> i2 = int.class ;
		System.out.println("c2 hashcode:"+c2.hashCode());
		//第三种
		try {
			Class<?> c3 = Class.forName("java.lang.Object");
			System.out.println("c3 hashcode:"+c3.hashCode());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
}

打印的哈希:

哈希码值相等说明它们是一个对象


获取构造方法

        Constructor构造方法类  在java.lang.reflect.Constructor包下.

        可以使用这个类获取构造方法的修饰符,这个方法是:getModifiers() 。

        可以获取构造方法的名字:getName() 。

        可以获取构造方法的参数类型:getParameterTypes() 。

四种获取构造方法的方式:

        

1)获取所有公有构造方法:class.getConstructors() ;

2)获取指定的公有构造方法:class.getConstructor(Class<?>...parameterTypes) ;

3)获取所有构造方法:class.getDeclaredConstructors() ;

4)获取指定的构造方法:class.getDeclaredConstructor(Class<?>...parameterType) ;

创建构造方法的实例:

        

public T newInstance(Object...initargs) ;

创建构造方法的实例需要强制类型转换,参数数量可以自定义:

Object obj1 = (Object) constructor.newInstance() ;

Object obj2 = (Object) constructor.newInstance("参数1","参数2",......)

Demo:

package day22.Class;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class GetConstructor {

	@SuppressWarnings("rawtypes")
	public static void main(String[] args) {
		//创建映射
		try {
			Class c = Class.forName("day22.Class.Student") ;
			//获取所有公共的构造方法
			Constructor cons[] = c.getConstructors() ;
//			//获取所有构造方法
//			Constructor[] cons = c.getDeclaredConstructors();
			for(Constructor con : cons) {
				System.out.print(Modifier.toString(con.getModifiers())+" ");
				System.out.print(con.getName()+"(");
				Class paras[] = con.getParameterTypes() ;
				for(int i=0;i<paras.length;i++) {
					System.out.print(paras[i].getSimpleName()+"args");
					if(i<paras.length-1) {
						System.out.print(",");
					}
				}
				System.out.println("){ }");
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		
	}
}



结果:

所有公共

所有

 获取各种参数的构造方法并创建带值对象。

package day22.Class;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

public class GetConstructor {

	@SuppressWarnings("rawtypes")
	public static void main(String[] args) {
		//创建映射
		try {
			Class c = Class.forName("day22.Class.Student") ;
			//获取所有公共的构造方法
//			Constructor cons[] = c.getConstructors() ;
			//获取所有构造方法
			Constructor[] cons = c.getDeclaredConstructors();
			for(Constructor con : cons) {
				//获取修饰符,使用toString方法获取字符串型的
				System.out.print(Modifier.toString(con.getModifiers())+" ");
				System.out.print(con.getName()+"(");
				Class paras[] = con.getParameterTypes() ;
				for(int i=0;i<paras.length;i++) {
					System.out.print(paras[i].getSimpleName()+" args");
					if(i<paras.length-1) {
						System.out.print(",");
					}
				}
				System.out.println("){ }");
			}
			//获取无参构造的方法
			Constructor cs1 = c.getDeclaredConstructor() ;
			//创建无参构造的实例
			Object obj = cs1.newInstance() ;
			System.out.println("无参构造实例:"+obj.toString());
			
			//获取带一个参数的构造方法
			Constructor cs2 = c.getDeclaredConstructor(String.class) ;
		    Student e = (Student)cs2.newInstance("你好");
		    System.out.println("带一个参数的构造方法实例:"+e);
			
			
			//获取全参构造方法
			Constructor c1 = c.getDeclaredConstructor(String.class ,int.class,String.class) ;
			//因为这个构造方法是私有的所以需要获取权限
			c1.setAccessible(true);
			//创建c1构造方法的实例并强制类型转换
			Student e2 = (Student)c1.newInstance("ALOHA",22,"TG208") ;
			System.out.println(e2.toString());
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		
		
	}
}



结果:


Field成员变量类

    java.lang.reflect.Field包下,提供了getModifiers() 、getName() 、getType() 。

    获取成员变量的途径和获构造方法的途径相似,这里不再赘述。

获取成员变量后可以给成员变量进行赋值操作。获取变量值首先需要判断这个变量是否是私有的,如果是私有的我们需先获取权限:使用setAccessible(true) ;方法 。如果不是,直接获取即可。

获取:经实例化的对象可以使用get方法获取这个值,API提供了各种get不同类型的方法。

修改:


Demo:

package day22.Class;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;

public class getField {

	public static void main(String[] args) {
		
		try {
			Class c = Class.forName("day22.Class.Student") ;
			Field[] dfs = c.getDeclaredFields();
			for(Field df :dfs) {
				System.out.print(Modifier.toString(df.getModifiers())+" ");
				System.out.print(df.getType().getSimpleName()+" ");
				System.out.println(df.getName());
			}
			//获取无参构造
			Constructor cs = c.getConstructor();
			//用无参构造创建新的实例
			Student stu = (Student)cs.newInstance() ;
			//获取反射对象的name属性
			Field f = c.getDeclaredField("name") ;
			System.out.println("修改前:" + f.get(stu));
			//设置属性值为hello
			f.set(stu, "hello");
			//打印这个属性
			System.out.println("修改后:"+f.get(stu));
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}
}

结果:


获取成员方法



获取并打印所有方法Demo:

package day22.Class;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 获取一下sql包中Time类的所有方法
 * 
 * @author malaganguo
 *
 */
public class getMethod {

	public static void main(String[] args) {

		try {
			//创建获取字节码文件
			Class c = Class.forName("java.lang.String");
			//获取所有方法
			Method ms[] = c.getDeclaredMethods() ;
			for(Method m :ms) {
				//获取并打印修饰符
				System.out.print(Modifier.toString(m.getModifiers())+" ");
				//获取并打印返回值
				System.out.print(m.getReturnType().getSimpleName()+" ");
				//获取方法名
				System.out.print(m.getName()+"(");
				//获取参数
				Class<?>[] paras = m.getParameterTypes();
				for(int i=0;i<paras.length;i++) {
					//打印参数类型
					System.out.print(paras[i].getSimpleName()+" args ");
					if(i<paras.length-1) {
						System.out.print(",");
					}
				}
				System.out.print(") ");
				
				//如果有异常,获取并打印异常
				Class<?>[] et = m.getExceptionTypes();
				for(int i=0 ;i<et.length;i++) {
					if(et.length>0) {
						System.out.print(" throws ");
						System.out.println(et[i].getSimpleName());
						if(i<et.length-1) {
							System.out.println(" ,");
						}
				}
				
				}
				System.out.println();
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}

	}
}

结果(部分截屏):


反射的应用——动态代理

       使用动态代理可以让代理对象做事情,代理对象由InvocationHandler接口的实现并覆写接口中的唯一抽象方法——invoke(Object proxy, Method method, Object[] args)来实现。在覆写这个方法之前,我们需要手动创建目标代理对象,然后给这个目标代理对象提供一个公共的访问方法。

代码块:

Dao

package Dynamic_proxy;
/**
 *
 * 针对用户操作的接口
 * 		提供了增删改查的方法
 *
 */
public interface UserDao {

	public abstract void add() ;//增加
	public abstract void delete() ;//删除
	public abstract void update() ;//修改
	public abstract void find() ;//查询
}


DaoImpl

package Dynamic_proxy;

//ssh 老框架
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 find() {
		System.out.println("调用了查询功能");
	}

}

MyInvocationHandler

package Dynamic_proxy;

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

public class MyInvocationHandler implements InvocationHandler {

	//给生成对象设置代理对象
	private Object target ;

	public MyInvocationHandler(Object target) {
		super();
		this.target = target;
	}
	
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//这是代理做的事情
		System.out.println("校验程序");
		Object obj = method.invoke(target, args); //让target给args做代理
		System.out.println("日志记录");
		
		return obj;
	}

}

Test

package Dynamic_proxy;

import java.lang.reflect.Proxy;

public class Test {

	public static void main(String[] args) {
		
		//创建UserDao多态
		UserDao ud = new UserDaoImpl() ;
		//创建代理对象hander,给ud代理
		MyInvocationHandler hander = new MyInvocationHandler(ud) ;
		
		UserDao ud2 = (UserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), hander);
		ud2.add();
		ud2.delete();
		ud2.update();
		ud2.find();
	}
}

执行结果:



猜你喜欢

转载自blog.csdn.net/weixin_38930706/article/details/80600596