黑马程序员 反射

-------------------android培训 java培训期待与您交流!-------------------


反     射



反射就是把Java类中各种成分如(成员变量,构造方法,方法等)
映射成相应的Java类。这样就可以通过成员变量、方法、构造方法

等来调用对象。那具体是怎样操作的呢?

Class对象
Java程序中许多对象在运行时都会有两种类型:编译时类型和运行时类型。
每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过Class对象可以访问到Java虚拟机中的这个类。
Java程序中获得Class对象有如下三种方式:
(1)使用Class类的forName()静态方法。该方法需要传入字符串参数,该字符串参数的值是某个类的全限定类名(必须添加完整的包名)。
(2)调用某个类的Class属性来获取该类对应的Class对象。比如:Person.class将返回Person类对应的Class对象。
(3)调用某个对象的getClass()方法,该方法是java.lang.Object类中的一个方法,所以所有Java对象都可以调用该方法,该方法返回该对象所属类对应的Class对象。
第一种和第二种方式都是直接根据类来获取该类的Class对象,但相比之下,第二种方式有如下两种优势:
(1)代码更安全,程序在编译阶段就可以知道需要访问的Class对象是否存在。
(2)程序性能更高,因为这种方式无须调用方法,所以性能更好。
所以大部分时候建议使用第二种来获取Class对象。当我们获取到Class对象后,程序就可以调用Class对象的方法来获取该类的真实信息。

从Class对象中获取信息
Class对应的类包含四个构造函数:
(1)Connstructor<T>   getConstructor(Class<?>... parameter types):返回此Class对象所表示的类的指定的public构造函数。
(2)Connstructor<T>[]   getConstructors():返回此Class对象所表示的类的所有public构造函数。
(3)Connstructor<T>   getDeclaredConstructor(Class<?>... parameter types):返回此Class对象所表示的类的指定构造函数,与构造的访问级别无关。
(4)Connstructor<T>[]   getDeclaredConstructosr():返回此Class对象所表示的类所有构造函数,与构造的访问级别无关。

访问Class对应的类所包含的方法:
(1)Metnod   getMethod(String name,Class<?>... parameter types):返回此Class对象所表示的类的指定public方法。
(2)Method[]   getMethods():返回此Class对象所表示的类的所有public方法。
(3)Method   getDeclaredMethod(String name,Class<?>... parameter types):返回此Class对象所表示的类的指定方法,与方法的访问级别无关。
(4)Method[]  getDeclaredMethods():返回此Class对象所表示的类的全部方法,与方法的访问级别无关。


访问Class对应的类所包含的属性(Field):
(1)Field   getField(String name):返回该Class对象所表示的类的指定的public属性。
(2)Field[]   getFields():返回该Class对象所表示的类的所有public属性。
(3)Field   getDeclaredField(String name):返回该Class对象所表示的类的指定属性,与属性的访问级别无关。
(4)Field[]   getDeclaredFields():返回该Class对象所表示的类的全部属性,与属性的访问级别无关。


访问Class对象的类上所包含的注解:
(1)<A  extends Annotation>  A  getAnnotation(Class<A>  annotationClass):试图获取该Class对象所表示类上指定类型的注解;如果该类型的注解不存在则返回null。
(2)Annotation[]   getAnnotations():返回此元素上存在的所有注解。
(3)Annotation[]   getDeclaredAnnotations():返回直接存在与此元素上的所有注解。
访问Class对象对应类包含的内部类
(1)Class<?>[]   getDeclaredClasses():返回该Class对象所对应类里包含的全部内部类。
(2)Class<?>   getDeclaringClass():返回该Class对象所对应类所在的外部类。
(3)Class<?>[]  getInterfaces():返回该Class对象对应类所实现的全部接口。
(4)int  getModifiers():返回此类或接口的所有修饰符。必须使用Modifier工具类,才能获得真实的修饰符。
(5)Package  getPackaget():获取此类的包。
(6)String  getName():以字符串形式返回此Class对象所表示的类的名称。
(7)String  getSimpleName():以字符串形式返回此Class对象所表示的类的简称。
(8)Class<? super T> getSuperclass():返回该Class所表示的类的超类(父类,基类)对应的Class对象。

Class对象用于判断该类是否为接口,枚举,注解类:
(1)boolean  isAnnotation():返回此Class对象是否表示一个注解类型。
(2)boolean  isAnnotationPresent(Class<? extends Annotation>  annotationClass):判断此Class对象上是否使用了Annotation注解修饰。
(3)boolean  isAnonymousClass():返回此Class对象是否是一个匿名类。
(4)boolean  isArray():返回此Class对象是否表示一个数组类。
(5)boolean  isEnum():返回此Class对象是否表示一个枚举类。
(6)boolean  isInterface():返回此Class对象是否表示一个接口。
(7)boolean  isInstance(Object obj):判断obj是否是此Class对象的实例,该方法可以完全代替instanceof操作符。
通过Class对象,如果我们需要确定一个方法,应该由方法名和形参列表来确定。比如:clazz.getMethod("method1",String.class);这样来确定一个叫method1(String str)的方法。确定构造函数则只需要参数列表就OK了,因为同一个类的所有构造函数的名字都是相同的。

使用反射生成并操作对象

创建对象
反射创建对象有两种方式:
(1)使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认的构造函数,而执行newInstance()方法时,实际上是利用默认的构造函数来创建类的实例。
(2)先使用Class对象获取指定的Constructor对象,在调用Constructor对象的newInstance()方法来创建该Class对象对应的实例。通过这种方式可以选择使用某个类的指定构造函数来创建实例。

写两个小程序演示一下:

//第一个:一个类调用令一个类的main方法:
package cn.itcast.day1;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
//定义一个类,该类的主函数用于打印字符串数组中的元素
class MainFun{
	public static void main(String[] args){
		for(String arg :args)
			System.out.println(arg);
		}
}
public class MainMethod {
	public static void main(String[] args){ 
		String str = args[0];
		Method mainMethod = null;
		try {
			//获取方法类的实例对象
			mainMethod = Class.forName(str).getMethod("main",String[].class);
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
		//调用类,并传入参数
		//由于main方法是静态方法,因此不能传入实例对象,用类名调用,只传入null
		//需要在运行时传入MainMethod类即:cn.itcast.day1.MainMethod
		mainMethod.invoke(null, new Object[]{new String[]{"sdsf","err","wwf"}});
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

运行结果:

sdsf

err

wwf

//第二个:从配置信息中动态地获取一个集合:
//定义一个类,覆盖equals和hashCode方法。
package cn.itcast.day1;
public class ReflectValue {
	private int x;
	private int y;
	public ReflectValue(int x, int y) {
		super();
		this.x = x;
		this.y = y;
	}
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
	ReflectValue other = (ReflectValue) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}
}

//配置信息,HashSet集合

//把ReflectValue类写入配置信息中的集合:
package cn.itcast.day1;
import java.io.*;
import java.util.*;

public class ReflectProperties {
	public static void main(String[] args) {
		ReflectValue rv1= new ReflectValue(2,4);
		ReflectValue rv2= new ReflectValue(5,6);
		ReflectValue rv3= new ReflectValue(7,8);
		ReflectValue rv4= new ReflectValue(2,4);
		InputStream ips = null;
		try {
			ips = new FileInputStream("config.properties");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Properties props = new Properties();
		try {
			props.load(ips);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			ips.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	String className = props.getProperty("className");
	Collection<ReflectValue> coll = null;
	try {
		coll = (Collection<ReflectValue>)Class.forName(className).newInstance();
	} catch (InstantiationException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IllegalAccessException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (ClassNotFoundException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	coll.add(rv1);
	coll.add(rv2);
	coll.add(rv3);
	coll.add(rv4);
	System.out.println(coll.size());
	}
}

运行结果:

3

改变配置信息:

运行结果:

4




------------------- android培训  java培训 期待与您交流!-------------------

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值