反射的基本使用

一、Class类

在java中,允许通过一个对象找到其所在的类的所有信息,这便是Class类的作用。

1. Objcet类对反射的支持

在Object类中定义了以下方法,该方法将被所有子类继承:public final Class getClass()  以上方法的返回值是一个Class对象,该类是java反射机制的源头。

2. Class类

Class本身表示一个类的自身,可以通过Class类得到一个类的完整结构,包括此类中的方法定义,属性定义等。

获取Class类的实例有三种方法:

(1) 通过forName()方法

(2)通过类.class

(3)对象.getClass()

例:

package org.lxh.demo15.getclassdemo ;
class X{
};
public class GetClassDemo02{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 指定泛型
		Class<?> c2 = null ;		// 指定泛型
		Class<?> c3 = null ;		// 指定泛型
		try{
			// 以下的操作形式是在开发中最常用的一种形式
			c1 = Class.forName("org.lxh.demo15.getclassdemo.X") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		c2 = new X().getClass() ;		// 通过Object类中的方法实例化
		c3 = X.class ;	// 通过类.class实例化
		System.out.println("类名称:" + c1.getName())  ;	// 得到类的名称
		System.out.println("类名称:" + c2.getName())  ;	// 得到类的名称
		System.out.println("类名称:" + c3.getName())  ;	// 得到类的名称
	}
};

3. 利用Class类实例化对象

如果现在已经实例化了Class对象,则可以通过Class类中提供的

  public T newInstance() throws InstantiationException,IllegalAccessException 函数实例化对象。

但是使用该函数实例化对象需要注意一点,该类必须存在无参构造函数。

       要想解决这样的问题,必须明确指定要调用的构造方法,并传递参数,但是从实际的角度来看,一般使用反射实例化对象的时候,都最好存在一个无参构造方法,这样比较合理。要调用带有参数的构造方法,则必须使用Constructor类。

4. Constructor类

可以利用Constructor类获取Class中的有参构造方法,并产生实例。

操作过程:(1) 通过Class类的getConstructors()方法获得该类的所有构造方法。

    (2) 向构造方法中传递一个对象数组进去,里面包含了构造方法所需的各个参数。

    (3) 之后通过Constructor实例化对象。

    public T newInstance(Object... initargs)
              throws InstantiationException, IllegalAccessException,IllegalArgumentException,InvocationTargetException

例:

package org.lxh.demo15.instancedemo ;
import java.lang.reflect.Constructor ;	// 导入反射机制包
class Person{
	private String name ;	// name属性
	private int age ;		// age属性
	public Person(String name,int age){
		this.setName(name) ;
		this.setAge(age);
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	public String toString(){	// 覆写toString()方法
		return "姓名:" + this.name + ",年龄:" + this.age  ;
	}
};
public class InstanceDemo03{
	public static void main(String args[]){
		Class<?> c = null ;		// 声明Class对象
		try{
			c = Class.forName("org.lxh.demo15.instancedemo.Person") ;
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Person per = null ;	// 声明Person对象
		Constructor<?> cons[] = null ;
		cons = c.getConstructors() ;
		try{
			per = (Person)cons[0].newInstance("李兴华",30) ;	// 实例化对象
		}catch(Exception e){
			e.printStackTrace() ;
		}
		System.out.println(per) ;	// 内容输出,调用toString()
	}
};

二、反射应用 - 取得类的结构

可以利用Class取得一个类所实现的全部接口、继承的所有父类、全部构造方法、全部方法、及全部属性。

1. 取得所实现的全部接口

public Class<?>[] getInterfaces()

2. 取得父类

public Class<? super T> getSuperClass()

3. 取得构造方法

public Constructors<?>[] getConstructors()

在Constructors中存在几个常用方法:

(1)  取得修饰符 : public int getModifiers()

(2) 取得方法名称: public String getName()

(3) 取得参数的类型: public Class<?>[] getParameterTypes()

但是发现修饰符变成了数字,必须使用Modifier类进行还原。

public static String toString(int mod)

例:

ackage org.lxh.demo15.classinfodemo ;
import java.lang.reflect.Constructor ;	// 导入构造方法的包
import java.lang.reflect.Modifier ;	// 导入构造方法的包
public class GetConstructorDemo03{
	public static void main(String args[]){
		Class<?> c1 = null ;		// 声明Class对象
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化对象
		}catch(ClassNotFoundException e){
			e.printStackTrace() ;
		}
		Constructor<?> con[] = c1.getConstructors() ;	// 取得一个类中的全部构造
		for(int i=0;i<con.length;i++){
			Class<?> p[] = con[i].getParameterTypes() ;		// 得到构造方法中的全部参数
			System.out.print("构造方法:" ) ;	 // 输出构造,直接打印
			int mo = con[i].getModifiers() ; // 得到所要的访问权限
			System.out.print(Modifier.toString(mo) + " ") ;	// 得到修饰符
			System.out.print(con[i].getName()) ;	// 取得构造方法的名字
			System.out.print("(") ;
			for(int j=0;j<p.length;j++){
				System.out.print(p[j].getName() + " arg" + i) ;
				if(j<p.length-1){
					// 判断此是否是最后一个参数
					System.out.print(",");	// 输出“,”
				}
			}
			System.out.println("){}") ;
		}
	}
};
4. 取得全部方法

public Method[] getDeclaredMethods()

                            throws SecurityException //输出本类中声明的全部方法       

public Method[] getMethods()

                    throws SecurityException //输出具有的所有方法

方法操作: 

取得返回值类型: public Class<?> getReturnType()

取得全部的参数类型:public Class<?>[] getParameterTypes()

取得修饰符: public int getModifiers()

取得异常类型: public Class<?>[] getExceptionTypes()

取得方法名称: public String getName()

 5. 取得全部属性

public Field[] getDeclaredFields()

                          throws SecurityException //取得本类中声明的全部属性

public Field[] getFields()

                  throws SecurityException //取得本类具有的所有属性(即包括从父类继承下来的)

Field类使用方法与Method方法类似,不再赘述。

三、深入反射

 1. 通过反射调用类中的方法。

                 public Method getMethod(String name,
                    Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException

通过此方法可以获得一个method对象。然后通过此method对象调用该方法:

public Object invoke(Object obj, Object... args) throws IllegalAccessException,  IllegalArgumentException,  InvocationTargetException

第一个参数为调用该方法的对象,后面的可变参数为传入该函数的参数

2. 通过反射调用类的setter和getter方法。

可以采用一种通用的方式来处理setter和getter方法的调用,例如:

import java.lang.reflect.Method ;
public class InvokeSetGetDemo{
	public static void main(String args[]){
		Class<?> c1 = null ;
		Object obj = null ;
		try{
			c1 = Class.forName("org.lxh.demo15.Person") ;	// 实例化Class对象
		}catch(Exception e){}
		try{
			obj = c1.newInstance() ;
		}catch(Exception e){}
		setter(obj,"name","Troy",String.class) ;	// 调用setter方法
		setter(obj,"age",22,int.class) ;	// 调用setter方法
		System.out.print("姓名:") ;
		getter(obj,"name") ;
		System.out.print("年龄:") ;
		getter(obj,"age");
	}
	/**
		Object obj:要操作的对象
		String att:要操作的属性
		Object value:要设置的属性内容
		Class<?> type:要设置的属性类型
	*/
	public static void setter(Object obj,String att,Object value,Class<?> type){
		try{
			Method met = obj.getClass().getMethod("set"+initStr(att),type) ;	// 得到setter方法
			met.invoke(obj,value) ;	// 设置setter的内容
		}catch(Exception e){
			e.printStackTrace() ;
		}
	}
	public static void getter(Object obj,String att){
		try{
			Method met = obj.getClass().getMethod("get"+initStr(att)) ;	// 得到setter方法
			System.out.println(met.invoke(obj)) ;	// 调用getter取得内容
		}catch(Exception e){
			e.printStackTrace() ;
		}
	}
	public static String initStr(String old){	// 将单词的首字母大写
		String str = old.substring(0,1).toUpperCase() + old.substring(1) ;
		return str ;
	}
};

3. 通过反射调用类的属性

public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException //取得本类声明的属性

public Field getField(String name) throws NoSuchFieldException,SecurityException //取得公共属性

设置值:public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException

取得值: public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException

在访问私有属性时,必须让该属性可见: public void setAccessible(boolean flag) throws SecurityException

建议:虽然可以这样直接这样操作对象的属性,但是还是建议通过setter和getter方法来调用属性,因为这样更安全。

4. 通过反射操作数组

获得数组得类型信息,Class中存在以下方法:public Class<?> getComponentType()

Array类中存在以下方法:public static Object newInstance(Class<?> componentType, int... dimensions) throws IllegalArgumentException,

        NegativeArraySizeException

则以上两个方法可以搭配使用,能以仅知道一个数组对象的时候,就能创建与该对象同样类型的数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值