黑马程序员——反射

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

什么是反射

java反射机制就是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法
对于任意一个对象,都能够调用它任意一个方法和属性。
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

简单的讲:反射就是动态获取类中信息。可以理解为对类的解剖

如何得到各个字节码对应的实例对象(class类型)
1,类名.class; 例如,System.class
2,对象.getClass(); 例如,new Date.getClass()
3,Class.forName(“类名”); 例如,Class.forName(“java.util.Date”);

基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。

总之:只要在源程序中出现的类型,都有各自的Class实例对象,例如:int[], void ….

反射简单的讲,就是把java类中的各种成分映射成相应的java类

使用反射获取一个类中的构造方法

import java.io.*;
import java.lang.reflect.Constructor;
import java.net.*;

public class Demo {
    public static void main(String[] args) throws Exception {

        //使用反射来获取String str = new String(new StringBuffer("abc"));
        Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//此方法是获取String的构造方法,并将该构造方法封装成一个对象Constructor,                   

                            //StringBuffer.class代表要获取哪个构造方法

        String str1 = (String)constructor1.newInstance(new StringBuffer("abc"));//此方法相当于用构造方法创建了一个String类型的对象,参数是StringBuffer("abc");
                //由于在编译时,编译器只知道它是一个构造方法对象,并不知道它是什么类型的构造方法对象,所以需要加上强制转换。
                //编译器编译时,只看左边,既:只看constructor,只知道它是一个构造方法对象而以,并不知道是什么类型

        //String str2 = (String)constructor1.newInstance("abc");//此方法是错误的。因为构造coustructor1是能接收StringBuffer参数的构造方法,不是接收String类型的构造方法。

        System.out.println(str1.charAt(2));//c


    }
}

使用反射获取一个类中的变量

import java.io.*;
import java.lang.reflect.Field;
import java.net.*;

class Person{
    private int x;
    public int y;
    public Person(int x, int y) {
        super();
        this.x = x;
        this.y = y;
    }
}
public class Demo {
    public static void main(String[] args) throws Exception {
        Person p = new Person(3,5);

        Field fieldY = p.getClass().getField("y");//fieldY的值是多少?是5,错!fieldY只是封装了某个基本类型的对象而已,想要知道该基本类型的值,需要用对象中的方法get获取
        System.out.println(fieldY.get(p));// 5 获取p这个对象中的y的值

//      Field fieldX = p.getClass().getField("x");//此处会报错,因为Person类中的x是私有的,不可获取
//      System.out.println(fieldX.get(p));

//      Field fieldX =p.getClass().getDeclaredField("x");//能够获取到类中私有变量的方法 
//      System.out.println(fieldX.get(p));//此处会报错。虽然fieldX获取到了私有的变量,但是fieldX.get(p)不可以获取到

        Field fieldX = p.getClass().getDeclaredField("x");
        fieldX.setAccessible(true);//设置fieldX中的get方法能够获取得到Person类中的私有变量
        System.out.println(fieldX.get(p));//3


    }
}

使用反射获取一个类中的方法

import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.*;


public class Demo {
    public static void main(String[] args) throws Exception {

        String str1 = "abcdefgh";

        Method methodCharAt = String.class.getMethod("charAt", int.class);
        System.out.println(methodCharAt.invoke(str1, 1));//b    获取str1这个字符串中,角标为1的字符
        System.out.println(methodCharAt.invoke(str1, new Object[]{2}));//c  这一种接收参数的形式也可以,这是在jdk1.4版本的时候用法,因为当时没有可变参数

        Method methodIndexOf = String.class.getMethod("indexOf", int.class,int.class);
        System.out.println(methodIndexOf.invoke(str1, 'c', 0));//2  获取str1这个字符串中,字符'c'出现的角标

        Method methodValueOf = String.class.getMethod("valueOf",boolean.class);
        System.out.println(methodValueOf.invoke(null, true));//true     将boolean类型的true,变成字符串"true"
                        //invock第一个参数为null,代表valueOf这个方法是静态的,因为静态方法不需要对象调用,所以参数为null
    }
}

数组反射

/*     
 数组反射:Array,该类中的方法全是静态的
        该类提供了动态创建和访问 Java 数组的方法。       
 */
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Arrays;
public class Demo {
    public static void main(String[] args) throws Exception {
        String[] strs = new String[]{"abc","aaa","kkk"};

        Object obj = strs;
        method(obj);
        method("123");
    }

    public static void method(Object obj) {
        if(obj.getClass().isArray()){//判读obj是否为一个数组

            int len = Array.getLength(obj);//通过反射的Array方法,获取obj对象中数组的长度

            for(int i=0;i<len;i++){
                //返回指定数组对象中索引组件的值。
                String str = (String) Array.get(obj, i);
                System.out.println(str);
            }

        }
        else{
            System.out.println(obj);
        }
    }
}

反射的练习

/*
 需求:
    用反射的方法,将Person对象中的字符串的'b'字符全部改为'a',
    如:"aabbcc"修改后的值为"aaaacc"。
 */
import java.io.*;
import java.lang.reflect.Field;
import java.net.*;

class Person {
    public int a = 2;
    public int b = 5;
    public String str1 = "aabbcc";
    public String str2 = "abcabbcc";
    public String str3 = "qwert";

    @Override
    // 此处的意思代表,如果toString写错了,编译时会出现提示,因为自己并不能保证覆盖父类的方法写对了
    public String toString() {
        return str1 + "..." + str2 + "..." + str3;
    }
}

public class Demo {
    public static void main(String[] args) throws Exception {
        Person p = new Person();

        System.out.println(p);//aabbcc...abcabbcc...qwert

        Field[] fields = p.getClass().getFields();// 获取对象中所有的公共变量,并存放到Field类中
        for (Field field : fields) {//遍历fields对象中的所有public类型

            //if(field.getType().equals(String.class))
            //字节码都是一个份的,干嘛用equals去比较
            if (field.getType() == String.class) {//通过getType方法,获取Person中变量的类型,如果获取到的类型是String类型,那么就执行以下代码

                String str1 = (String) field.get(p);//通过Field类中的get方法,获取Person类中的字符串
                String str2 = str1.replace('b', 'a');//将Person类中的字符串中的'b'修改为'a'

                field.set(p, str2);//将修改后的字符串再写入Person类中
            }
        }
        System.out.println(p);//aaaacc...aacaaacc...qwert
    }
}
/*
 需求:用反射方式执行某个类中的main方法
 */
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.*;

public class Demo {
    public static void main(String[] args) throws Exception {
        // 普通的调用方式
        // String[] strs = new String[]{"111","222","333"};
        // Demo2.main(strs);

        // 反射的调用方式
        String[] strs = new String[] { "111", "222", "333" };
        Method methodMain = Class.forName("Demo2").getMethod("main", String[].class);
        //methodMain.invoke(null, strs);//此处报异常,因为传递strs数组进来时,invoke自动将数组拆成了3个参数,那么传递给Demo2类中main方法的
                    //参数就不是一个数组了,而已3个String类型的参数,所以会出现异常

        methodMain.invoke(null, new Object[]{strs});//此方法是正确的,因为invoke将Object数组拆成了1个参数,而此参数却是一个数组,所以,
                //将此数传递给Demo2类中的main方法是可行的


        methodMain.invoke(null, (Object)strs);//此方法正确,通过反射的形式调用了Demo2类中的main方法,
                //invoke中第一个参数为null的原因是,main方法为静态的,不需要对象去调用。而第二个参数是(Object)strs是因为,
                //告诉invoke方法,此方法不是一个数组,是一个Object类型的对象,这样invoke方法就不会将strs数组拆成3个String类型


    }
}

class Demo2 {
    public static void main(String[] args) throws Exception {
        for (String arg : args)
            System.out.println(arg);
    }
}
/*     
  练习:将集合的名称以键值的形式存入一个配置文件中,
    通过键获取集合的名称,并在该集合中存入数据,并打印集合的长度
 */
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.*;

class Person {
    private int x, y;

    public Person(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public int hashCode() {
        return x + y * 32;
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Person))
            throw new RuntimeException();
        Person p = (Person) obj;
        return x == p.x && y == p.y;
    }

}

public class Demo {
    public static void main(String[] args) throws Exception {
        InputStream is = new FileInputStream("c:\\properties.txt");
        Properties prop = new Properties();
        prop.load(is);
        is.close();

        Person p1 = new Person(3,3);
        Person p2 = new Person(5,5);
        Person p3 = new Person(3,3);

        String className = prop.getProperty("className");//获取键为className的值

        Constructor con = Class.forName(className).getConstructor();//获取className这个字符串的构造方法
        Collection coll = (Collection) con.newInstance();//调用这个字符串的构造方法
        coll.add(p1);
        coll.add(p2);
        coll.add(p3);
        coll.add(p1);
        System.out.println(coll.size());//4

        /*
            此程序的使用方法:

                在c盘中创建一个properties.txt文件。
                在文件中写   className=java.util.ArrayList
                这样程序的运行结果为4

                如果在文件中写 className=java.util.HashSet
                那么程序的运行结果为2

         */
    }
}
package cn.itcast.reflect;

import java.io.*;
import java.util.*;


/*
 * 练习:电脑运行基于主板。
 * 
 * 如:有一个声卡,声卡想要运行,就必须要通过主板调用。
 *    后期又来了个网卡,网卡想要运行,也必须通过主板调用。
 */
interface PCI {
    public abstract void open();

    public abstract void close();
}

class ZhuBan {//主板
    public void run() {
        System.out.println("ZhuBan...run");
    }

    public void pciInvoke(PCI pci) {
        pci.open();
        pci.close();
    }
}

class WangKa implements PCI {//网卡实现PCI接口
    public void open() {
        System.out.println("WangKa....open");
    }

    public void close() {
        System.out.println("WangKa....close");
    }
}

class ShengKa implements PCI {//声卡实现PCI接口
    public void open() {
        System.out.println("ShengKa....open");
    }

    public void close() {
        System.out.println("ShengKa....close");
    }
}

public class Demo {

    public static void main(String[] args) throws Exception {
        File file = new File("D:\\peizhi.txt");
        if (!file.exists()) {
            throw new RuntimeException("文件不存在");
        }

        ZhuBan zb = new ZhuBan();
        zb.run();

        Properties prop = new Properties();//创建一个Properties对象
        FileReader fr = new FileReader(file);//创建一个流和peizhi.txt文件相关联
        prop.load(fr);//将peizhi.txt文件中的键值存入prop集合中

        //循环遍历peizhi.txt文件中的键值
        for (int i = 0; i < prop.size(); i++) {
            //获取peizhi.txt文件中的值,该值是一个对象的名称
            String className = prop.getProperty("peizhi" + (i + 1));

            //获取peizhi.txt文件中名称的字节码文件对象
            Class clazz = Class.forName(className);
            //创建获取到的名称  的对象。例如:获取到的名称是WangKa。那么相当于PCI pci = new WangKa();
            PCI pci = (PCI) clazz.newInstance();
            //调用主板中的方法
            zb.pciInvoke(pci);
        }
    }
}
/*
 * 此程序用法:在D盘中创建一个peizhi.txt文件。并在文件中写入一下数据
 *      peizhi1=cn.itcast.reflect.WangKa
 *      peizhi2=cn.itcast.reflect.ShengKa
 * 
 * 此程序这么设计的扩展性极强。以后如果想加入一个内存卡,那么就写一个内存卡的类,并实现PCI接口,
 * 当类写完了以后,再将类名存入peizhi.txt文件中。 当程序运行时,就会自动获取peizhi.txt文件中的信息。
 */

总结

/*
    反射方法的总结。
    看完该例子就会找到反射的使用规律

    例如:
    1,获取某类的构造函数,想都不用想,直接就上,Constructor constructor = 字节码文件对象.getConstructor();
        这样就拿到了构造方法的Constructor对象。相对此构造方法怎么宰割,查API找方法去

    2,获取某类的方法,想都不用想,直接就上,Method method = 字节码文件对象.getMethod("方法名",参数类型.class);
        这样也拿到了方法的Method。想对此方法怎么宰割,继续查API去

    3,如果方法是私有时,Method method = 字节码文件对象.getDeclaredMethod("方法名",参数类型.class);
        然后再加上
        method.setAccessible(true);
        那么此私有的方法也获取到了,爱怎么使用再查API去。
 */
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
import java.util.*;

class Person {
    public int x = 3;

    private int y = 5;

    public Person() {
        System.out.println("person()....run");
    }

    public Person(int x, int y) {
        System.out.println("Person(int x,int y).....run");
    }

    public void method() {
        System.out.println("method()......run");
    }

    public void method(String str, int num) {
        System.out.println("method(String str,int num)....run");
    }

    public static void staticMethod() {
        System.out.println("staticMethod().....run");
    }

    private void privateMethod() {
        System.out.println("privateMethod.....run");
    }
}

public class Demo {
    public static void main(String[] args) throws Exception {
        // 获取无参构造函数
        Constructor constructor1 = Class.forName("Person").getConstructor();
        Person p = (Person) constructor1.newInstance();// person()....run

        // 获取有参构造函数
        Constructor constructor2 = Class.forName("Person").getConstructor(
                int.class, int.class);
        constructor2.newInstance(5, 6);// Person(int x,int y).....run

        // 获取 公有 的字段
        Field field1 = Class.forName("Person").getField("x");
        int x = (Integer) field1.get(p);
        System.out.println(x);// 3

        // 获取 私有 的字段 ,getDeclaredField代表能够获取Person类中私有的字段
        Field field2 = Class.forName("Person").getDeclaredField("y");
        field2.setAccessible(true);// 想要获取就必须加上这一句
        int y = (Integer) field2.get(p);
        System.out.println(y);// 5

        // 获取无参方法
        Method method1 = p.getClass().getMethod("method", null);
        method1.invoke(p, null);// method()......run

        // 获取有参方法
        Method method2 = p.getClass().getMethod("method", String.class,
                int.class);
        method2.invoke(p, "abc", 2);// method(String str,int num)....run

        // 获取无参的静态方法
        Method method3 = p.getClass().getMethod("staticMethod", null);
        method3.invoke(p, null);// staticMethod().....run

        // 获取 私有 的方法 ,getDeclaredMethod代表能够获取Person类中的私有方法
        Method method4 = p.getClass().getDeclaredMethod("privateMethod", null);
        method4.setAccessible(true);// 如果要获取私有的,就必须加上这一句
        method4.invoke(p, null);// privateMethod.....run

    }
}
# 高校智慧校园解决方案摘要 智慧校园解决方案是针对高校信息化建设的核心工程,旨在通过物联网技术实现数字化校园的智能化升级。该方案通过融合计算机技术、网络通信技术、数据库技术和IC卡识别技术,初步实现了校园一卡通系统,进而通过人脸识别技术实现了更精准的校园安全管理、生活管理、教务管理和资源管理。 方案包括多个管理系统:智慧校园管理平台、一卡通卡务管理系统、一卡通人脸库管理平台、智能人脸识别消费管理系统、疫情防控管理系统、人脸识别无感识别管理系统、会议签到管理系统、人脸识别通道管理系统和图书馆对接管理系统。这些系统共同构成了智慧校园的信息化基础,通过统一数据库和操作平台,实现了数据共享和信息一致性。 智能人脸识别消费管理系统通过人脸识别终端,在无需接触的情况下快速完成消费支付过程,提升了校园服务效率。疫情防控管理系统利用热成像测温技术、视频智能分析等手段,实现了对校园人员体温监测和疫情信息实时上报,提高了校园公共卫生事件的预防和控制能力。 会议签到管理系统和人脸识别通道管理系统均基于人脸识别技术,实现了会议的快速签到和图书馆等场所的高效通行管理。与图书馆对接管理系统实现了一卡通系统与图书馆管理系统的无缝集成,提升了图书借阅的便捷性。 总体而言,该智慧校园解决方案通过集成的信息化管理系统,提升了校园管理的智能化水平,优化了校园生活体验,增强了校园安全,并提高了教学和科研的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值