java --反射
java --反射
求是科技 发表于1年前
java --反射
  • 发表于 1年前
  • 阅读 36
  • 收藏 4
  • 点赞 0
  • 评论 1

腾讯云 技术升级10大核心产品年终让利>>>   

反射是动态语言的关键。
反射机制提供的功能
1.在运行时判断一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断一个类的成员变量与方法
4.在运行时调用一个对象的成员变量与方法
5.生成动态代理
#1.反射简单应用

	public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
		/**常规方法:创建一个类的对象,并调用其中的方法**/
		Person p1 = new Person();
		p1.setName("张三");
		p1.setAge(30);
		System.out.println(p1);
		p1.dothing();
		
		/***反射实现**/
		Class<?> clazz = Person.class;
		//1.创建clazz对应的运行时类Person的对象
		Person p2 = (Person) clazz.newInstance();
		//此时p2对象的属性都是默认值
		System.out.println(p2);
		//2.获取p2对象的属性(共有权限)
		Field f1 = clazz.getField("name");
		//3.给属性赋值
		f1.set(p2, "李四");
		//此时p2对象的name有值了
		System.out.println(p2);
		//4.获取p2对象的属性(私有权限)
		Field f2 = clazz.getDeclaredField("age");
		//设置权限
		f2.setAccessible(true);
		f2.set(p2, 31);
		//此时p2对象的name与age均有值了
		System.out.println(p2);
		//5.获取p2对象的方法(无参方法)
		Method m1 = clazz.getMethod("dothing");
		//调用方法
		m1.invoke(p2);
		//6.获取p2对象的方法(有参方法)
		Method m2 = clazz.getMethod("dothing2", String.class);
		//调用方法
		m2.invoke(p2, "王五");
	}

Person类如下

public class Person {
	public String name;
	private int age;
	//无参方法
	public void dothing(){
		System.out.println("我是中国人");
	}
	//有参方法
	public void dothing2(String name){
		System.out.println("我是:"+name);
	}
}

#2.详讲Class

	/**
	 * java.lang.Class:是反射的源头
	 * 有三种方法获取Class类的实例
	 * @throws ClassNotFoundException 
	 */
	public static void main(String[] args) throws ClassNotFoundException {
		//方法1:调用运行时类本身的.class属性
		Class clazz1 = Person.class;
		System.out.println(clazz1.getName());
		//举例(jdk自带的类也行)
		Class clazz2 = String.class;
		System.out.println(clazz2.getName());
		
		//方法2:通过运行时类的对象获取
		Person p1 = new Person();
		Class clazz3 = p1.getClass();
		System.out.println(clazz3.getName());
		
		//方法3:通过Class的静态方法获取
		String className = "com.test.reflect.Person";
		Class<?> clazz4 = Class.forName(className);
		System.out.println(clazz4.getName());
	}

#3.ClassLoader
类加载器是用来把类(class)装载进内存的。
jvm定义了两种类型的类加载器:启动类加载器(bootstrap)和用户自定义类加载器。jvm在运行时会产生三个类加载器,引导类加载器(bootstrap)、扩展类加载器(extension)、系统类加载器(system)。

	@Test
	public void test() throws ClassNotFoundException, IOException{
		//获取系统类加载器
		ClassLoader loader1 = ClassLoader.getSystemClassLoader();
		//sun.misc.Launcher$AppClassLoader@73d16e93
		System.out.println(loader1);
		
		//获取系统类加载器的父级
		ClassLoader loader2 = loader1.getParent();
		//sun.misc.Launcher$ExtClassLoader@15db9742
		System.out.println(loader2);
		
		//查看Person类是由哪个加载器加载
		Class<?> clazz1 = Person.class;
		ClassLoader loader4 = clazz1.getClassLoader();
		//sun.misc.Launcher$AppClassLoader@73d16e93
		System.out.println(loader4);
		
		//查看系统类是由哪个类加载器加载
		String className = "java.lang.Object";
		Class<?> clazz2 = Class.forName(className);
		ClassLoader loader5 = clazz2.getClassLoader();
		//打印null,因为Object是属于系统类,应该由系统类加载器加载,在初始化加载一次
		System.out.println(loader5);
		
		//获取属性文件的值
		//方法1:属性文件在工程的某个包下
		//ClassLoader loaderWay1 = this.getClass().getClassLoader();
		//InputStream is = loaderWay1.getResourceAsStream("com\\test\\reflect\\db1.properties");
		
		//方法2:属性文件存放在src目录下
		//FileInputStream is = new FileInputStream(new File("src\\db2.properties"));
		
		//方法3:属性文件存放在工程路径下
		FileInputStream is = new FileInputStream(new File("db3.properties"));
		//公共部分
		Properties pros = new Properties();
		pros.load(is);
		String name = pros.getProperty("user_name");
		String password = pros.getProperty("user_password");
		System.out.println(name+":"+password);
	}

属性文件所在位置图
输入图片说明
#4.反射的实际应用
##1.创建运行时类的对象
调用Class类的newInstance()方法,可以创建类的对象。

	public void test() throws ClassNotFoundException, IOException, InstantiationException, IllegalAccessException{
		String name = "com.test.reflect.Person";
		Class<?> clazz = Class.forName(name);
		//1.创建运行时类的对象,newInstance调用了Person的无参构造器
		Object obj = clazz.newInstance();
		Person p = (Person) obj;
		System.out.println(p);
	}

##2.获取类的属性、方法

	/**
	 * 获取对应的运行时类的属性
	 */
	@Test
	public void test(){
		Class<?> clazz = Person.class;
		//1.getFields:可以获取本类及父类中申明为public的属性
		Field[] f = clazz.getFields();
		for(Field fTmp:f){
			System.out.println(fTmp.getName());
		}
		//2.getDeclaredFields:可以获取本类中所有的属性
		Field[] f2 = clazz.getDeclaredFields();
		for(Field fTmp2:f2){
			System.out.println(fTmp2.getName());
		}
		
	}

Person类

/**
 * 单继承,多实现
 */
public class Person extends Nature implements MyInterface,Serializable{
	
	private static final long serialVersionUID = 1L;
	public String name;
	private int age;
	int id;
}

Nature类

public class Nature {
	public double weight;
	//方法
	public void breath(){
		System.out.println("呼吸");
	}
}

MyInterface接口

public interface MyInterface {

	public void show();
}

##3.获取权限修饰符/变量类型/变量名

	@Test
	public void test(){
		Class<?> clazz = Person.class;
		Field[] f = clazz.getDeclaredFields();
		for(Field fTmp:f){
			//1.获取属性权限修饰符
			int i = fTmp.getModifiers();
			//将整型转成实际的权限
			String cc = Modifier.toString(i);
			System.out.print(cc+" ");
			//2.获取属性的变量类型
			Class type = fTmp.getType();
			System.out.print(type.getName()+" ");
			//3.获取属性名
			System.out.print(fTmp.getName());
			//换行
			System.out.println();
		}
	}

##4.获取运行时类的方法

	@Test
	public void test(){
		Class<?> clazz = Person.class;
		//1.getMethods:获取运行时类及其父类中所有的public方法
		Method[] methods = clazz.getMethods();
		for(Method m:methods){
			System.out.println(m);
		}
		//2.getDeclaredMethods:获取运行时类本身所申明的方法
		Method[] methods2 = clazz.getDeclaredMethods();
		for(Method m2:methods2){
			System.out.println(m2.getName());
		}
	}

##5.获取运行时类的方法权限修饰符/返回值类型/方法名

	@Test
	public void test(){
		Class<?> clazz = Person.class;
		Method[] methods2 = clazz.getDeclaredMethods();
		for(Method m2:methods2){
			//1.获取权限修饰符
			String str = Modifier.toString(m2.getModifiers());
			System.out.print(str);
			//2.返回值类型
			Class returnType = m2.getReturnType();
			System.out.print(returnType.getName());
			//3.方法名
			System.out.print(m2.getName());
		}
	}

##6.获取运行时类的构造器

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		//获取Person类的所有的构造器
		Constructor[] cons = clazz.getDeclaredConstructors();
		for(Constructor c:cons){
			System.out.println(c.getName());
		}
	}

##7.获取运行时类的父类/带泛型的父类

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		Class superClass = clazz.getSuperclass();
		System.out.println(superClass);
	}

##8.获取运行时类的接口

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		Class[] interfaces = clazz.getInterfaces();
		for(Class i:interfaces){
			System.out.println(i);
		}
	}

##9.获取运行时类的包

	@Test
	public void test() throws ClassNotFoundException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		Package pack = clazz.getPackage();
		System.out.println(pack);
	}

#5.通过反射调用类中指定方法/指定属性

	/**
	 * 调用运行时类中指定的属性
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalArgumentException 
	 */
	@Test
	public void test() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException{
		String className = "com.test.reflect.Person";
		Class clazz = Class.forName(className);
		/***获取运行时类对象***/
		//1.创建运行时类的对象
		Person p = (Person) clazz.newInstance();
		System.out.println(p);
		/***获取指定属性***/
		//2.获取指定的属性(公有属性)
		Field name = clazz.getField("name");
		//2.1给指定属性赋值(公有属性)
		name.set(p, "张三");
		//3.获取指定属性(私有属性)
		Field age = clazz.getDeclaredField("age");
		//3.1修改私有属性的可访问权限
		age.setAccessible(true);
		//3.2给指定属性赋值(私有属性)
		age.set(p, 30);
		System.out.println(p);
		/***获取指定方法***/
		Method m1 = clazz.getMethod("show");
		//调用指定方法
		Object obj = m1.invoke(p);
		//如果obj==null,则说明该方法返回void
		System.out.println(obj);
		
		//调用静态方法
		Method m2 = clazz.getMethod("testStatic");
		Object obj2 = m2.invoke(Person.class);
		System.out.println(obj2);
	}

#6.反射应用之动态代理
动态代理是指用户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态地创建目标类的代理对象。 动态代理使用场合:调试、远程方法调用
代理设计模式原理
1.使用一个代理将对象包装起来
2.使用该代理对象取代原始对象
3.任何对原始对象的调用都要经过代理对象
4.代理对象决定是否/何时将方法的调用转到原始对象上
##6.1静态代理

/**
 * 静态代理模式
 */
public class TestDelegate {
	public static void main(String[] args) {
		//被代理类
		NikeClothFactory ncf = new NikeClothFactory();
		//代理类
		ProxyFactory proxy = new ProxyFactory(ncf);
		//调用方法
		proxy.productCloth();
	}
}

接口

//接口
interface ClothProduct{
	void productCloth();
}

被代理类

//被代理类
class NikeClothFactory implements ClothProduct{

	@Override
	public void productCloth() {
		System.out.println("nike工厂生产衣服");
	}
}

代理类

//代理类
class ProxyFactory implements ClothProduct{

	//创建接口
	ClothProduct cp;
	//构造器
	//创建代理类的对象,实际传入的是一个被代理的对象
	//该构造器的功能:完成被代理类的初始化
	public ProxyFactory(ClothProduct cp) {
		this.cp = cp;
	}
	@Override
	public void productCloth() {
		System.out.println("代理类执行");
		cp.productCloth();
	}
}

##6.2动态代理

/**
 * 动态代理模式
 */
public class TestProxyDelegate {
	public static void main(String[] args) {
		//1.被代理类对象
		RealSubject rsj = new RealSubject();
		//2.代理类对象
		MyInvocationHandler mih = new MyInvocationHandler();
		//3.传入被代理类,动态返回一个代理对象
		Object obj = mih.blind(rsj);
		//4.强转,此时的sb就是代理类的对象
		Subject sb = (Subject) obj;
		//5.执行被代理类方法,此时会转成去执行代理类的invoke方法
		sb.action();
		
		//再举一例
		NikeClothFactory nike = new NikeClothFactory();
		Object obj2 = mih.blind(nike);
		ClothProduct cp = (ClothProduct) obj2;
		cp.productCloth();
		
	}
}

接口

//接口
interface Subject{
	void action();
}

被代理类

//被代理类
class RealSubject implements Subject{

	@Override
	public void action() {
		System.out.println("我是被代理类");
	}
}

动态代理类

//动态代理类
class MyInvocationHandler implements InvocationHandler{
	//定义一个类,表示实现了接口的类(即被代理类)
	Object obj;
	
	//实例化被代理的类
	//返回一个代理类的对象
	//方法名随便命名
	public Object blind(Object obj){
		//1.实例化被代理的类
		this.obj = obj;
		//2.返回一个代理类
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
	}
	/**
	 * 代理类的对象调用被代理类的方法时,会转换为对如下invoke方法的调用
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		//1.获取被代理类执行的方法名称
		String methodName = method.getName();
		System.out.println("被代理类执行的方法名称:"+methodName);
		//2.获取被代理类执行的方法的参数
		if (args != null) {
			for(Object arg:args){
				System.out.println(arg);
			}
		}
		//3.被代理类执行方法返回值
		Object returnVal = method.invoke(obj, args);
		System.out.println(returnVal);
		return returnVal;
	}
}
共有 人打赏支持
粉丝 87
博文 438
码字总数 222864
评论 (1)
业余编程人士
请问一下 反射提取Field的时候 可以判断哪些是 int, double, final 或者 static类型吗?
×
求是科技
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: