zoukankan      html  css  js  c++  java
  • Java的反射机制

    前言


    反射提供了一种动态的功能,这样的动态功能很强大。它主要体如今通过反射相关的API,就能够知道一个陌生


    的Java类的全部信息。包含属性、方法、构造器等。

    并且元素全然能够在执行时动态的进行创建或调用,而不必在


    JVM执行时就进行确定。通过查阅相关文档,进行了整理。本篇也是基于以下文章进行扩充。


           http://blog.csdn.net/mark_yangs/article/details/47427037》             

               

    反射的原理是什么


    严格意义上来讲,Java并非动态语言。它并没有Perl和Python那样灵活。

    可是。Java的反射机制却让它显得动


    态起来。


    普通情况下,假设想生成这个类的对象时,执行这个程序的JVM会确认这个类的Class对象是否已经载入。假设


    尚未加载,JVM就会依据类名查找.class文件,并将其加载,一旦这个类的Class对象被加载内存,它就能够被用来创


    建这个类的全部对象。


    另外,对于一个未知类型的引用来说,一般会採用强制类型转换的形式来得到开发人员想要的类型引用,假设运行


    了一个错误的类型转换。就会抛出一个ClassCastException异常。


      在以上两个过程中,Class类一直都在起作用。由于Class类实例包括的是一个Java类的所有信息,包括类名、方


    法、属性等。换句话来说,也就是Class对象就是代表一个类的类。


    Java用Class类来代表了全部的类,方便了开发人员掌控类信息。通过Class。开发人员能够得到属性、方法、构造


    器、修饰符等信息。在动态的获取这些信息以后。开发人员就能够用该Class创建实例、调用不论什么方法、訪问不论什么属性


    等操作。这些也是反射的主要用途。


    反射机制相关的API主要集中在java.lang.reflect包以下,开发人员也就是利用该包以下的接口和类进行相关的反射


    开发。大多数的框架。如Struts、Hibernate和Spring,都会频繁地使用反射API来完毕它们动态的功能。


    Class类的含义和作用是什么


    Class类在反射机制中起到了很关键的作用,它是开发人员进行反射开发的入口。

    从上面能够知道Class是用来记


    录一个类的各种信息,它伴随着类的载入而 创建。那么,类会在什么时候被载入到JVM中呢?概括来说,一个普通的


    Java类,会在下面几种情况,被载入到JVM中。


    (1)须要使用该类创建对象。

    例如以下代码就会导致Stundent类被载入到JVM类中:


    Student mStudent=new Student();

    (2)訪问该类的静态成员,实例代码例如以下:


    public class Student {
    	static int count=2;
    }

    public class Main {
    	public static void main(String[] args) {
    		System.out.println(Student.count);
    	}
    }

    (3)使用Class类的静态forName()方法,动态地载入一个指定类名的类。假设类未找到,则抛出


    ClassNotFoundException异常。实例代码例如以下:


    public class Main {
    	public static void main(String[] args) throws ClassNotFoundException {
    		Class clazz=Class.forName("com.example.bill.Student");
    	}
    }


    无论通过什么样的形式,类一旦被载入进入JVM以后,就会为它创建一个Class类的实例对象。那么,开发人员又


    该怎样得到这个Class对象呢?概括来说,要得到一个类的Class对象,能够通过下面几种途径。


    (1)Class的forName()方法的返回值就是Class类型,也就是动态导入类的Class对象的引用。forName()方法的完


    整定义例如以下:


    public static Class<?> forName(String className) throws ClassNotFoundException


    (2)每一个类都会有一个名称为Class的静态属性,通过它也是能够获取到Class对象的,实例代码例如以下:


    Class<Student> clazz=Student.class;

    (3)Object类中有一个名为getClass的成员方法,它返回的是对象的执行时类的Class对象。由于Object类是全部


    类的父类。所以。全部的对象都能够使用该方法得到它执行时类的Class对象。实例代码例如以下:


    public class Main {
    	public static void main(String[] args) throws ClassNotFoundException {
    		Student mStudent=new Student();
    		Class<Student> clazz=(Class<Student>) mStudent.getClass();
    	}
    }

    获取到Class对象以后。就能够通过调用它的一些成员方法来获取它所代表的类的属性、方法、修饰符等信息,


    以及调用newInstance()方法来创建新的实例对象。还有其它一些功能方法。


    怎样操作类的成员变量


    Field类,代表的是类的属性(字段),也被称为成员变量。反射能够获取到它的对象。Field对象通过Class类的


    getDeclaredField()或getDeclaredFields方法获取到,处于java.lang.reflect包下。

    Field提供有关类或接口的单个字段


    的信息,以及对它的动态訪问权限,反射的字段可能是一个静态的字段或实例的字段。


    Field的方法主要分为两个类,即getXXX和setXXX。当中getXXX是用于获取某个对象的该字段的值,而且有一


    定的类型规定,比如。getFloat(),而setXXX则是用于设置值。它们一般有两个參数,一个是对象引用,还有一个则是


    须要设置的值。


    下面为一个Field的使用演示样例,通过反射来比較两个对象的大小:


    public class FieldTestClass {
    	public String name;
    	public int age;
    	
    	public FieldTestClass(String name,int age){
    		super();
    		this.name=name;
    		this.age=age;
    	}
    }


    public class Main {
    	public static void main(String[] args) throws ClassNotFoundException {
    		FieldTestClass obj1=new FieldTestClass("bill1",100);
    		FieldTestClass obj2=new FieldTestClass("bill2", 200);
    		System.out.println(compare(obj1, obj2).name);
    	}
    	
    	private static FieldTestClass compare(FieldTestClass obj1,FieldTestClass obj2){
    		try {
    			Field field1=obj1.getClass().getDeclaredField("age");
    			Field field2=obj2.getClass().getDeclaredField("age");
    			int val1=(Integer)field1.get(obj1);
    			int val2=(Integer)field2.get(obj2);
    			if(val1>val2){
    				return obj1;
    			}else{
    				return obj2;
    			}
    		} catch (NoSuchFieldException e) {
    			e.printStackTrace();
    		} catch (SecurityException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		}
    		
    		return null;
    	}
    	
    }

    以上代码输出结果为:bill2


    值得注意的是,假设我们将FieldTestClass中的age设置成private,也就是私有属性时,程序会报


    IllegalAccessException异常。



    怎样操作类的方法


    Method类,代表的是类的方法。

    与Field类似,反射能够获取到它的对象,使用它的方式则是动态调用,Method


    对象通过Class类的getMethod()或getMethods()方法获取到,也处于java.lang.reflect包下,Method提供关于类或接口


    中的某个方法(以及怎样訪问该方法)的信息,所反映的方法可能是类方法或实例方法(包含抽象方法在内)。


    Method类中使用最多的方法是invoke(),它的含义就是方法调用。

    它的第一个參数为Class所代表的类的一个实例


    对象,以后则是一个不定长的Object类型的參数列表,它是Method对象所代表的方法须要的參数列表。


    下面为一个Method的使用实例。通过命令行參数来实现方法的动态调用:


    public class MethodTestClass {
    	public void m1(){
    		System.out.println("m1.....");
    	}
    	public void m2(){
    		System.out.println("m2.....");
    	}
    }

    public class CallMethodTest {
    	public static void main(String[] args) {
    		args = new String[] { "m1" };
    		String methodName = args[0];
    		if (methodName != null) {
    			Class<MethodTestClass> clazz = MethodTestClass.class;
    			try {
    				Method m = clazz.getDeclaredMethod(methodName);
    				if (m != null) {
    					MethodTestClass obj = clazz.newInstance();
    					m.invoke(obj);
    				}
    			} catch (NoSuchMethodException e) {
    				e.printStackTrace();
    			} catch (SecurityException e) {
    				e.printStackTrace();
    			} catch (InstantiationException e) {
    				e.printStackTrace();
    			} catch (IllegalAccessException e) {
    				e.printStackTrace();
    			} catch (IllegalArgumentException e) {
    				e.printStackTrace();
    			} catch (InvocationTargetException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }

    以上代码输出结果:m1.....


    注意假设指定的方法名不存在,程序会报NoSuchMethodException异常。假设将方法的权限设置成private,也就是私


    有属性时,程序会报IllegalAccessException异常。


    怎样利用反射机制訪问类的私有成员


    依据Java的语法规则,类的私有成员(包含私有的成员变量和方法)仅仅能被内部的方法所訪问。

    可是,通过反射


    机制,却能够訪问一个类的全部成员,包含私有成员在内。


    假设开发人员在开发反射机制程序的时候。对待私有成员像公有成员一样,那就会遇到一个异常的抛出,下面程序


    能够訪问私有成员:

    public class PrivateTestClass {
    	private String field;
    	public PrivateTestClass(String field){
    		super();
    		this.field=field;
    	}
    }

    public class PrivateTest {
    	public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    		PrivateTestClass obj=new PrivateTestClass("bill");
    		Class clazz=obj.getClass();
    		Field f=clazz.getDeclaredField("field");
    		f.setAccessible(true);//訪问性设置成true
    		System.out.println(f.get(obj));
    	}
    }


    程序输出结果:bill


    从以上代码来看。私有的成员变量field是能够被成功訪问的。当中比較关键一行代码就是调用Field的


    setAccessible()方法。让field属性变得能够訪问。



    -------------------------------------------------------------------------------------------------------------------------------------------------------

    转载请注明出处:http://blog.csdn.net/hai_qing_xu_kong/article/details/47614679情绪控



  • 相关阅读:
    SQL语法之DDL和DML
    流的装饰模式
    SharePoint 通过客户端API访问SharePoint状态栏
    SQL Server 2008 阻止保存要求重新创建表的更改问题的设置方法
    30个特别酷的SharePoint站点
    在Sharepoint站点状态栏显示列表内容数据
    在SharePoint2010中如何使用状态栏?
    SPGridView and Pagination in SharePoint SharePoint中的SPGridView和分页功能
    一步步教你在SharePoint站点创建具有分页、排序、筛选功能的SPGridView Web部件
    使用对象模型读取SharePoint列表
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/7358401.html
Copyright © 2011-2022 走看看