- 一.反射机制
- Class类
package hellojava.day14; public class Test { public static void main(String[] args) {//实例化class类对象的四种方法 Person p=new Person(); Class clazz=p.getClass();// clazz对象中就包含对象P所属的Person类的所有信息 Class c0=Person.class;//通过类名,class创建指定类的class实例 Class c1=p.getClass();//通过一个类的实例对象的getClass()方法,获得对应实例对象的类的class实例 try { Class C2=Class.forName("day14.Person");//通过 Class的静态方法forName("day14.Person");方法获取 // 一个类的Class实例 //forName("day14.Person")方法中的参数是呢要获取的class实例的全路径(包名.类名) } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
- 通过反射调用类的完整结构(Field Method Constructor Superclass Interface Annotation) package hellojava.day14;public class Person { } public class Student extends Person implements Move,Study{ String school; public void showInfo(){ System.out.println("学校是:"+this.school); } @Override public void moveType() { System.out.println("骑自行车上学"); } @Override public void studyInfo() { System.out.println("学习的是大学的知识"); } }
package hellojava.day14; public interface Move { void moveType(); }
package hellojava.day14; public interface Study { void studyInfo(); }
package hellojava.day14; public class Person { String name; int age; } public class Test1 { public static void main(String[] args) { try {//通过包名.类名的字符串,调用calss.forname方法获取指定类的class实例 Class clazz=Class.forName("hellojava.day14.Student"); Class superClazz = clazz.getSuperclass();//获取父类 System.out.println("父类:"+superClazz.getName()); Class[] interfaces= clazz.getInterfaces();//获取当前所有接口 for (Class c:interfaces){ System.out.println("接口:"+c.getName()); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
获取构造器
import java.lang.reflect.Constructor; public class Test1 { public static void main(String[] args) { try {//通过包名.类名的字符串,调用calss.forname方法获取指定类的class实例 Class clazz=Class.forName("hellojava.day14.Student"); Class superClazz = clazz.getSuperclass();//获取父类 System.out.println("父类:"+superClazz.getName()); Class[] interfaces= clazz.getInterfaces();//获取当前所有接口 for (Class c:interfaces){ System.out.println("接口:"+c.getName()); } Constructor[] cons= clazz.getConstructors();//获取到类公有的构造方法 for (Constructor c:cons){ System.out.println("构造方法名称:"+c.getName());//获取方法名称 //getModifiers()获取方法修饰符返回数组1代表public System.out.println("构造方法名称:"+c.getName()+"的修饰符是:"+c.getModifiers());//获取方法修饰符 Class[] paramClazz =c.getParameterTypes(); for (Class pc:paramClazz){ System.out.println("构造方法名称:"+c.getName()+"的参数类型是:"+pc.getName()); } } Constructor[] cons1 =clazz.getDeclaredConstructors();//获取所有类的构造方法 for (Constructor c:cons1){ System.out.println("------------------------------"); System.out.println("构造方法名称:"+c.getName());//获取方法名称 //getModifiers()获取方法修饰符返回数组1代表public,返回数字2代表private System.out.println("构造方法名称:"+c.getName()+"的修饰符是:"+c.getModifiers()); Class[] paramClazz =c.getParameterTypes();//获取构造方法的参数类型,有几个参数就有几个 for (Class pc:paramClazz){ System.out.println("构造方法名称:"+c.getName()+"的参数类型是:"+pc.getName()); } System.out.println("------------------------------"); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
用反射的构造方法来创建对象
//如果用反射的构造方法来创建对象 try { Object obj= clazz.newInstance();//相当于调用 Student()类的无参公有的构造方法 Student stu=(Student)obj; Constructor c=clazz.getConstructor(String.class);//指定获取有一个参数并且为String类型的公有构造 Student stu1= ( Student)c.newInstance("第一中学");//newInstance实例化对象 System.out.println(stu1.school); //通过反射机制,可以强制的调用私有的构造方法 Constructor c1=clazz.getDeclaredConstructor(String.class,int.class);//指定获取有两个参数(String int)的构造方法 c1.setAccessible(true);//解除私有的封装,下面就可以对这个私有方法强制调用 Student stu2= ( Student)c1.newInstance("长得三",12); System.out.println(stu2.school); } catch (Exception e) { e.printStackTrace(); }
Method[] ms=clazz.getMethods();//获取到类的所有公有的方法
//Method[] ms1=clazz.getDeclaredMethods();//获取到类的所有方法
for (Method m:ms){ System.out.println("方法名:"+m.getName()); System.out.println("返回值类型:"+m.getReturnType()); System.out.println("修饰符:"+m.getModifiers()); Class[]pcs= m.getParameterTypes();//获取方法的参数类型,是一个数组,方法有几个参数,数据就有几个元素 if (pcs!=null&&pcs.length>0){ for (Class pc:pcs){ System.out.println("参数类型:"+pc.getName()); } } System.out.println("=================================");
Field[] fs=clazz.getFields();//获取类公有的属性,包含父类 // Field[] fs=clazz.getDeclaredFields();//获取本类(不包含父类)所有的属性包含私有属性 for (Field f:fs){ System.out.println("修饰符"+f.getModifiers()); System.out.println("属性的类型"+f.getType()); System.out.println("属性的名称"+f.getName()); }
类所在的包
Package p=clazz.getPackage();//获取类所在的包 System.out.println(p.getName());
通过反射调用类中的指定方法
在上面代码Student类中加入如下代码
private void test(String name){ System.out.println("这个是test(String name)私有方法"); } public String getSchool(){ return this.school; } public void setInfo(String name,String school){ this.name=name; this.school=school; System.out.println("这个是setInfo(String name,String school){方法"); } public void setInfo(int age){ this.name=name; this.school=school; System.out.println("这个是setInfo(int age){方法"); }
在Test1类中写调用测试
//下面不论是反射调用setinfo还是test方法都是调用的obj的方法 // obj对象实际上就是student对象 Constructor con=clazz.getConstructor();//获取无参构造 Object obj=con.newInstance();//使用无参构造创建对象 Method m= clazz.getMethod("setInfo",String.class,String.class); //得到名称setInfo的方法参数是String String m.invoke(obj,"dg","大威德");//参数1.是实例化对象,2.是调用当前方法的实际参数 //如果想要调用一个私有的方法 Method m1=clazz.getDeclaredMethod("test",String.class);//获取方法名test参数为String类型的方法 m1.setAccessible(true);//解除私有封装,下面可以强制使用 m1.invoke(obj,"斩杀"); //调用一个重载方法 Method m2=clazz.getDeclaredMethod("setInfo",int.class);//setInfo的重载方法 m2.invoke(obj,1); //有返回值的方法 Method m3=clazz.getMethod("getSchool");//sgetSchool的没有参数的方法 String school=(String) m3.invoke(obj);//调用有返回值但是无参数的方法 System.out.println(school); } catch (Exception e) { e.printStackTrace(); }
调用指定属性
//反射创建一个对象 Constructor con1=clazz.getConstructor(); Student stu1=(Student)con.newInstance(); Field f=clazz.getField("school");//获取名称为school属性 f.set(stu1,"第三中学");//对stu1对象的school属性设置值"第三中学" String school1=(String) f.get(stu1);//获取stu1对象的school属性值 System.out.println(school1); //如果是私有属性 Field f1=clazz.getDeclaredField("privateField"); f1.setAccessible(true);//解除私有的封装,以便强制调用 f1.set(stu1,"测试私有属性"); System.out.println(f1.get(stu1));
Java的动态代理
package hellojava.day14; public interface ITestDemo { void test1(); void test2(); }
public class TestDemoImpl implements ITestDemo { public TestDemoImpl() { super(); } @Override public void test1() { System.out.println("执行test1"); } @Override public void test2() { System.out.println("执行test2"); } }
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; //动态代理类 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; } }
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被代理,那么这个对象类一定要有相应的接口 // 就像本案例中TestDemo接口和实现类TestDemoImpl test.test1(); test.test2(); System.out.println("============================================"); //需求在执行test1和test2方法时需要加入一些东西,在执行方法前打印test1或test2开始执行 //在执行方法后打印test1或test2执行完毕打印的方法要和当时调用方法保持一致 InvocationHandler handler=new ProxyDemo( test); //Proxy.newProxyInstance()有三个参数,参数1是代理对象的类加载器参数二是被代理的对象的接口 //参数三是代理对象 返回值就是成功被代理的对象,返回的是object类型,需要根据当前的情况类型转换 ITestDemo t=(ITestDemo) Proxy.newProxyInstance(handler.getClass().getClassLoader(),test.getClass().getInterfaces(),handler); t.test1(); System.out.println("============================================"); t.test2(); } } 测试输出