• 5.7(1) 反射


    5.7 反射

     

     

    反射(reflection library)提供了动态操作java代码程序的方法,这项功能被大量应用于JavaBean中,使用反射,在设计或运行添加新类的时候,能够快速地应用开发工具动态查找新添加类的能力。

      能够分析类能力的程序叫做反射(reflective)。

    •   在运行中分析类的能力;
    •       在运行中查看对象;
    •       实现通用的数组操作代码;
    •       利用Method对象。

    5.7.1 Class类

      在程序运行期间,java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类,JVM利用运行时类型信息选择相应的方法执行。

      可以通过专门的Java类访问这些信息,保存这些信息的类被称为Class,Object类中的getClass()方法将会返回一个Class类型的实例。

    Employee e;
    ...
    Class cl = e.getClass();
    

      如同用一个Employee对象表示一个特定的雇员属性一样,一个Class对象将表示一个特定类的属性。最常用的Class方法是getName。这个方法返回类的名字。

    System.out.println(e.getClass().getName() + " " + e.getName());
    

      如果e是一个雇员,会打印出:

    Employee Harry Hacker
    

      如果e是一个经理,会打印出:

    Manager Harry Hacker
    

      如果类在一个包里,包的名字也作为类名的一部分:

    Date d = new Date();
    Class cl = d.getClass();
    String name = cl.getName();
    

      也可以调用静态方法forName获得类名对应的Class对象。

    String className = "java.util.Date";
    Class cl = Class.forName(className);
    

      如果类名保存在字符串中,并可在运行中改变,就可以使用这个方法。这个方法只有在className是类名或接口名的时候才能执行。否则,forName方法将会抛出一个checkedexception异常(已检查异常)。无论何时使用这个方法,都应该提供一个异常处理器(execption handler)。

      获得Class类对象的第三种方法非常简单,如果T是任意的java类型,T.class将代表匹配的类对象。例如:

    Class cl1 = Date.class;
    Class cl2 = int.class;
    Class cl3 = Double[].class;
    

      一个Class对象实际上表示的是一个类型,而这个类型未必一定是一种类,例如,int不是类,但int.class是一个Class类型的对象。

      JVM为每个类管理一个Class对象,因此,可以利用==运算符实现两个类对象比较的操作。例如:

    if(e.getClass() == Employe.class)
        ...
    

      还有一个很有用的方法newInstance(),可以用来快速地创建一个类的实例。例如,

    e.getClass().newInstance();
    

      创建一个与e具有相同类型的实例,newInstance方法调用默认的构造器(没有参数的构造器)初始化新创建的对象。如果这个类没有默认的构造器,就会抛出一个异常。

      将forName域newInstance配合起来使用,可以根据存储在字符串中的类名创建一个对象。

    String s = "java.util.Date";
    Object m = Class.forName(s).newInstance();
    

    5.7.3 利用反射分析类的能力

      java.lang.reflect中包含三个类Filed、Method和Constructor分别用于描述类的域、方法和构造器。

           Filed类:    getDeclaredFileds()

                getName(返回项目的名称)、getType(返回域所属的类型)、getModifiers(返回一个整型数值,描述修饰符的情况)

       Method类:   getDeclaredMethods()

                getName(返回项目的名称)、getModifiers(返回一个整型数值,描述修饰符的情况)、getReturnType(返回值类型)、                       getParameterTypes(返回参数类型)

    Constructors类:  getDeclaredConstructors()

                getName(返回项目的名称)、 getParameterTypes(返回参数类型)

    package reflect_5_13;
    
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.lang.reflect.Modifier;
    import java.util.Scanner;
    
    public class ReflectionTest {
    	public static void main(String args[])
    	{
    		String name;
    		if(args.length > 0)
    		{
    			name = args[0];
    		}
    		else
    		{
    			Scanner in = new Scanner(System.in);
    			System.out.println("Enter class name(e.g.java.util.Date): ");
    			name = in.next();
    		}
    		
    		try
    		{
    			//首先用cl保存获取的name.class
    			Class cl = Class.forName(name);
    			//获得超类supercl
    			Class supercl = cl.getSuperclass();
    			//获取cl的修饰语(public/private/final...)
    			String modifiers = Modifier.toString(cl.getModifiers());
    			if(modifiers.length() > 0)
    				System.out.print(modifiers + " ");
    			System.out.print("class " + name);
    			if(supercl != null && supercl != Object.class)
    				System.out.print("extends " + supercl.getName());
    			
    			System.out.print("
    {
    ");
    			printConstructors(cl);
    			System.out.println();
    			printMethods(cl);
    			System.out.println();
    			printFields(cl);
    			System.out.println("}");
    			
    			
    		}catch(ClassNotFoundException e)
    		{
    			e.printStackTrace();
    		}
    		System.exit(0);		
    	}
    	
    	/*
    	 * 输出所有的构造器
    	 */
    
    	public static void printConstructors(Class cl)
    	{
    		Constructor[] constructors = cl.getDeclaredConstructors();
    		for(Constructor c:constructors)
    		{
    			//构造器的名字
    			String name = c.getName();
    			System.out.print(" ");
    			//构造器的修饰符
    			String modifiers = Modifier.toString(c.getModifiers());
    			if(modifiers.length() > 0)
    			{
    				System.out.print(modifiers + " ");
    			}
    			System.out.print(name + "(");
    			//构造器的参数类型
    			Class[] paramTypes = c.getParameterTypes();
    			for(int j = 0; j < paramTypes.length; j++)
    			{
    				if(j > 0)
    				{
    					System.out.print(", ");
    				}
    				System.out.print(paramTypes[j].getName());	
    			}
    			System.out.println(");");
    		}
    	}
    	
    	/*
    	 * 输出所有的方法
    	 */
    	public static void printMethods(Class cl)
    	{
    		Method[] methods = cl.getDeclaredMethods();
    		for(Method m:methods)
    		{
    			//方法的获取返回类型
    			Class retType = m.getReturnType();
    			//方法的名称
    			String name = m.getName();
    			
    			System.out.print(" ");
    			
    			//方法的修饰符
    			String modifiers = Modifier.toString(m.getModifiers());
    			if(modifiers.length() > 0)
    			{
    				System.out.print(modifiers + " ");
    			}
    			System.out.print(retType.getName() + " " + name + "(");
    			
    			//将参数类型打印出来
    			Class[] paramTypes = m.getParameterTypes();
    			for(int j = 0; j < paramTypes.length; j++)
    			{
    				if(j > 0)
    				{
    					System.out.print(", ");
    				}
    				System.out.print(paramTypes[j].getName());
    			}
    			System.out.println(");");	
    		}
    	}
    	/*
    	 * 输出所有的域
    	 */
    	public static void printFields(Class cl)
    	{
    		Field[] fields = cl.getDeclaredFields();
    		
    		for(Field f:fields)
    		{
    			//域的类型
    			Class type = f.getType();
    			//域的名称
    			String name = f.getName();
    			System.out.print(" ");
    			//域的修饰符
    			String modifiers = Modifier.toString(f.getModifiers());
    			if(modifiers.length() > 0)
    			{
    				System.out.print(modifiers + " ");
    				System.out.println(type.getName() + " " + name + " ");
    			}
    		}
    	}
    }
    

    输出结果:

    Enter class name(e.g.java.util.Date): 
    java.util.Date
    public class java.util.Date
    {
     public java.util.Date(int, int, int, int, int, int);
     public java.util.Date(java.lang.String);
     public java.util.Date();
     public java.util.Date(long);
     public java.util.Date(int, int, int);
     public java.util.Date(int, int, int, int, int);
    
     public boolean after(java.util.Date);
     public boolean before(java.util.Date);
     public boolean equals(java.lang.Object);
     public java.lang.String toString();
     public int hashCode();
     public java.lang.Object clone();
     public int compareTo(java.util.Date);
     public volatile int compareTo(java.lang.Object);
     private void readObject(java.io.ObjectInputStream);
     private void writeObject(java.io.ObjectOutputStream);
     private final sun.util.calendar.BaseCalendar$Date normalize();
     private final sun.util.calendar.BaseCalendar$Date normalize(sun.util.calendar.BaseCalendar$Date);
     public static long parse(java.lang.String);
     public static long UTC(int, int, int, int, int, int);
     public int getDate();
     private static final java.lang.StringBuilder convertToAbbr(java.lang.StringBuilder, java.lang.String);
     private final sun.util.calendar.BaseCalendar$Date getCalendarDate();
     private static final sun.util.calendar.BaseCalendar getCalendarSystem(long);
     private static final sun.util.calendar.BaseCalendar getCalendarSystem(int);
     private static final sun.util.calendar.BaseCalendar getCalendarSystem(sun.util.calendar.BaseCalendar$Date);
     public int getDay();
     public int getHours();
     private static final synchronized sun.util.calendar.BaseCalendar getJulianCalendar();
     static final long getMillisOf(java.util.Date);
     public int getMinutes();
     public int getMonth();
     public int getSeconds();
     private final long getTimeImpl();
     public int getTimezoneOffset();
     public int getYear();
     public void setDate(int);
     public void setHours(int);
     public void setMinutes(int);
     public void setMonth(int);
     public void setSeconds(int);
     public void setYear(int);
     public java.lang.String toGMTString();
     public java.time.Instant toInstant();
     public java.lang.String toLocaleString();
     public void setTime(long);
     public static java.util.Date from(java.time.Instant);
     public long getTime();
    
     private static final sun.util.calendar.BaseCalendar gcal 
     private static sun.util.calendar.BaseCalendar jcal 
     private transient long fastTime 
     private transient sun.util.calendar.BaseCalendar$Date cdate 
     private static int defaultCenturyStart 
     private static final long serialVersionUID 
     private static final [Ljava.lang.String; wtb 
     private static final [I ttb 
    }
    

      

    构造器:名称、修饰符、参数类型

    方法:名称、修饰符、参数类型、返回类型

    域:名称、类型

      其他的API还需要详细的了解。

    5.7.4 在运行时使用反射分析对象

      查看任意对象的数据域名称和类型:

    1、获得对于的Class对象;

    2、通过Class对象调用getDeclaredFields。

      在编写程序的时候,如果知道想要查看的域名和类型,查看指定的域是一件很容易的事情,而利用反射机制可以查看在编译时还不清楚的对象域。

      查看对象域的关键方法是Field类中get方法。如果f是一个Field类型的对象(例如,通过getDeclaredFields得到的对象),obj是某个包含f域的类的对象,f.get(obj)将返回一个对象,其值为obj域的当前值。

    Eployee harry = new Employee("Harry Hacker", 35000, 10, 1, 1989);
    Class cl = harry.getClass();
    Field f = cl.getDeclaredField("name");
    Object v = f.get(harry);
    

      实际上这段代码有问题,由于name是一个私有域,所以get方法将会抛出一个IllegalAccessException。只有利用get方法才能得到可访问域的值,除非拥有访问权限,否则Java安全机制只允许查看任意对象有那些域,而不允许读取它们的值。

      反射机制的默认行为受限于java的访问控制,然而,如果一个java程序没有收到安全管理器的控制,就可以覆盖访问控制,为了达到这个目的,需要调用Field、Method或Constructor对象的setAccessible方法。例如:

    f.setAccessible(true);
    

      setAccessible方法是AccessibleObject类中的一个方法,它是Field、Method和Constructor类的公共超类。这个特性是为调试、持久化存储和相似机制提供的。

      get方法还有一个需要解决的问题,nama是一个String,因此它作为Object返回没有任何问题。但是,假设我们想要查看salary域,它属于double类型,而java中数值类型不是对象。要想解决这个问题,可以使用Fields类中的getDouble方法,也可以调用get方法,此时,反射机制将会自动将这个域值打包到对应的对象包装器中,这里将打包成Double。

      调用f.get(obj, value)可以将obj对象的f域设置为新值。

      使用getDeclaredFields获得所有的数据域,然后使用setAccessible将所有的域设置为可访问的,对于每个域,获得了名字和值。

    能让一个男孩子热血的,不仅有梦想,还有姑娘。
  • 相关阅读:
    开启mysql远程登录
    InfluxDB安装及配置
    基于ssh反向代理实现的远程协助
    小工具之进程守护器
    生成freeswitch事件的几种方式
    freeswitch模块之event_socket
    freeswitch对接其它SIP设备
    freeswitch注册过程分析
    redis参考文档
    创建型模式之Builder模式及实现
  • 原文地址:https://www.cnblogs.com/Mr24/p/6511988.html
Copyright © 2020-2023  润新知