黑马程序员———反射

来源:互联网 发布:网络教育的本科学历国家承认吗 编辑:程序博客网 时间:2024/05/29 15:21

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流------

一.反射的基础---Class类

1.1一个类对应一个.java文件,编译时期编译为.class文件,运行时把.class文件加载到内存中得到对应的字节码,内存中的每一份字节码就是一个Class类型的对象,一个源程序中可能包含多个类,运行时也就会在内存中产生多份字节码,也即多个Class类型的对象,通常有三种方法获取类对应的Class类型的对象,以String类为例,示例代码如下:

public class ReflectDemo {public static void main(String[] args) {try {String str=new String("abc");Class cls1=str.getClass();Class cls2=String.class;Class cls3=Class.forName("java.lang.String");System.out.println(cls1==cls2);//输出trueSystem.out.println(cls1==cls3);//输出trueSystem.out.println(cls1.isPrimitive());//输出false,String类对应的Class类型的对象不是原始(基本)类System.out.println(int.class.isPrimitive());//输出true,int对应的Class类型的对象是原始(基本)类System.out.println(Integer.class.isPrimitive());//输出falseSystem.out.println(Integer.TYPE.isPrimitive());//输出true,Integer.TYPE等价于int.class} catch (ClassNotFoundException e) {e.printStackTrace();}}}

二.构造方法的反射应用

2.1通过每个类对应的Class类型的对象(也即加载到内存中的字节码)的getConstructor()方法可以获取到该类的某个构造方法(每个构造方法属于Constructor 类型的对象),具体是哪个构造方法要看传入的参数,getConstructor(StringBuffer.class)获取到的构造方法在调用时只能传入StringBuffer类型的参数,通过Constructor 类型对象的newInstance()方法可以创建出一个Object类型的对象并可强转为对应类的对象,示例代码如下:

public class ReflectDemo {public static void main(String[] args) {try {Constructor constructor=String.class.getConstructor(StringBuffer.class);//newInstance方法返回的是Object类型的对象String str=(String)constructor.newInstance(new StringBuffer("abc"));System.out.println(str.charAt(2));} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}

三.成员变量的反射应用

3.1Constructor 类型的对象表示类中的一个构造方法,由于一个类可能有几个构造方法,具体是哪个构造方法由getConstructor()方法传入的参数确定(传入的参数类型是Class),同理,Field类型的对象表示类中的一个成员变量,由于一个类可能有几个成员变量,具体是哪个成员变量也是由getField()方法传入的参数确定(传入的就是成员变量名),若是私有的成员变量,则调用getDeclaredField()方法,想要获取某个对象对应的成员变量值是通过Field类型的对象调用get()方法,该方法传入对象对应的引用变量,若是私有的成员变量,则还需调用setAccessible(true)方法才能获取到,示例代码如下:

public class ReflectPoint {private int x;public int y;public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}}

public class ReflectDemo {public static void main(String[] args) {try {ReflectPoint rp=new ReflectPoint(3, 5);Field fieldX=rp.getClass().getDeclaredField("x");fieldX.setAccessible(true);System.out.println(fieldX.get(rp));Field fieldY=rp.getClass().getField("y");System.out.println(fieldY.get(rp));} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchFieldException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}

3.2成员变量反射综合案例,将任意一个对象的String类型的所有成员变量所对应的字符串内容中的字符'b'改为字符'a',示例代码如下:

public class ReflectPoint {private int x;public int y;public String str1="ball";public String str2="basketball";public String str3="itcast";public ReflectPoint(int x, int y) {super();this.x = x;this.y = y;}@Overridepublic String toString() {return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3="+ str3 + ", x=" + x + ", y=" + y + "]";}}

public class ReflectDemo {public static void main(String[] args) {try {ReflectPoint rp=new ReflectPoint(3, 5);Field[] fields=rp.getClass().getFields();for (Field field : fields) {//这里使用==是因为等式两边都表示String类对应的字节码,是同一份字节码if(field.getType()==String.class){String oldValue=(String) field.get(rp);String newValue=oldValue.replace('b', 'a');field.set(rp, newValue);}}System.out.println(rp);} catch (SecurityException e) {e.printStackTrace();}   catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}
四.成员方法的反射应用
4.1对类中普通成员方法,静态成员方法的调用,示例代码如下:

public class ReflectDemo {public static void main(String[] args) {String str=new String("abc");System.out.println(str.charAt(2));//下面通过反射来实现对象对所在类成员方法的调用try {Method methodCharAt=String.class.getMethod("charAt", int.class);//若是对静态成员方法的调用则将对象名str换成nullSystem.out.println(methodCharAt.invoke(str, 2));} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}
4.2用反射的方式执行某个类的main方法,示例代码如下:

public class ReflectDemo {public static void main(String[] args) {//首先使用普通方式调用ReflectTest.main(new String[]{"111","222","333"});//下面使用反射的方式调用try {Method mainMethod=ReflectTest.class.getMethod("main", String[].class);//若将第二个参数写成new String[]{"111","222","333"},编译器会对数组进行拆包//得到三个参数,这与main方法只传入一个参数不符,所以把字符串数组对象强转为Object对象,目的就是防止对数组拆包mainMethod.invoke(null, (Object)new String[]{"111","222","333"});} catch (SecurityException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}}class ReflectTest{public static void main(String[] args) {for (String str : args) {System.out.println(str);}}}

五.数组与Object关系及其反射类型

5.1数组与Object关系,示例代码如下:

public class ReflectDemo {public static void main(String[] args) {int[] a1=new int[]{1,2,3};int[] a2=new int[3];int[][] a3=new int[2][3];String[] a4=new String[]{"111","222","333"};System.out.println(a1.getClass().getName());//输出[ISystem.out.println(a3.getClass().getName());//输出[[ISystem.out.println(a4.getClass().getName());//输出[Ljava.lang.String;System.out.println(a4.getClass().getSuperclass().getName());//输出java.lang.ObjectSystem.out.println(a1.getClass()==a2.getClass());//a3,a4都属于Object[],a1,a2则不属于Object[] obj3=a3;Object[] obj4=a4;System.out.println(a1);//输出[I@18a992fSystem.out.println(Arrays.asList(a1));//输出[[I@18a992f]System.out.println(a4);//输出[Ljava.lang.String;@1bab50aSystem.out.println(Arrays.asList(a4));//输出[111, 222, 333]}}

5.2数组的反射应用,上述示例代码已经说明直接打印数组对象是不会得到数组中每个元素的,利用反射的方式可以将任何数组对象中的所有元素直接打印出来,示例代码如下:

public class ReflectDemo {public static void main(String[] args) {int[] a1=new int[]{1,2,3,4};String[] a2=new String[]{"111","222","333","444"};printObj(a1);System.out.println();printObj(a2);}public static void printObj(Object obj){Class clazz=obj.getClass();if(clazz.isArray()){int len=Array.getLength(obj);for (int i = 0; i < len; i++) {System.out.print(Array.get(obj, i)+"  ");}}else{System.out.println(obj);}}}





0 0