反射(java基础)

来源:互联网 发布:php日期比较 编辑:程序博客网 时间:2024/05/14 13:03

一、反射的基础:Class

 

         1. 概述                             

             java用于描述一类事物的共性,该类事物有什么属性,没有什么属性,java程序中的各
          个java类,他们是否属于同一类事物?这个类的的名称就是Class。
             

        2. Class类:

              1. Class加载一个class,虚拟机会在内存里生成一个字节码,通过该字节码可以创建多个
             对象。    
             2.格式:
                  //Class cls1 = Person.class;
                  //Class cls2 = p1.getClass();
                  //Class cls3 = Class.forName("java.lang.String");//查询,加载字节码    

             3. 三种方式获取到的字节码是相等的

             4. 只要在源程序中出现的数据类型,都有各自的Class实例对象。例如:int[]和void

 */public static void main(String[] args) throws Exception{String str1 = "st1";Class<? extends String>  cls1 = str1.getClass();Class<String> cls2 = String.class;Class<?> cls3 = Class.forName("java.lang.String");System.out.println("cls1="+cls1+"\tcls2="+cls2+"\t比较结果:"+(cls1==cls2));System.out.println("cls1="+cls1+"\tcls3="+cls3+"\t比较结果:"+(cls1==cls3));System.out.println(cls1.isPrimitive());System.out.println(int.class.isPrimitive());System.out.println(int.class == Integer.TYPE);// 基本类型的字节码和它对应的对象的TYPE是相等的。 即int.class == Integer.TYPE;System.out.println(int[].class.isPrimitive()); System.out.println(int[].class.isArray());Class<Void> clsv = void.class;System.out.println(clsv);}

二、 反射:

     * 1. 概述:

     *         反射就是把java类中的各种成分映射成对应的java类。

     * 2. 构造方法的反射应用

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

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

     *         eg:Constructor[]  constructors= Class.forName("java.lang.String").getConstructor();

     *         得到某一个构造方法:(获得方法时要用到类型)

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

     *         创建实例对象:(调用方法时要用到类型)

     *             *通常方式:String str = new String(new StringBuffer("abc"));

     *             *反射方式:String str = (String)constructor.newInstance(new StringBuffer("abc"));

public static void MethodDemo() throws NoSuchMethodException,InstantiationException, IllegalAccessException,InvocationTargetException {//构造方法的反射//new String();Constructor<String> constructor = String.class.getConstructor(StringBuffer.class); //jdk1.5新特性,可变参数String str = constructor.newInstance(new StringBuffer("abc"));System.out.println(str);}


     * 3. 成员变量的反射应用

     *         详情见例子:

 

public static void FieldDemo() throws NoSuchFieldException,IllegalAccessException {Person person = new Person("ss","basketball",5);//Field personname = person.getClass().getField("name");  //getField只能访问共有的成员Field personname = person.getClass().getDeclaredField("name");  //getDeclaredField  无论是否公开都能看到personname.setAccessible(true);                                 //setAccessible:是否允许我强行获取//fieldname的值是ss吗?不是!!!!System.out.println(personname.get(person));}


     * 4. 成员变量案例

private static void changeString1(Object obj) throws Exception{Field filed = obj.getClass().getDeclaredField("hobby");  filed.setAccessible(true);if(filed.getType()==String.class){//这里用"==",因为同一个字节码用==比较准确String oldValue = (String)filed.get(obj);String newValue = oldValue.replace('u', 'a');filed.set(obj, newValue);}}private static void changeString(Object obj) throws Exception{Field[] filed = obj.getClass().getFields();  //获取obj内所有的成员变量for(Field fil : filed){if(fil.getType()==String.class){//这里用"==",因为同一个字节码用==比较准确String oldValue = (String)fil.get(obj);String newValue = oldValue.replace('a', 'b');fil.set(obj, newValue);}}}

三、Method类:

     1. Method基础应用

     * Method类代表某个类中的一个成员方法
     * 得到类中的某一个方法:
     * eg:Method charAt = Class.forName("java.lang.String").getMethod("charAt",int.class);
     * 调用方式:System.out.println(str.charAt(1));
     * 反射方式:System.out.ptintln(charAt.invoke(str,1));
   

public static void main(String[] args)throws Exception {//str.charAt(1);String str = "It's my class";//普通调用System.out.println(str.charAt(1));//反射调用Method methodCharAt = String.class.getMethod("charAt",int.class);System.out.println(methodCharAt.invoke(str,1));System.out.println(methodCharAt.invoke(str,new Object[]{2}));//1.4特性   Object invoke(Object obj, Object[])  }

     2.main方法的反射调用

     为什么要用反射,因为我不知道这个main()方法是属于谁的 ,所以用反射
     *
     * 需求:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法
     * 注意:main()方法的参数是一个字符串数组,而invoke()方法版本中,会将后面的数组当作参数打散。
     * 所以不能使用mainMethod.invoke(null,new String[]{"xxxx"});
     * 解决办法:  

                1. mainMethod.invoke(null,new Object[]{new String[]{"xxxx"}})
                2. mainMethod.invoke(null,(Object)new String[]{"cccc"});

class TestArguments{public static void main(String[] args){for(String arg : args){System.out.println(arg);}}}public class MainTest {/** * @author Mr.z *  * 为什么要用反射,因为我不知道这个main()方法是属于谁的 ,所以用反射 *  * 需求:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法 *  *  * 注意:main()方法的参数是一个字符串数组,而invoke()方法版本中,会将后面的数组当作参数打散。 * 所以不能使用mainMethod.invoke(null,new String[]{"xxxx"}); * 解决办法:1. mainMethod.invoke(null,new Object[]{new String[]{"xxxx"}}) * 2. mainMethod.invoke(null,(Object)new String[]{"cccc"}); */public static void main(String[] args)throws Exception {//静态方式调用main方法TestArguments.main(new String[]{"111","222"});//反射方式调用String startingClassName = args[0];Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);//mainMethod.invoke(null, new Object[]{new String[]{"123"}});mainMethod.invoke(null,(Object)new String[]{"123"});}}

四、数组反射

      1、反射类型:

     *          1. 具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
     *          2. 代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class
     *          3. 基本类型的一维数组可以被当作Object使用,不能作为Object[]使用。非基本类型的一维数组,既
     *         可以被当作Object使用,又能作为Object[]使用
     *          4. Arrays.asList()方法处理int[]和String[]时候,不能直接用来处理int[]

     2、数组反射的应用

import java.lang.reflect.Array;import java.util.Arrays;public class ArrayFelection {/** * @author Mr.zz          */public static void main(String[] args) throws Exception {//ArrayTest();String [] str = {"aaaa","bbbb","cccc"};Object obj = str;printObject(obj);printObject("asdfsdfsad");}private static void printObject(Object obj) {Class<?> cla = obj.getClass();   //获取字节码文件if (cla.isArray()) {int lang = Array.getLength(obj);for (int i = 0; i < lang; i++) {System.out.println(Array.get(obj,i));}} else {System.out.println(obj);}}public static void ArrayTest() {int[] a1 = new int[] { 4, 5, 6 };int[] a2 = new int[4];int[][] a3 = new int[2][3];String[] a4 = new String[] { "a", "b", "c" };System.out.println(a1.getClass() == a2.getClass());Class<?> c1 = a1.getClass();Class<?> c3 = a3.getClass();Class<?> c4 = a4.getClass();System.out.println(c1 == c3);System.out.println(c1 == c4);System.out.println(a1.getClass().getName());System.out.println(a1.getClass().getSuperclass().getName());System.out.println(a4.getClass().getSuperclass().getName());// Object obj1 = a1;// Object obj2 = a2;// Object[] objError = a1; //这是错误的,因为基本数据类型不是对象// Object[] obj3 = a3;// Object[] obj4 = a4;System.out.println(a1);System.out.println(a4);System.out.println(Arrays.asList(a1)); // 会报错,因为int不是对象System.out.println(Arrays.asList(a4));}

五、反射的综合应用:制作框架

代码:

import com.itema.bean.ReflectPoint;public class ReflectDemo1 {/** * @author Mr.zz * 反射的综合应用:制作框架 *  */public static void main(String[] args) throws Exception {//HashSetDemo_Leak();InputStream ips = new FileInputStream("config.properties");Properties props = new Properties(); //等效于hashMap,但是它可以从文件中读取大量元素,而不必一个一个读取//从文件中读取信息props.load(ips);         //良好的习惯:用完就关闭,避免内存泄漏ips.close();    String className = props.getProperty("className1");@SuppressWarnings("unchecked")Collection<Object> collections = (Collection<Object>)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);//pt1.y = 7;collections.remove(pt1); //因为pt1的hash值在存入的时候通过计算,将pt1存在了相应的区域,然后我们改变流y的值, //此时pt1的hash值已经改变,此时在对应得内存hash值区域并不能找到pt1,所以此时内存发生了泄露System.out.println(collections.size());}
注意:要在工程目录下新建一个名为config.properties的配置文件,并输入以下代码。

      所谓框架就是被别人调用的。所以用反射调用配置文件里的信息可以方便别人修改

 className1 = java.util.ArrayList className1 = java.util.HashSet  




0 0
原创粉丝点击