黑马程序员.Android攻城狮.JAVA高新.2.2.Java 高新技术(2)

Java 高新技术(2)

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

1、反射的概念

        什么是字节码:它是经过编译器预处理过的一种文件,是Java执行文件存在的形式,它本身是二进制文件,但是不可以被系统执行,需要虚拟机加载执行。
        反射就是把Java类中的各个成分映射成相应的java类,一个类用一个Class类的对象表示,一个类中的组成部分,如成员变量、构造方法、普通方法等信息也可以用一个个java类来表示,Class类中提供了很多方法,而且Field、Method、Constructor等可以用于获取类中内容所属于的类。
        Class的实例对象:加载的每个类在内存中的字节码就是一个Class对象,在Java中允许通过一个实例化对象找到一个类的完整信息,获取的方法主要有三种,如下面的代码中所示:
public class DemoReflect {
	public static void main(String[] args) throws ClassNotFoundException {
		String s1 = new String("abc");
		Class c1 = s1.getClass();
		Class c2 = String.class;
		Class c3 = Class.forName("java.lang.String");
		System.out.println(c1 == c2);
		System.out.println(c1 == c3);
		System.out.println(c3 == c2);
	}
}

运行结果:
true
true
true

        (1) 可通过一个类的实例化对象获取,由于每个类都是Object类的子类,而Object类中定义了getClass方法可以获取类的信息
        (2) 可通过类中的Class属性获得,每个类中都有一个Class属性
        (3) 可调用Class类的静态方法forName获取
        Class类的常用方法有:
                public String  getName(); Class类中最常用的方法getName以 String 的形式返回此 Class 对象所表示
        的实体(类、接口、数组类、基本类型或 void)名称
                public package  getPackage();得到一个类的包信息
                public Class[] getInterface();得到一个类中所实现的全部接口
                public Method[] getMethods();得到一个类中的全部方法
                public Method getMethod(String name, Class ...Parameter Types);得到一个Method对象,并设置
        一个方法中的所有参数类型
                public Field[] getDeclaredFields();得到本类中单独定义的全部属性
                public Field[] getFields();得到本类继承而来的全部属性
                public Constructor[] getConstructors();得到一个类中的全部构造方法
                public static Class<?> forName(String className);得到实例化Class对象
                public Object newInstance(); 根据Class定义的类实例化对象
                public Class<?>  getComponentType(); 返回表示数组组件类型的 Class
                public Class  getSuperclass(); 返回表示此 Class 所表示的实体的超类的 Class
                public boolean  isArray(); 判定此 Class 对象是否表示一个数组类

        从以上三种方法可以看出,前两种都需要传入导入一个明确的类,如果一个类不明确的时候,使用起来就会受到一些限制,所以第三种方式更加的灵活,也是最常用的一种方式。

2、反射的应用

        (1) Constructor类
        Constructor类代表一个类中的一个构造方法,若想获取类的全部构造方法,则可 通过使用Class的方法getConstructors()即可获取,如:Constructor[] con = Class.forName("java.lang.String").getConstructors()。
        还可以得到某个单独的构造方法,如:
         Constructor con = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
        这里我们使用了Class中的方法: public Constructor<T> getConstructor(Class<?>... parameterTypes),可以根据可变参数列表得到具有相应参数的构造方法。
        获取构造方法后可以使用该构造方法创建一个对象,即使用Constructor类中的newInstance方法,如下代码所示:
import java.lang.reflect.Constructor;

public class DemoReflect1 {
	public static void main(String[] args) throws Exception {
	    Constructor con1 = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
	    String s = (String)con1.newInstance(new StringBuffer("abcd"));
	    System.out.println(s);
	}
}

        在Class类中还存在一个无参的newInstance方法,使用该方法可以通过Class类本身实例化一个其他类的对象,但是必须要保证被实例化的类中存在一个无参构造方法。
public class DemoReflect {
	public static void main(String[] args) throws Exception {
	    Class c = Class.forName("Person");
	    System.out.println(c);
	    Person p = (Person) c.newInstance();
	    p.setAge(20);
	    System.out.println(p.getAge());
	}
}
class Person{
	private String name;
	private int age;
	public Person(){}
	public Person(String name, int age){
		this.name = name;
		this.age = age;
	}
	public void setName(String name){
		this.name = name;
	}
	public void setAge(int age){
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
}

        (2) Field类
        Field类表示一个类中的成员变量,使用Class类中的方法: public Field[] getDeclaredFields()与public Field[] getFields()可以得到本类中单独定义的全部属性或者是 得到本类从父类继承而来的或者是继承接口的全部属性。这两种方法返回的都是Field类型的数组,每一个对象表示一个类中的属性,Field类中的主要方法有:
        public Object get(Object obj);得到一个对象中属性的具体内容
        public void set(Object obj, Object value);设置指定对象中属性的具体内容
        public int getModifiers();得到属性的修饰符
        public String getName();返回此属性的名称
        public boolean isAccessible();判断此属性是否可被外部访问
        public void setAccessible();设置一个属性是否可被外部访问
        以下代码为通过反射获取Person类中的私有属性的内容:
import java.lang.reflect.Field;

public class DemoReflect1 {
	public static void main(String[] args) throws Exception {
		Person p = new Person("hao",20);
	    Class c = p.getClass();
	    Field[] f = c.getDeclaredFields();//获取全部的属性
	    for(int i=0;i
   
   

        下面的程序演示了使用反射获取对象中的属性,并修改其属性
import java.lang.reflect.Field;

public class DemoReflect1 {
	public static void main(String[] args) throws Exception {
		Person p = new Person("hao",20,"china");
	    Class c = p.getClass();
        Field[] f = c.getDeclaredFields();//获取本类全部的属性,包括private,但是访问需要设置Accessible
	    for(Field s : f){
	    	s.setAccessible(true);//设置私有属性可被访问
	    	if(String.class == s.getType()){
	    		String buf = (String)s.get(p);
	    		buf = buf.toUpperCase();//将String类型的属性变为大写
	    		s.set(p, buf);
	    	}
	    	System.out.println(s.get(p));//获取p对象各个属性的值
	    }
    }
}
class Person{
	private String name;
	private String country;
	private Integer age;
	public Person(){}
	public Person(String name, int age, String c){
		this.name = name;
		this.age = age;
		this.country = c;
	}
	private Person(String name){
		this.name = name;
	}
	public void setName(String name){
		this.name = name;
	}
	public void setAge(int age){
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
}

        (3) Method类
        Method类表示类中的方法,要取得类中的方法,可以使用Class类中的getMethods方法,此方法返回一个Method类型的对象数组,Method类中的方法有:
        public int getModifiers();取得本方法中的访问修饰符
        public String getName();取得方法的名称
        public Class<?> getParameterTypes();得到方法的全部参数类型
        public Class<?> getReturnType();得到方法的返回值类型
        public Class<?> getExceptionTypes();得到一个方法的全部抛出异常
        public Object invoke(Object obj, Object...args);通过反射调用类中的方法

3、反射的深入应用    

        反射除了可以得到一个类中的结构之外,还能够调用类中指定的方法,并且可以通过反射完成对数组的操作。
        (1) 通过反射调用一个类中的方法        
        想要调用类中的方法可以通过Method类完成,步骤如下:
        (a) 通过Class类的getMethod方法取得一个Method对象,并设置此方法操作时所需要的参数类型;
        (b) 使用invoke方法调用,并向方法中传递要设置的参数。
        下面的程序演示了使用反射调用一个类中的main方法:
import java.lang.reflect.*;

public class DemoReflect2 {
	public static void main(String[] args) throws Exception {
		Method me = Class.forName("com.day2.Test")
		                .getDeclaredMethod("main", String[].class);
		me.invoke(null, (Object)new String[]{"hello","java"});
	}
}
class Test{
	public static void main(String[] args){
		for(String arg : args)
			System.out.println(arg);
	}
}

        一个类中的属性必须封装,而属性的设置要通过setter及getter方法,那么使用反射进行setter及getter的设置是极为重要的应用。下面的程序演示了使用反射调用类中的setter及getter方法:
import java.lang.reflect.*;

public class DemoReflect2 {
	public static void main(String[] args) throws Exception{
		Person p1 = new Person();
		setter(p1, "setName", "howard", String.class);
		setter(p1, "setAge", 30, int.class);
		System.out.println("姓名:");
		getter(p1,"getName");
		System.out.println("年龄:");
		getter(p1,"getAge");
	}
	public static void setter(Object obj, String method, Object value, Class
    
     c) throws Exception {
		Method m = obj.getClass().getDeclaredMethod(method, c);
		m.invoke(obj, value);
	}
	public static void getter(Object obj, String method) throws Exception {
		Method m = obj.getClass().getDeclaredMethod(method);
		System.out.println(m.invoke(obj));
	}
}
class Person{
	private String name;
	private Integer age;
	public Person(){}
	public Person(String name, int age){
		this.name = name;
		this.age = age;
	}
	public void setName(String name){
		this.name = name;
	}
	public void setAge(int age){
		this.age = age;
	}
	public String getName(){
		return name;
	}
	public int getAge(){
		return age;
	}
}

        (2) 通过反射操作数组
        反射不仅能够应用在类上,还能够应用在数组上,即可以使用反射操作数组。
        具有相同维数和相同数据类型、且长度可以不同的两个数组的Class为同一类型,具有相同的字节码。基本数据类型的一维数组可以当做Object使用,非基本类型的一维数组可以当做Object或者Object[]使用。
        在java.lang.reflect包中使用Array类表示一个数组,可以通过此类取得数组长度、内容等操作,Array类的常用方法有:
        public static Object get(Object array, int index);根据下标取得数组的内容
        public static Object newInstance(Class<?> componentType, int length);根据已有的数组类型开辟新的数组对象

        public static void set(Object array, int index, Object value);修改指定位置的内容

4、通过反射模拟框架的功能

        采用配置文件加反射的方式创建ArrayList于HashSet的实例对象,比较程序运行的差异。

import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;

public class DemoReflect3 {
	public static void main(String[] args) throws Exception {
		//加载配置文件
		InputStream in = DemoReflect3.class.getResourceAsStream("config.properties");
		Properties prop = new Properties();
		prop.load(in);
		in.close();
		String className = prop.getProperty("className");
		System.out.println(className);
		//根据加载的配置文件创建指定类型的集合
		Collection c = (Collection)Class.forName(className).newInstance();
		Person p1 = new Person("a",23);
		Person p2 = new Person("b",33);
		Person p3 = new Person("c",34);
		c.add(p1);
		c.add(p2);
		c.add(p3);
		c.add(p3);
		System.out.println(c.size());
	}
}

//定义一个config.properties文件,存放到与源文件相同的包下
//属性文件的内容为
className=java.util.HashSet
//然后修改属性文件的内容为,观察前后运行的结果
className=java.util.ArrayList
        以上代码实现了通过外部配置文件改变程序功能,Java程序通过反射的方式从配置文件获取信息,并创建相应的类,这就简单的模拟了一个框架的功能。

        

---------- Windows Phone 7手机开发、.Net培训、期待与您交流! ----------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值