黑马程序员---自学随堂笔记----反射

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制,总而言之就是把java类中各种成分映射成相应的java类。

获取Class的方法:

  public static void getClassDemo() throws ClassNotFoundException {
        String s = "abcdefg";
        "//通过对象的getClass()方法获取字类型的字节码文件"
        Class c1 = s.getClass();
        "//通过类型获取字节码文件"
        Class c2 = String.class;
        "/*通过Class.forName()获取字节码文件,若字节码没有加载进内存,就把文件加载进内存,若已经在内存中
        则直接取出字节码文件使用,内部是字符串,并且类所在的包也要写上*/"
        Class c3 = Class.forName("java.lang.String");
        System.out.println(c1 == c2);"//true"
        System.out.println(c1 == c3);"//true"
        System.out.println(c3 == c2);"//true"
        System.out.println(c1.getName());"获取类的名称,包括包名"
        System.out.println(c1.getSuperclass());"直接获取到Object的类,不论它上面有其他什么父类"
        System.out.println(c1.getModifiers());"最后修改时间"
        System.out.println(c1.getPackage());"获取包名"
        System.out.println(c1.getMethods());"获取所有方法,返回Methods[],不包括私有方法"
        System.out.println(c1.getMethod("charAt", int.class));"获取其中一个方法,指定方法名称,指定方法中参数类型的字节码文件"
        System.out.println(c1.getFields());"获取所有属性,返回Filed[]"
        System.out.println(c1.getField("name"));"获取指定属性,并返回Field"
        System.out.println(c1.isPrimitive());"判断是不是基本数据类型"
        System.out.println(int.class == Integer.class);"false"
        System.out.println(int.class == Integer.TYPE);"true"
        System.out.println(c1.isArray());"判断是不是数组类型"
    }

有9个预定义的Class对象:
byte ,short,int,long,boolean,char,float,double,void

通过反射获取构造方法,并创建对象:

    public static void getConstruct() throws ClassNotFoundException,
            InstantiationException, IllegalAccessException, NoSuchMethodException,
            SecurityException, IllegalArgumentException, InvocationTargetException {
        "//一般创建空参数的对象和有参数的对象"
        String str = "abc";
        String str2 = new String(new StringBuffer("abc"));
        "/**
         * 反射创建对象
         */
        // 获取没有参数的构造方法,并创建对象,然后对对象进行强转"
        Class c1 = Class.forName("java.lang.String");
        String s = (String) c1.newInstance();

        "// 获取有参数的构造方法,并创建对象"
        Class c2 = Class.forName("java.lang.String");
        "// 指定构造方法参数的字节码文件,可以通过参数的不同获取不同的构造方法"
        Constructor<String> con = c2.getConstructor(StringBuffer.class);
        "// 创建对象,并传入参数"
        StringBuffer sb = new StringBuffer("abc");
        String s1 = (String) con.newInstance(sb);
        System.out.println(s.getClass() == s1.getClass());"// true是同一个字节码文件"
        System.out.println(s == s1);"// false不是一个对象"
    }

通过反射获取类中属性:
对应的类:Field Field[]


    public static void getField() throws ClassNotFoundException, NoSuchFieldException,
            SecurityException, IllegalArgumentException, IllegalAccessException {

        Persion p = new Persion(10, "lisi");
        Class c = Class.forName("Persion.Persion");
        "// 获取的是Persion中num这个属性,不会获取他的值"
        Field f1 = c.getField("num");
        "/**
         * 这里获取的是这个Persion类中num属性,而不是Persion对应的具体的某个对象中的num
         * 不同对象他们对应的值不同,所以获取值的时候要传入对象,表示要获取那个对象这个属性的值
         */"
        System.out.println(f1.getInt(p));
        "// 修改某一个对象这个属性的值"
        f1.setInt(p, 30);
        System.out.println(f1.getInt(p));

        "// 获取所有的非私有属性,并返回Fiel[]"
        Field[] f2 = c.getFields();
        for (Field f : f2) {
            System.out.println(f.getName());
        }
        "/**
         * 获取所有属性,包括私有属性,并返回Fiel[]
         * c.getDeclaredFields();只是获取所有属性,但是并不能对私有属性进行操作
         */"
        Field[] f3 = c.getDeclaredFields();
        for (Field f : f3) {
            "//f.setAccessible(true);允许对某一个私有属性进行操作,"
            f.setAccessible(true);
            "//获取属性名称"
            System.out.println(f.getName());
        }
    }

用反射获取类中的方法:
Method Methos[]


public static void getMethos() throws ClassNotFoundException, NoSuchMethodException,
            SecurityException, IllegalAccessException, IllegalArgumentException,
            InvocationTargetException {
        Persion p = new Persion(30, "lisi");
        Class c = Class.forName("Persion.Persion");

        "// 获取方法,传入要获取的方法名,方法中要传入的 参数类型 的字节码文件"
        Method m1 = c.getMethod("setName", String.class);
        "// p这个对象调用SetName这个方法,传入的参数是“张三”"
        m1.invoke(p, new Object[] { "zhangsan" });"// = p.setName("zhangsan");"
        "// p这个对象调用getName这个方法,传入的参数是null,不需要参数"
        Method m2 = c.getMethod("getName", null);
        System.out.println(m2.invoke(p, null));"// = p.getName();"
        "//当一个方法是静态方法的时候使用m.invoke(null,'a'),不许要传入对象,因为静态方法不需要对象就能直接调用"

        "/**
         * 获取所有的方法,除了私有方法
         */"
        Method[] m3 = c.getMethods();
        for (Method m : m3) {
            System.out.println(m.getName());
        }
        "/**
         * 获取所有的方法,包括获取私有方法
         * c.getDeclaredMethods();获取但不能操作
         * m.setAccessible(true);允许操作
         */"
        Method[] m4 = c.getDeclaredMethods();
        for (Method m : m4) {
            m.setAccessible(true);
            System.out.println(m.getName());
        }

        "/**
         * 当方法中要传入的参数是数组时,如何传入参数
         * 参数类型是数组时候,一般我们会传入:m5.invoke(p,new String[] { "1", "2", "3", "4" });
         * java 1.5之前传入的参数是数组类型,也就是把多个参数都封装到一个数组中传入,数组类型是Object[]类型
         * 所以new String[]数组Java虚拟机会直接看成new Object[],这样他会进行对数组进行拆开,然后把里面的元素作为参数传入
         * 而java1.5之后可以直接书写多参数,不用封装成new Object[],但是为了兼容1.5之前的版本,当传入的参数是数组类型的时候,会转换成Object[]类型(基本数据类型不能转换成Object[]类型),然后对数组进行拆开,然后把里面的元素当做参数传入,造成错误
         * 解决方式:
         * 1、 (Object) new String[] { "1", "2", "3", "4" }强转
         * 2、new Object[] { new String[] { "1", "2", "3", "4" } }
         * 把new String[]作为参数传入,这样就算拆开数组也不会有问题
         * 参数是String[] 要传入String[].class,不能传String
         * 参数是String 要传入String.class 
         */"

        Method m5 = c.getMethod("shuzu", String[].class);
        m5.invoke(p, new Object[] { new String[] { "1", "2", "3", "4" } });
    }
    "/**
         * 数组的反射
         * 具有相同的维度和元素类型相同的数组就是同一种类型,他们的字节码文件相同,Class对象相同
         */"
        int[] a1 = new int[] { 1 };
        int[] a2 = new int[2];
        int[][] a3 = new int[1][];
        String[] a4 = new String[] { "1", "2", "3", "4" };
        System.out.println(a1.getClass() == a2.getClass());"// true"
        System.out.println(a1.getClass()==a3.getClass());"//false"
        System.out.println(a1.getClass() == a4.getClass());"//false"
        Object obj1 = a1;
        Object obj2 = a3;
        Object obj3 = a4;
        "// Object[] obj4 = a1;//基本数据类型数据不能用Object[]表示"
        Object[] obj5 = a3;
        Object[] obj6 = a4;

        "/**
         * 实例:
         * Arrays.aList();
         * 在java1.5之前参数是new Object[]
         * 在java1.5之后参数是T...a
         */"
        System.out.println(Arrays.asList(a1));"// [[I@1acd47]"
    "// 在反射中,当获取的对象是一个数组时候,可以使用Array(不是Arrays),来操作数组"
        Class cla = a4.getClass();
        if (cla.isArray()) {
            int len = Array.getLength(a4);
            System.out.println(Array.get(a4, 2));
        }

反射实例

    public static void demo() {
        "// 创建Properties 对象"
        Properties p = new Properties();
        "// 声明FileInputStream对象"
        FileInputStream fis = null;
        try {
            "//读取properties文件"
            fis = new FileInputStream("c://demo//a.txt");
            "//加载数据"
            p.load(fis);
            System.out.println(p.getProperty("demo") + "   " + p.getProperty("http"));
            "//获取demo多对应的值,然后创建他类的对象"
            Class c1 = Class.forName(p.getProperty("demo"));
            System.out.println(c1.getName());
            "//创建这个类的对象,这里使用的接口的类,因为传入的类实现了这个接口,就是这个接口的子类,多态的应用,提高扩展性"
            Rule r = (Rule) c1.newInstance();
            "//获取指定的方法,传入参数类型的字节码文件"
            Method m = c1.getMethod("down", String[].class, int.class);
            "//调用类中方法"
            m.invoke(r, new Object[] { new String[] { p.getProperty("http") }, 1 });

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
"//定义接口,其他类实现这个接口"
package Persion;

public interface Rule {
    public abstract void down(String[] s, int a);
}

"自定义类实现Rule 这个接口,利用传入的参数进行操作,可以利用传入的参数做任何操作,这里通过传入的参数获取网络资源,然后复制到指定位置"

public class Down implements Rule {

    @Override
    public void down(String[] s, int a) {
        FileOutputStream fos = null;
        HttpURLConnection conn = null;
        try {

            URL url = new URL(s[0]);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setReadTimeout(3000);
            conn.connect();
            "把.之后的数据截取出来"
            String regex = "\\.\\w+";
            "//创建pattern对象,关联正则表达式"
            Pattern p = Pattern.compile(regex);
            "//通过pattern对象和要匹配的字符串关联,返回匹配引擎"
            Matcher m = p.matcher(s[0]);
            String name = null;
            "//不断循环找数据"
            while (m.find()) {
                name = m.group();
            }
            fos = new FileOutputStream("c://demo//a" + name);
            InputStream in = conn.getInputStream();
            int len = 0;
            byte[] by = new byte[1024];
            while ((len = in.read(by)) != -1) {
                fos.write(by, 0, len);
                fos.flush();
            }
            System.out.println("OK");

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            if (fos != null) {

                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值