第十一章 反射1

概述

反射机制,就是通过一个抽象的类名能够在自己记忆(加载类的内存)中找到相匹配的类的具体信息
前提:jvm已经加载这个类,相当于人脑有了这个类的记忆
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
Java反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时调用任意一个对象的成员变量和方法
生成动态代理
实例化Class类对象(四种方法)

package day14;

public class Test {
	public static void main(String[] args) {
		Person p =new Person();
		
		Class c0 =Person.class;  //通过类名.class创建指定类的class实例
		Class c1 =p.getClass();  //通过一个类的实例对象.getclass方法获取对应实例对象的类的class实例
		try {
			//通过class的静态方法forname(string name)来获取一个类的class实例
			//参数是获取class类的全路径(包名.类名),常用
			Class c2=Class.forName("day14.Person");
		} catch (ClassNotFoundException e) {
		
			e.printStackTrace();
		}
		
	}
}

通过反射调用类的完整结构

实现的全部接口
所继承的父类
全部的构造器

package day14;

public class Person {
	String name;
	int age;
	
}

package day14;

public class Test {
	public static void main(String[] args) {
		Person p =new Person();
		
		Class c0 =Person.class;  //通过类名.class创建指定类的class实例
		Class c1 =p.getClass();  //通过一个类的实例对象.getclass方法获取对应实例对象的类的class实例
		try {
			//通过class的静态方法forname(string name)来获取一个类的class实例
			//参数是获取class类的全路径(包名.类名),常用
			Class c2=Class.forName("day14.Person");
		} catch (ClassNotFoundException e) {
		
			e.printStackTrace();
		}
		
	}
}

package day14;

public interface Move {
	void moveType();
}

package day14;

public interface Study {
	void studyInfo();
}
package day14

public class Student extends Person  implements Move,Study{
	public Student() {
		System.out.println("调用的是无参构造");
	}
	
	public Student(String school) {
		this.school=school;
		System.out.println("调用的String school构造");
	}
	private Student (String name,int age) {
		this.name=name;
		this.age=age;
		System.out.println("调用的是String name,int age构造");
	}
	String school;
	
	
	public void showInfo() {
		System.out.println("学校是"+this.school);
	}
	@Override
	public void studyInfo() {
		System.out.println("学习的知识");
		
	}

	@Override
	public void moveType() {
		System.out.println("骑自行车");
		
	}
	
}

package day14;

import java.lang.reflect.Constructor;

public class Test1 {
	public static void main(String[] args) {
		try {
			Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
			
			Class superClazz=clazz.getSuperclass();//获取父类
			System.out.println(superClazz.getName());
			
			Class[] inclazz=clazz.getInterfaces();//获取当前类的接口
			for(Class c:inclazz) {
				System.out.println(c);
			}
			
//			Constructor[]cons=clazz.getConstructors();//获取公有的构造方法,private修饰的获取不到
//			//getModifiers()返回数字1代表public,2代表private
//			
//			for(Constructor c:cons) {
//				System.out.println("构造方法名称是"+c.getName()+"构造修饰符是 "+c.getModifiers());
//				Class[]cc=c.getParameterTypes();//参数类型
//				for(Class s:cc) {
//					System.out.println("构造方法名称是"+c.getName()+"的参数类型是 "+s.getName());
//				}
//				//System.out.println(c.getParameterTypes());
//			}
			
			
			Constructor[] conss =clazz.getDeclaredConstructors();//获取所有的构造方法
			for(Constructor c:conss) {
				System.out.println("构造方法名称是"+c.getName()+"构造修饰符是 "+c.getModifiers());
				Class[]cc=c.getParameterTypes();//参数类型
				for(Class s:cc) {
					System.out.println("构造方法名称是"+c.getName()+"的参数类型是 "+s.getName());
				}
			}
			
			
			
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		
	}
}

通过反射的方法创建对象

package day14;

import java.lang.reflect.Constructor;

public class Test1 {
	public static void main(String[] args) {
		try {
			Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例

			try {
				Object obj =clazz.newInstance(); //相当于调用Student类的无参共有的构造方法
				Student stu =(Student)obj ; //把obj强转,这样就可以输出了,输出的是 调用的是无参构造
				
				Constructor c=	clazz.getConstructor(String.class);//指定一获取一个参数并且为string类型的构造方法
				Object obj1=c.newInstance("第一中学");//newInstance实例化对象
				Student stu1 =(Student)obj1;
				System.out.println(stu1.school);
				
				//通过反射机制,可以强制的调用私有的构造方法
				Constructor c1=clazz.getDeclaredConstructor(String.class,int.class);//指定两个参数的构造方法
				c1.setAccessible(true);//解除私有封装,下面就可以对私有方法强制调用
				Student stu2=(Student)c1.newInstance("张三",12);
				
			} 
			catch (Exception e) {
				
				e.printStackTrace();
			}
			
			
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		
	}
}

全部的方法

package day14;

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

public class Test1 {
	public static void main(String[] args) {
		try {
			Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例

			try {
	
				//Method[] ms=clazz.getMethods();  //获取所有共有的的方法
				Method[] ms=clazz.getDeclaredMethods();
				for(Method m:ms) {
					System.out.println("方法名"+m.getName());
					System.out.println("返回值类型"+m.getReturnType());
					System.out.println("修饰符"+m.getModifiers());
					Class[]c=m.getParameterTypes();
					if(c!=null&&c.length>0) {
						for(Class cs:c) {
							System.out.println("参数类型"+ cs.getName());
						}
					}
					
					System.out.println("===========================");
				}
			} 
			catch (Exception e) {
				
				e.printStackTrace();
			}
			
			
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		
	}
}

全部的Field(属性)

package day14;

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

public class Test1 {
	public static void main(String[] args) {
		try {
			Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例

			try {
	
		
				
				//Field[] f=clazz.getFields();//获取所有公有属性,包括父类的
				Field[] f=clazz.getDeclaredFields();//获取所有属性包括私有属性,不包含父类的
				for(Field fs:f) {
					System.out.println("修饰符是"+fs.getModifiers());
					System.out.println("属性的类型"+fs.getType());
					System.out.println("属性的名称是"+fs.getName());
				}
				Package  p=clazz.getPackage(); //获取类所在的包
				System.out.println(p.getName());
			} 
			catch (Exception e) {
				
				e.printStackTrace();
			}
			
			
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		
	}
}

通过反射调用类中的指定方法、指定属性

指定方法

package day14;

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

public class Test1 {
	public static void main(String[] args) {
		try {
			Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
/**
 * 注意,下面不论是反射调用哪个方法都是调用obj对象的方法,实际上就是调用student对象
 */
			try {
				//Constructor con =	clazz.getConstructor();//获取无参构造
				//Object obj=con.newInstance();//使用无参构造创建对象(这两行等于下边一行)
				Object obj=clazz.newInstance(); //使用无参构造创建对象
				
				//名称setSchool 参数是string,string的方法
				Method m =clazz.getMethod("setSchool",String.class,String.class);
				m.invoke(obj, "张三","第一中学"); //,调用方法,参数一是实例化的对象,后面参数是当前方法的参数
				
				//如果想要调用私有方法
				Method m1 =clazz.getDeclaredMethod("test", String.class);//获取方法名为test参数为String的方法
				m1.setAccessible(true);//解除私有方法封装
				m1.invoke(obj, "李四");
				
				//重载一个setSchool方法
				Method m2 =clazz.getDeclaredMethod("setSchool", int.class);//重载方法
				m2.invoke(obj, 1);
				
				//有返回值的方法
				Method m3 =clazz.getDeclaredMethod("getSchool");//获取方法
				String school =(String) m3.invoke(obj); //调用有返回值没有参数的的方法,强转
				System.out.println(school);//输出是第一中学,因为上边setSchool赋值了,这里返回来了
			} 
			catch (Exception e) {
				
				e.printStackTrace();
			}
			
			
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		
	}
}

指定属性

package day14;

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

public class Test1 {
	public static void main(String[] args) {
		try {
			Class clazz=Class.forName("day14.Student");//通过包名.类名的字符串,调用forname方法获取指定类的class实例
		try {
			//反射创建对象
				Constructor con =clazz.getConstructor();
				Student stu =(Student) con.newInstance();
				
				Field f =clazz.getField("school"); //获取名为school的属性
				f.set(stu, "第三中学");//对stu对象的school属性设置值 第三中学
				String s=(String) f.get(stu); //获取stu对象的school属性的值
				System.out.println(s);
				
				//私有的属性
				Field f1 =clazz.getDeclaredField("fied");//获取私有属性
				f1.setAccessible(true);
				f1.set(stu, "测试私有属性");
				String ss=(String) f1.get(stu);
				//f1.setAccessible(true); 写在这个位置就不行,写上面就行
				System.out.println(ss);
			} 
			catch (Exception e) {
				
				e.printStackTrace();
			}
			
			
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		
	}
}

Java动态代理

一个java项目,其中有100java类,每个java有1000个方法,总共100个方法。需要在每个方法上加上两句话,在方法执行前输出这个方法开始执行,在方法之后输出方法结束。
动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。
2.创建被代理的类以及接口

3.通过Proxy的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个Subject接口代理
4.通过 Subject代理调用RealSubject实现类的方法

package day14;

public interface ITestDemo {
	void test1();
	void test2();
}

package day14;

public class TestDemoImpl implements ITestDemo {

	@Override
	public void test1() {
		System.out.println("执行test1方法");

	}

	@Override
	public void test2() {
		System.out.println("执行test2方法");
	}

}

package day14;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 动态代理类
 * @author xrh
 *
 */
public class ProxyDemo implements InvocationHandler{

	
	Object obj ; //被代理的对象
	
	public ProxyDemo(Object obj) {
		this.obj=obj;
		
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		System.out.println(method.getName()+"方法开始执行");
		
		Object result=method.invoke(this.obj, args);//执行指定代理对象的指定方法,可能会有返回值所以要接收
		
		System.out.println(method.getName()+"方法执行完毕");
		
		return result;
	}

}

package day14;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Test2 {
	public static void main(String[] args) {
		ITestDemo test =new TestDemoImpl(); //对象多态
		/**
		 * 一个对象想要通过Proxy.newProxyInstance方法被代理 
		 * 那么这个对象的类一定要有相应的接口,
		 * 就像这里TestDemoImpl类有一个ITestDemo接口
		 */
		test.test1();
		test.test2();
	System.out.println("=============================");	
		/**
		 * 每个执行方法时加入东西
		 */
		//ProxyDemo实现的接口是InvocationHandler,所以可以这样new,接口的多态,参数就是代理对象
		InvocationHandler handler =new ProxyDemo(test); 
		
		//第一个参数类加载器,第二个参数被代理的对象的接口,参数三是代理对象,返回的值是成功被代理后的对象
		ITestDemo t=(ITestDemo) Proxy.newProxyInstance(handler.getClass().getClassLoader(), test.getClass().getInterfaces(), handler);
		//返回的是object类型,需要根据情况转化类型
		
		
		t.test1();
		t.test2();
	}
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值