黑马程序员—Java反射

来源:互联网 发布:全国进出口数据 编辑:程序博客网 时间:2024/04/28 22:01

14. 反射

 

 

14.1   Class类

 

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。

 

Class.forName(String) 该方法返回字节码。如果字节码曾经被加载过,存在于jvm中,则直接返回。如果jvm中还没有此字节码,则用类加载器去加载,将其缓冲在jvm中

此方法会抛出ClassNotFoundException异常,因为输入的String有可能不是一个对象。

 

如何得到各个字节码对应的对象(即Class对象,但并不是有具体参数的实例对象):

1)  类名.class 如 Person.class

2)  对象.getClass() 如 new Date().getClass()

3)  Class.forName(“类名”) 如Class.forName(“java.util.Date”)

class ReflectTest {public static void main(String[] args) throws Exception{String str1 = "abc";Class cls1 = str1.getClass();Class cls2 = String.class;Class cls3 = Class.forName("java.lang.String");/*三者得到的都是同一份字节码,对应的都是String类,  而String类可以创造多个不同的实例化对象*/System.out.println(cls1==cls2);    //trueSystem.out.println(cls1==cls3);    //trueSystem.out.println(cls2==cls3);    //true/*String类不是基本类型,Integer也不是,而Integer封装的TYPE是。  即:boolean、byte、char、short、int、long、float 和 double*/System.out.println(cls1.isPrimitive());    //falseSystem.out.println(Integer.class.isPrimitive());  //falseSystem.out.println(Integer.TYPE==int.class);  //trueSystem.out.println(Void.TYPE.isPrimitive()); //true。Void是一个占位符类}}

Class.newInstance():该方法内部先得到默认的空参数的构造方法,然后用该构造方法创建实例对象。该方法内部用了缓存机制来保存默认构造方法的实例对象。

如:Stringobj = (String)Class.forName(“java.lang.String”).newInstance () //得到空字符序列


14.2   反射

 

1)  反射就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等

2)  一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象。

 

 

14.3  Constructor类

 

Constructor类代表某个类中的一个构造方法

 

得到某个类所有的构造方法:

Constructor[] constructors = Class.forName("java.lang.String").getConstructors();

 

得到某一个构造方法:

Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);

getConstructor()方法中传入的参数是想要获取的构造方法能够传入的参数,如果该构造方法能传入多个参数,getConstructor()中可以传入一个包含这些参数的数组,也可以利用1.5新特性,直接将各个参数写入,用“ , ”分割

 

使用Constructor中的newInstance()方法,可以将得到的构造方法实例化(即使用此方法),注意使用时需要进行强转,因为jvm并不知道得到的Constructor对象是哪个类中的构造方法。newInstance()中传入的参数就是对应构造方法传入的参数。

import java.util.*;import java.lang.reflect.*;class ConstructorDemo {public static void main(String[] args) throws Exception{Constructor[] constructors = Class.forName("java.lang.String").getConstructors();System.out.println(Arrays.toString(constructors));//获得的构造方法是以StringBuffer对象为参数的。Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);String str = (String)constructor.newInstance(new StringBuffer("abc"));System.out.println(str);}}


14.4  Field类

 

Field类代表某个类中的一个成员变量

import java.lang.reflect.*;class FieldDemo {public static void main(String[] args) throws Exception{ReflectPoint pt1 = new ReflectPoint(3,5);//获取类中的成员变量/*Field只代表获取到的类中的某个变量,不代表该变量在某个实例对象中的值  如果该成员变量用private修饰,则此方法会报出NoSuchFieldException异常*/Field fieldY = pt1.getClass().getField("y");//获取类中的成员变量,private修饰的同样可以获取Field fieldX = pt1.getClass().getDeclaredField("x");//获取成员变量在某个实例对象中的值System.out.println(fieldY.get(pt1));//通过setAccessible(true)方法才能够得到private修饰的成员变量值fieldX.setAccessible(true);System.out.println(fieldX.get(pt1));}}class ReflectPoint {private int x;public int y;ReflectPoint(int x,int y){this.x = x;this.y = y;}}

映射Field类应用:

//将某个对象实例中所有String类型的成员变量中的字符b替换成字符a:import java.lang.reflect.*;class FieldTest {public static void main(String[] args) throws Exception{ReFlectPoint2 pt2 = new ReFlectPoint2("hbhb","bob");//获取包含所有成员变量的数组Field[] fields = pt2.getClass().getFields();for(Field field : fields){//判断成员变量类是否是String 类型的类字节码用==比较,因为同一个类的字节码在虚拟机中是唯一的if(field.getType() == String.class){//获取该变量在pt2中的值String oldValue = (String)field.get(pt2);//将该值中的b字符替换成a字符String newValue = oldValue.replace('b','a');//将该变量在pt2中的值设置成新的值。field.set(pt2,newValue);}}System.out.println(pt2);}}class ReFlectPoint2{public String str1;public String str2;public String str3 = "itcast";ReFlectPoint2(String str1,String str2){this.str1 = str1;this.str2 = str2;}public String toString(){return str1 + ":" + str2 + ":" + str3;}}


14.5  Method类

 

Mthod类代表某个类中的一个成员方法

import java.lang.reflect.*;class MethodDemo {public static void main(String[] args) throws Exception{String str = "abc";//获得的方法是以一个int类型的值为参数的Method methodcharAt = Class.forName("java.lang.String").getMethod("charAt",int.class); //对str调用此方法,invoke(obj,args)中第二个参数是原方法要传入的参数System.out.println(methodcharAt.invoke(str,1));//如果该方法是静态的,则通过Method的invoke方法调用时,第一个参数传null//Method.invoke(null,args)}}

JDK1.4和JDK1.5的invoke方法的区别:

JDK1.5:public Object invoke(Objectobj,Object…args)

JDK1.4:public Object invoke(Objectobj,Object[] args)

则上述的methodcharAt.invoke(str,1)可以写成methodcharAt.invoke(str, new Object[ ]{1})


14.6  数组的反射

 

1) 具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象

2) 代表数组的Class实例对象的getSuperclass()方法返回的父类为Object类对应的Class

3) 基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当作Object类型使用,又可以当作Object[]类型使用。

4) Arrays.asList()方法处理int[]和String[]时的差异

import java.util.*;class ArrayReflect {public static void main(String[] args) {int[] a1 = new int[]{1,2,3};int[] a2 = new int[4];int[][] a3 = new int[2][3];String[] a4 = new String[]{"a","b","c"};//a1和a2属于同一个类型System.out.println(a1.getClass() == a2.getClass());System.out.println(a1.getClass().getSuperclass().getName());System.out.println(Arrays.asList(a1));                   // 输出a1的内存地址System.out.println(Arrays.asList(a4));                   // 输出a,b,c/*因为需要兼容JDK1.4的方法,所以传入a4时,使用的是asList(Object[] a),将数组中每一个String传入List中。而传入a1时,因为int不是Object子类,使用的是asList(T... a),所以将a1作为一个参数(数组对象)传入到List当中。因此a4可以输出每个字符串对象,而a1只能输出作为一个数组对象的内存地址*/}}


14.7  反射的作用: 实现框架功能

 

1) 框架:

框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类

2) 框架要解决的核心问题:

因为在写程序是无法知道要被调用的类名,所以,在程序中无法直接new某个类的实例对象了,而要同反射方式来做。


利用反射建立的小框架:

框架并不知道需要建立什么样的集合对象,通过读取文件来建立相关的集合

import java.util.*;import java.io.*;class  FrameworkDemo{public static void main(String[] args) throws Exception{//尽量面向父类或接口编程,通过读取文件来获取className的值InputStream ips = new FileInputStream("d:\\workspace\\java\\config.properties");Properties props = new Properties();props.load(ips);ips.close();String className = props.getProperty("className");//通过读取到的className建立相关类型的对象Collection collections = (Collection)Class.forName(className).newInstance();ReflectPoint pt1 = new ReflectPoint(3,3);ReflectPoint pt2 = new ReflectPoint(5,5);ReflectPoint pt3 = new ReflectPoint(3,3);collections.add(pt1);collections.add(pt2);collections.add(pt3);collections.add(pt1);//根据文件中设置className为ArrayList和HashSet得到不同的结果。System.out.println(collections.size());}}




0 0