java 反射机制

 java的反射机制
反射机制是什么
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字, 那么就可以通过反射机制来获得类的所有信息。 

反射机制能做什么
反射机制主要提供了以下功能: 

在运行时判断任意一个对象所属的类;
在运行时构造任意一个类的对象;
在运行时判断任意一个类所具有的成员变量和方法;
在运行时调用任意一个对象的方法;
生成动态代理(了解)

反射机制的优点与缺点

为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态编译与静态编译的概念, 

静态编译:在编译时确定类型,绑定对象,即通过。 
动态编译:运行时确定类型,绑定对象。

动态编译最大限度发挥了java的灵活性,体现了多 态的应用,有效降低类之间的藕合性。 

优点:反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在JavaEE的开发中 它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如 这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。 
缺点:它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。 

认识 Class 类

Class类的实例表示Java应用运行时的类或接口(每个java类运行时都在JVM里表现为一个Class对象,可通过多种方式来获取Class的对象。数组同样也被映射为为Class 对象的一个类,所有具有相同元素类型都共享该 Class 对象,相同类型数组也共享Class对象。8个基本类型和关键字void同样表现为 Class  对象。

Class 类能做什么

通过Class类我们可以创建该类的实例(对象),可以获取该对象的所有属性信息(修饰符、属性名等)、所有方法信息(修饰符、返回值类型、参数列表等),以及可以获得改类继承的父类、该类实现的接口等信息。甚至可以修改被private修饰的成员属性,可以调用private修饰的成员方法。


获取 Class 对象的方式

 // 一般采用这种形式(需要处理异常 ClassNotFoundException )
    Class class1 = Class.forName("com.yztc.lin.model.TestReflect");
    Class class2 = new TestReflect().getClass();
    Class class3 = TestReflect.class;
    System.out.println("类名称   " + class1.getName());// getName 获得完整的类名(含包名)
    System.out.println("类名称   " + class2.getName());
    System.out.println("类名称   " + class3.getName());

Class 常用方法

                   
 1. static Class forName(String className) 通过完整的类名获得该类的 Class对象      
 2.String getName()                         获得完整的类名(含包名)              
  3.Class getSuperclass()         取得父类的Class                
4.  Class[] getInterfaces()               获取所有的实现的接口                
 5. T newInstance()                         通过默认构造器实例化对象              
 6. Constructor[] getConstructors()       获得该类的所有构造器                
 7. Constructor getConstructor(Class... parameterTypes) 根据参数列表,获得该类的指定构造器         
 8. Field[] getDeclaredFields()             获得本类的全部属性                 
 9. Field getDeclaredField(String name)     根据名字获取本类属性                
10  Field[]  getFields()                     获得本类及实现的接口或父类的全部public属性  
11.  Field getField(String name)             根据名字获取接口或父类的public属性      
 12. Method[] getDeclaredMethods()           获得本类的全部方法                 
 13. Method getDeclaredMethod(String name, Class... parameterTypes) 根据方法名和参数列表获取本类方法          
 14. Method[] getMethods()                   获得实现的接口或父类的全部public方法     
  15.Method getMethod(String name, Class... parameterTypes) 根据方法名和参数列表获取接口或父类的public方法
  16.int getModifiers();                     获得Class的访问修饰符类型 返回int值    
 17. boolean isInterface();                   判断Class 是否是接口             


反射的使用

1 获取一个对象的父类与实现的接口


  // 取得父类
    Class parentClass = class1.getSuperclass();
    System.out.println("clazz的父类为:" + parentClass.getName());
    // 获取所有的接口
    Class intes[] = clazz.getInterfaces();
    System.out.println("clazz实现的接口有:");
    for (int i = 0; i < intes.length; i++) {
    	System.out.println((i + 1) + ":" + intes[i].getName());
    }

2 获取某个类的构造器

2.1 获取某个类的具体构造器

    Constructor con = class1.getConstructor(int.class, String.class);//传递具体的参数列表的Class
    Class clazzs[] = con.getParameterTypes();// 获得该构造器的参数列表
    System.out.print("con :");
    for (int i = 0; i < clazzs.length; i++)
    	System.out.print(clazzs[i].getName() + "\t");

2.2 获取某个类的所有public构造器

 Constructor cons[] = class1.getConstructors();
    	// 查看每个构造方法需要的参数
    for (int i = 0; i < cons.length; i++) {
    	System.out.print("cons[" + i + "] :");
    	Class clazzs[] = cons[i].getParameterTypes();//获得该构造器的参数列表
    	for (int j = 0; j < clazzs.length; j++)
    		System.out.print(clazzs[j].getName() + "\t");
    	System.out.println();
    }
2.3 通过反射机制实例化一个类的对象

1. 方式一:通过默认构造器实例化对象

    Class class1 = Class.forName("com.yztc.lin.model.Student");
    Student stu = (Student) class1.newInstance();//默认走空构造器
    stu.setAge(20);
    stu.setName("Rollen");
    System.out.println(user.toString());

1. 方法二:通过指定构造器实例化对象
   
   Class class1 = Class.forName("com.yztc.lin.model.Student");
       //Constructor cons[] = class1.getConstructors();
       //Constructor con =cons[1];
       Constructor con = class1.getConstructor(int.class, String.class);//传递具体的参数列表的Class
       Student stu = (Student) con.newInstance(18,"张三");//走两个参数的空构造器
       System.out.println(user.toString());


3 反射某个类属性信息

Field类 相关方法
             
 1. Field.getModifiers()               获取修饰符类型 返回int值       
 2. Modifier.toString(int mod)         根据修饰符类型 返回具体的修饰符字符串  
 3. Field.getType()                   返回属性的类型              
 4. Field.getName()                   返回属性的名字              
  5.void setAccessible(boolean flag)   如果访问权限不够,可以设置该属性变成可访问
  6.void set(Object obj, Object value) 改变属性的值 set(属性所在的对象,值)
 7. Object get(Object obj)             获取属性的值 get(属性所在的对象)  


3.1 根据属性名获取 本类 的属性

 // 取得本类的 age 属性
    Field f = clazz.getDeclaredField("age");
    //修饰符类型
    int mo = f.getModifiers();
    String priv = Modifier.toString(mo);
    // 属性类型
    Class type = f.getType();
    System.out.println(priv + " " + type.getName() + " " + f.getName() + ";");

3.2 获取本类的全部属性

   // 取得本类的全部属性
    Field[] fields = clazz.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
      	Field f = fields[i];
    	String s = Modifier.toString(f.getModifiers())+" "+f.getType().getName()+" "+f.getName();
    	System.out.println(s);
    }

3.3 根据属性名获取接口或父类的public属性

    // 取得接口或父类的 age 属性
    Field f = clazz.getField("name");
    String s = Modifier.toString(f.getModifiers())+" "+f.getType().getName()+" "+f.getName();
    System.out.println(s);

3.4 获取接口或父类的全部public属性

     // 取得本类的全部属性
    Field[] fields = clazz.getFields();
    for (int i = 0; i < fields.length; i++) {
      	Field f = fields[i];
    	String s = Modifier.toString(f.getModifiers())+" "+f.getType().getName()+" "+f.getName();
    	System.out.println(s);
    }

3.5 通过反射机制操作某个类的属性

    Class clazz = Student.class;
    Object obj = clazz.newInstance();
    Field field = clazz.getDeclaredField("name");
    //field.setAccessible(true);//可以直接对 private 的属性赋值
    field.set(obj, "Java反射修改属性值");
    System.out.println(field.get(obj));//获取属性的值


4 获取某个类的全部方法

Method类的 相关方法
              
1. int getModifiers()             获取方法的修饰符类型         
2.  Modifier.toString(int mod)     根据修饰符类型 返回具体的修饰符字符串

3.  Class getReturnType()      获取返回值类型            

 4.String getName()              获取方法名              

  5.Class[] getParameterTypes() 获取参数列表             

 6. invoke                        调用方法               



4.1 根据方法名和参数列表获取 本类 的方法

    Method method = class1.getDeclaredMethod("privateMethod", String.class, int.class);
    int modifiers = method.getModifiers();//得到修饰符类型 返回int值
    String modifierStr = Modifier.toString(modifiers);//根据修饰符类型 返回具体的修饰符字符串
    Class returnType = method.getReturnType();//得到返回值类型
    String methodName = method.getName();//得到方法名
    System.out.print(modifierStr+" "+returnType+" "+methodName+" (");
    Class[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
    for (int i = 0; i < parameterTypes.length; i++) {
    	Class c = parameterTypes[i];
    	if (i==parameterTypes.length-1) {
    		System.out.print(c.getName()+" arg"+i);
    		break;
    	}
    	System.out.print(c.getName()+" arg"+i+",");
    }
    System.out.println(")");

4.2 获取本类的全部方法

  Method[] methods = clazz.getDeclaredMethods();
    for (Method method : methods) {
    	System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType() + " " + method.getName() + " (");
     	 Class[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
    	for (int i = 0; i < parameterTypes.length; i++) {
    		Class c = parameterTypes[i];
    		if (i == parameterTypes.length - 1) {
    			System.out.print(c.getName() + " arg" + i );
    			break;
    		}
    		System.out.print(c.getName() + " arg" + i + ",");
    	}
      	System.out.println(")");
    }


4.3 根据方法名和参数列表获取接口和父类的public方法

    	Method method = class1.getMethod("publicMethod", String.class, int.class);
    	System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType() + " " +method.getName() + " (");
    	Class[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
    	for (int i = 0; i < parameterTypes.length; i++) {
    		Class c = parameterTypes[i];
    		if (i == parameterTypes.length - 1) {
    			System.out.print(c.getName() + " arg" + i );
    		break;
    		}
    		System.out.print(c.getName() + " arg" + i + ",");
    	}
    	System.out.println(")");

4.4 获取接口和父类的全部public方法

   Method[] methods = clazz.getMethods();
    for (Method method : methods) {
    	System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getReturnType() + " " + method.getName() + " (");
      	Class[] parameterTypes = method.getParameterTypes();// 得到方法的参数列表是
    	for (int i = 0; i < parameterTypes.length; i++) {
    		Class c = parameterTypes[i];
    		if (i == parameterTypes.length - 1) {
    			System.out.print(c.getName() + " arg" + i );
    			break;
    		}
    		System.out.print(c.getName() + " arg" + i + ",");
    	}
      	System.out.println(")");
    }

4.5 通过反射机制调用某个类的方法

 public class Test {
    	public static void main(String[] args) throws Exception {
    		Class clazz = Class.forName("com.yztc.lin.model.Test");
    		Object obj = clazz.newInstance();
    		/** 调用Test类中的 test1 方法**/
    		Method method = clazz.getDeclaredMethod("test1");
          	//method.setAccessible(true);//打破访问权限的范围限制
    		Object returnVal = method.invoke(obj);
    		System.out.println("得到返回值:"+returnVal);
          
    		/**调用Test的test1方法**/
    		method = clazz.getMethod("test2", int.class, String.class);
    		method.invoke(obj, 20, "张三");
    	}
    
    	private int test1() {
    		System.out.println("通过反射调用了方法1");
    		return 123;
    	}
    	
    	public void test2(int i, String s) {
    		System.out.println("通过反射调用了方法2 i:" + i + " s:" + s);
    	}
    
    }

你可能感兴趣的:(javaSE)