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


    title: Java 反射机制初探
    date: 2017-08-04 08:29:02
    tags: [Java]

    Java 反射机制

    反射(Reflect)是Java语言中的重要的特性. Java框架中的绝大多数都使用了反射. 理解框架必须要精通反射的实现和原理. 在java.lang.reflect中, Java提供了一些列反射的类. 其中, 最常用的几个类分别为Class(这个类在java.lang包下), Method, Field, Constructor. 从字面意思上来看, 上面几个类分别对应了Java语言中的类, 方法, 字段, 构造方法. 通过学习使用这几个类, 可以让我们了解Java反射的过程和使用.

    Class

    Classjava.lang, 在Java文档中,对Class类的描述如下

    Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
    Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.

    从上面我们可以看到Class是Java类的对象. 从Class的实例中, 我们可以操纵Java指定的类. 而且Class类没有构造函数, 只能从一些特定途径生成类对象.

    下面代码展示了如何获取一个类对象,首先我们声明一个Student类, 该类是一个普通的类. 下面的所有代码不外加说明的话, 都在此类的基础上展开.

    package reflect;
    public class Student {
    	private int sId;
    	private int sName;
    	public int getsId() {
    		return sId;
    	}
    	public void setsId(int sId) {
    		this.sId = sId;
    	}
    	public int getsName() {
    		return sName;
    	}
    	public void setsName(int sName) {
    		this.sName = sName;
    	}
    	private void say(){
    		System.out.println("hello");
    	}
    	public void play(){
    		System.out.println("play");
    	}
    	public Student() {
    	}
    	public Student(int id){
    		this.sId = id;
    	}
    	public Student(int id, int sname){
    		this.sId = id;
    		this.sName = sname;
    	}
    }
    
    • 使用类全称获取类对象
    Class clazz = Class.forName("reflect.Student");
    
    • 使用类名获取类对象
    Class clazz = Student.class
    
    • 使用实例获得类对象
    Student s = new Student();
    Class clazz = s.getClass();
    

    上述三种方式都可以获取StudentClass对象. 目前来说, 第一种使用类名的字符串获取类对象更加常用.

    在一个类对象中有一个方法特别值得注意:newInstance(). 这个方法从字面上就可以很好理解: 产生一个该类的实例.

    Class clazz = Class.forName("reflect.Student");
    Object o = clazz.newInstance();
    

    但是这个方法只能调用无参构造函数. 当需要调用带参构造函数时或者类中没有无参构造函数时, 就不能用了. 幸好Java提供了Constructor类去调用其他的构造函数.

    Constructor

    Constructorjava.lang.reflect包中. 在Java文档中,对Constructor类的描述如下

    Constructor provides information about, and access to, a single constructor for a class.
    Constructor permits widening conversions to occur when matching the actual parameters to newInstance() with the underlying constructor's formal parameters, but throws an IllegalArgumentException if a narrowing conversion would occur.

    正如上面所说, Constructor是为了解决调用带参构造函数的时候使用, 当然它也可以用来调用无参构造函数. Constructor相当于Class中的newInstance()函数的升级版本.
    具体用法如下

    	Constructor[] constructors = clazz.getConstructors();
    	for(int i=0;i<constructors.length;i++){
    		Method getIdMethod = clazz.getMethod("getsId");
    		System.out.println(constructors[i].getName()+" "+constructors[i].getParameterCount());
    		if(constructors[i].getParameterCount()==0){
    			Object o = constructors[i].newInstance();
    			System.out.println(getIdMethod.invoke(o));
    		}
    		else if(constructors[i].getParameterCount()==1){
    			Object o = constructors[i].newInstance(1);
    			System.out.println(getIdMethod.invoke(o));
    		}else{
    			Object o = constructors[i].newInstance(2,3);
    			System.out.println(getIdMethod.invoke(o));
    		}
    	}
    

    Method

    Methodjava.lang.reflect包中. 在Java文档中,对Method类的描述如下:

    A Method provides information about, and access to, a single method on a class or interface. The reflected method may be a class method or an instance method (including an abstract method).
    A Method permits widening conversions to occur when matching the actual parameters to invoke with the underlying method's formal parameters, but it throws an IllegalArgumentException if a narrowing conversion would occur.

    Method类是对Java类方法的抽象. 具体使用方法和示例代码如下

    	Method playMethod = clazz.getMethod("play");
    	playMethod.invoke(clazz.newInstance());		
    	Method[] allMethod = clazz.getDeclaredMethods();
    	for(int i=0;i<allMethod.length;i++){
    		System.out.println(allMethod[i].getName()+" "+allMethod[i].getParameterCount());
    	}	
    	Method sayMethod = clazz.getDeclaredMethod("say");
    	sayMethod.setAccessible(true);
    	sayMethod.invoke(clazz.newInstance());
    	sayMethod.setAccessible(false);
    

    注意到这句话sayMethod.setAccessible(true), 目的是让调用者有权限去执行类中的非public方法(或者权限不够的方法).

    Field

    Fieldjava.lang.reflect包中. 在Java文档中,对Field类的描述如下:

    A Field provides information about, and dynamic access to, a single field of a class or an interface. The reflected field may be a class (static) field or an instance field.
    A Field permits widening conversions to occur during a get or set access operation, but throws an IllegalArgumentException if a narrowing conversion would occur.

    Field类是对Java类字段的抽象. 具体使用方法和示例代码如下

    	Field[] fields = clazz.getDeclaredFields();
    	for(int i=0;i<fields.length;i++){
    		System.out.println(fields[i].getName());
    	}	
    	Object o = clazz.newInstance();
    	Method m = clazz.getMethod("setsId", int.class);
    	System.out.println(m.getName());
    	m.invoke(o, 1);
    	Field sidField = clazz.getDeclaredField("sId");
    	System.out.println(sidField.getInt(o));
    

    以上就是Java反射中的四个比较重要和基础的类. reflect包中还有许多重要的类, 比方说AOP的实现工具InvocationHandler动态代理等等. 理解基本的反射工具可以让我们更好地了解Java语言的特性和Java框架的原理.

  • 相关阅读:
    Cefsharp支持MP4和MP3的CEF库cef.redist.x86.3.2623,对应Cefsharp49
    解读设计模式
    模拟支付宝、淘宝登录2
    模拟支付宝、淘宝登录1
    上一篇随笔是2011-11-21 17:23,唏嘘啊。。。
    像素格式
    YUV格式详解
    认识RGB和YUV
    WPF性能优化经验总结
    【日期正则表达式】
  • 原文地址:https://www.cnblogs.com/yanximin/p/10982213.html
Copyright © 2011-2022 走看看