JAVA反射机制是在运行状态中,对于任意一个类,都可以知道这个类的全部属性和方法;对于任意一个对象,都可以调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。java
新建测试类: public class Dog implements Animal { private String name; String color; @Override public void say() { System.out.println("dog..say.."); } public void run(){ System.out.println("dog..run.."); } public void eat(String S){ System.out.println("dog..eat.."+S); } //.... public Dog() { } public Dog(String name, String color) { this.name = name; this.color = color; } }
1.Class是一个类,封装了当前对象所对应的类的信息
2.一个类中有属性,方法,构造器等,好比说有一个Person类,一个Order类,这些都是不一样的类,如今须要一个类,用来描述类,这就是Class,
它应该有类名,属性,方法,构造器等。Class是用来描述类的类。
3.对于每一个类而言,JRE 都为其保留一个不变的 Class 类型的对象。
4.Class 对象只能由系统创建对象,一个类(而不是一个对象)在 JVM 中只会有一个Class实例。bootstrap
@Test public void test5(){ Class clazz1=Dog.class; Class clazz2=Dog.class; System.out.println(clazz1); System.out.println(clazz2); System.out.println(clazz1==clazz2);//true }
获取Class对象的三种方式:
1.经过类名获取 类名.class
Class clazz=Dog.class;
2.经过对象获取 对象名.getClass()
Dog dog=new Dog();
Class clazz=dog.getClass();
3.经过全类名获取 Class.forName(全类名)
Class clazz=Class.forName("com.utils.Dog");数组
Class类的经常使用方法:ide
方法名函数 |
功能说明工具 |
static Class forName(String name)测试 |
返回指定类名 name 的 Class 对象ui |
Object newInstance()this |
调用缺省构造函数,返回该Class对象的一个实例spa |
Object newInstance(Object []args) |
调用当前格式构造函数,返回该Class对象的一个实例 |
getName() |
返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 |
Class getSuperClass() |
返回当前Class对象的父类的Class对象 |
Class [] getInterfaces() |
获取当前Class对象的接口 |
ClassLoader getClassLoader() |
返回该类的类加载器 |
Class getSuperclass() |
返回表示此Class所表示的实体的超类的Class |
类装载器是用来把类(class)装载进 JVM 的。JVM 规范定义了两种类型的类装载器:启动类装载器(bootstrap)和用户自定义装载器(user-defined class loader)。 JVM在运行时会产生3个类加载器组成的初始化加载器层次结构。
Reflection(反射)是Java被视为动态语言的关键,反射机制容许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操做任意对象的内部属性及方法。
Java反射机制主要提供了如下功能:
在运行时构造任意一个类的对象
在运行时获取任意一个类所具备的成员变量和方法
在运行时调用任意一个对象的方法(属性)
生成动态代理
1.获取对象中的method public void test() throws Exception { //获取Dog.class的对象 Class dogClass=Dog.class; //获取Dog.class全部的方法,包括父类方法,不包括私有方法 //Method[] methods=dogClass.getDeclaredMethods(); //获取Dog.class全部的方法,包括私有方法,不包括父类方法 Method[] methods=dogClass.getDeclaredMethods(); for(Method method:methods){ System.out.println(method.getName()); } //返回该Class对象的一个实例 Object objects= dogClass.newInstance(); //获取无参方法 say( ) Method method=dogClass.getDeclaredMethod("say"); //第一个参数表示执行哪一个对象的方法,剩下的参数是执行方法时须要传入的参数 method.invoke(objects,null); //获取带参方法 eat( ),参数类型为String.class method=dogClass.getDeclaredMethod("eat",String.class); method.invoke(objects,"骨头"); }
2.获取对象中的field public void test() throws Exception{ Class clazz=Dog.class; //获取全部字段属性,包括私有,不包括继承 Field fields[]= clazz.getDeclaredFields(); for (Field field:fields){ System.out.println(field.getName()+"---"+field.getType()); } //获取全部继承字段属性 fields = clazz.getFields(); for (Field field:fields){ System.out.println(field.getName()+"---"+field.getType()); } //获取非私有字段属性 Field field=clazz.getDeclaredField("color"); Object object=new Dog(); //设置字段属性值 field.set(object,"red"); System.out.println("field.get(object)="+field.get(object)); //获取私有字段属性 field=clazz.getDeclaredField("name"); object=new Dog(); field.setAccessible(true); //设置字段属性值 field.set(object,"tom"); System.out.println("field.get(object)="+field.get(object)); }
3.获取对象的构造方法 public void test() throws Exception{ Class clazz=Dog.class; //获取全部构造函数 Constructor[] constructors= clazz.getConstructors(); for (Constructor constructor:constructors){ System.out.println(constructor); } //获取无参构造方法 Constructor constructor= clazz.getConstructor(new Class[]{}); System.out.println("无参构造 "+constructor); constructor=clazz.getConstructor(new Class[]{String.class,String.class}); System.out.println("带参构造 "+constructor); }
5.看到这里,咱们本身动手设计一个工具方法。 //自定义反射方法 类对象和类方法名做为参数,执行方法 public Object myInvoke(Class object,String methodName,Object...args) throws Exception, InstantiationException { //把参数转化为对应的class对象 Class[] argsClass=new Class[args.length]; for (int i=0;i<args.length;i++){ argsClass[i]=args[i].getClass(); System.out.println(argsClass[i]); } //获取方法 Method method=object.getDeclaredMethod(methodName,argsClass); //执行方法 return method.invoke(object.newInstance(),args); } 测试: public void test() throws Exception { Object args[]=new Object[]{}; Object result= myInvoke(Dog.class,"say",args); System.out.println("result="+result); }
6.咱们再设计一个工具方法,不但能访问当前类的私有方法,还要能访问父类的私有方法 通常使用getDeclaredMethod获取方法(由于此方法能够获取类的私有方法,可是不能获取父类方法),如何获取父类方法呢? public Method getMethodForClass(Class clazz,String methodName,Class[] parameterTypes) throws NoSuchMethodException { for(;clazz != Object.class; clazz = clazz.getSuperclass()){ try { Method method = clazz.getDeclaredMethod(methodName, parameterTypes); if(method==null){ continue; } return method; } catch (Exception e) { System.out.println(e); } } return clazz.getDeclaredMethod(methodName, parameterTypes); }
第四步:文章小结 1. Class: 是一个类; 一个描述类的类.封装了描述方法的 Method,描述字段的 Filed,描述构造器的 Constructor 等属性. 2. 如何获得 Class 对象: 2.1 Person.class 2.2 person.getClass() 2.3 Class.forName("com.atguigu.javase.Person") 3. 关于 Method: 3.1 如何获取 Method: 1). getDeclaredMethods: 获得 Method 的数组. 2). getDeclaredMethod(String methondName, Class ... parameterTypes) 3.2 如何调用 Method 1). 若是方法是 private 修饰的, 须要先调用 Method 的 setAccessible(true), 使其变为可访问 2). method.invoke(obj, Object ... args); 4. 关于 Field: 4.1 如何获取 Field: getField(String fieldName) 4.2 如何获取 Field 的值: 1). 若是Field是 private 修饰的, 须要先调用 Field 的 setAccessible(true),setAccessible(true) 2). field.get(Object obj) 4.3 如何设置 Field 的值: field.set(Obejct obj, Object val) 5. 了解 Constructor