Java第十九课_反射

1.测试

  • 测试

    public class JiSuanQi {
        public int add(int a,int b){
            return a + b;
        }
    
        public int jian(int a,int b){
            return a - b;
        }
    
        public int cheng(int a,int b){
            return a * b;
        }
        public int div(int a,int b){
            return a / b;
        }
    }
    
    public class JiSuanQiTest {
        /*
            开发中测试代码和源代码需要分开. 源代码要发布装载到服务器上, 测试代码不需要
                1.创建与src(源码)同级的test包(需要将包定义为Test包), 在里面测试功能.
                    a.测试代码和源码需要在同一个包下: 源码lesson01里面的代码, 测试包也创建lesson01包测试(可以避免不必要的包导入)
                2.命名规则
                    a.类 : Test写后面
                    b.函数 : test写前面
         */
    
        // 测试中常使用断言Assert
        //      调用函数, 并设定期望值, 看函数结果是否符合预期
        @Test
        public void testAdd(){
            Assert.assertEquals(20, new JiSuanQi().add(10, 10));
        }
    
        @Test
        public void testJian(){
            Assert.assertEquals(20, new JiSuanQi().jian(30, 10));
        }
    
    
        @Test
        public void testCheng(){
            Assert.assertEquals(20, new JiSuanQi().cheng(4, 5));
        }
    
        // 对于异常的期望, 需要使用expected
        @Test(expected = ArithmeticException.class)
        public void testDiv1(){
            Assert.assertEquals(10, new JiSuanQi().div(100, 0));
        }
    
        @Test
        public void testDiv2(){
            Assert.assertEquals(10, new JiSuanQi().div(100, 10));
        }
    
        // 可能发生死循环时, 使用timeout. 运行一段时间后自动结束函数
        //      也可以用作程序效率的测试.
        @Test(timeout = 3000)// 单位 : 毫秒
        public void testRun01() {
            while (true) {
    
            }
        }
    
        // Ignore :忽略该函数
        //      有特殊情況时, 先跳过不测试
        @Ignore
        @Test
        public void testRun02(){
            try {
                TimeUnit.MILLISECONDS.sleep(2990);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    public class JiSuanQiTest02 {
    	// 测试中常使的其他@
        @BeforeClass// 所有函数执行前,执行一次
        public static void beforeClass(){
            System.out.println("@BeforeClass  ");
        }
    
        @Before// 在每一个函数执行之前执行一次
        public void before(){
            System.out.println("@Before  ");
        }
    
        @After// 在每一个函数执行之后执行一次
        public void after(){
            System.out.println("@After  ");
        }
    
        @AfterClass// 在所有函数执行之后执行一次
        public static void afterClass(){
            System.out.println("@AfterClass  ");
        }
    
        @Test
        public void add() {
            System.out.println("add....");
        }
    
        @Test
        public void jian() {
            System.out.println("jian....");
        }
    }
    

2.反射

  • Class

        public static void main(String[] args) throws ClassNotFoundException {
            // Class 就是内存中的字节码文件
    
            // 1.Object : getClass
            Class<?> c1 = new Practice01().getClass();
            // 2.内置的静态属性 .class
            Class<?> c2 = Practice01.class ;
            Class<Void> voidClass = void.class;
            Class<Integer> integerClass = int.class;
            // 3.动态加载 : Class : forName(String className)
            Class<?> c3 = Class.forName("com.msr.lesson01.Practice01");
            System.out.println(c1 == c2);
            System.out.println(c1 == c3);
        }
    
  • 用反射获取类属性

    public class Practice02 {
    
        public static void main(String[] args) {
            // 获取属性
            printAllField(String.class);
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            printAllDeclaredField(String.class);
            System.out.println("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
            printAllField(Integer.class);
            System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
            printAllDeclaredField(Integer.class);
    
        }
    
        // 获取公共属性
        private static void printAllField(Class<?> clazz) {
            // 获取所有的字段所在的数组
            Field[] fields = clazz.getFields();
            // 遍历数组
            for (Field field : fields) {
                // 获取修饰符之和
                int modifiers = field.getModifiers();
                // 获取类型
                Class<?> type = field.getType();
                String typeName = type.getName();
                // 获取名字
                String fieldName = field.getName();
                System.out.println(modifiers + "\t" + typeName + "\t" + fieldName);
            }
        }
    
        // 获取所有属性
        private static void printAllDeclaredField(Class<?> clazz) {
            // 获取所有的字段所在的数组
            Field[] fields = clazz.getDeclaredFields();
            // 遍历数组
            for (Field field : fields) {
                // 获取修饰符之和
                int modifiers = field.getModifiers();
                // 获取类型
                Class<?> type = field.getType();
                String typeName = type.getName();
                // 获取名字
                String fieldName = field.getName();
                System.out.println(modifiers + "\t" + typeName + "\t" + fieldName);
            }
    
        }
    }
    
  • 用反射获取类函数

    public class Practice03 {
        public static void main(String[] args) {
            // 获取函数
            printAllDeclaredMethod(String.class);
            System.out.println("===============================================================");
            printAllDeclaredMethod(Integer.class);
    
        }
    
        private static void printAllDeclaredMethod(Class<?> clazz) {
            // 获取所有函数所在的数组
            Method[] declaredMethods = clazz.getDeclaredMethods();
            // 遍历,得到每一个函数对象
            for (Method declaredMethod : declaredMethods) {
                // 获取修饰符之和
                int modifiers = declaredMethod.getModifiers();
                // 返回值类型
                Class<?> returnType = declaredMethod.getReturnType();
                // 函数名
                String methodName = declaredMethod.getName();
                System.out.print(modifiers + "\t" + returnType + "\t" + methodName + '(');
                // 形式参数的类型
                Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
                for (Class<?> parameterType : parameterTypes) {
                    System.out.print(parameterType.getSimpleName() + " , ");
                }
                System.out.println(')');
            }
        }
    }
    
  • 用反射获取类构造器

    public class Practice04 {
        public static void main(String[] args) {
            // 获取构造器
            printAllMethod(String.class);
            System.out.println("===============================================================");
            printAllMethod(Integer.class);
        }
    
        private static void printAllMethod(Class<?> clazz) {
            // 获取所有函数所在的数组
            Method[] methods = clazz.getMethods();
            // 遍历,得到每一个函数对象
            for (Method method : methods) {
                // 获取修饰符之和
                int modifiers = method.getModifiers();
                // 返回值类型
                Class<?> returnType = method.getReturnType();
                // 函数名
                String methodName = method.getName();
                System.out.print(modifiers + "\t" + returnType + "\t" + methodName + '(');
                // 形式参数的类型
                Class<?>[] parameterTypes = method.getParameterTypes();
                for (Class<?> parameterType : parameterTypes) {
                    System.out.print(parameterType.getSimpleName() + " , ");
                }
                System.out.println(')');
            }
        }
    }
    
  • 反射实例01:通过反射使用类

    public class A {
    
        private void m2(){
            System.out.println("私有的 m2 空参");
        }
    
        public void m1(){
            System.out.println("m1 空参");
        }
    
        public void m1(int num){
            System.out.println("m1 int参 : " + num);
        }
    
        public void m1(String string , int num){
            System.out.println("m1 String + int 参 : " + string + num);
        }
    
        public String m1(int num ,String s){
            System.out.println("m1 int + String参 : " + num + s);
            return s + num;
        }
    }
    
    public class Practice01 {
    
        public static void main(String[] args) {
            // 通过反射使用类
    
            // A 中公开函数的调用 getMethod
            // 创建反射
            Class<A> clazz = A.class;
            // 获取函数对象
            try {
                Method method = clazz.getMethod("m1");// 形参 : 类的函数名
                Object o = clazz.newInstance();// JDK9 中过时了
    
                // invoke 函数是来调用函数的,它的返回值就是函数的返回值,如果函数没有返回值或者被调用函数返回null,invoke函数也返回null
                // 调用空参函数
                Object invoke = method.invoke(o);// 实参
                System.out.println("invoke = " + invoke);
    
                // 调用 int 型 函数
                method = clazz.getMethod("m1", int.class);
                // JDK9开始
                Constructor<A> constructor = clazz.getConstructor();
                A a = constructor.newInstance();
                invoke = method.invoke(a, 3306);
                System.out.println("invoke = " + invoke);
    
                // String + int
                method = clazz.getMethod("m1", String.class, int.class);
                constructor = clazz.getConstructor();
                a = constructor.newInstance();
                invoke = method.invoke(a, "勤能补拙", 3306);
                System.out.println("invoke = " + invoke);
    
                //  int + String  有返回值
                method = clazz.getMethod("m1", int.class, String.class);
                constructor = clazz.getConstructor();
                a = constructor.newInstance();
                invoke = method.invoke(a, 3306, "业精于勤");
                System.out.println("invoke = " + invoke);
    
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {// 没有访问权限的意思
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            System.out.println("-----------------------");
    
            // A 中私有函数的调用 getDeclaredMethod
            Class<?> aClass = A.class;
            // 获取函数对象(私有)
            try {
                Method m2 = aClass.getDeclaredMethod("m2");
                // 赋予访问权限
                m2.setAccessible(true);
                Object invoke = m2.invoke(aClass.getConstructor().newInstance());
                System.out.println("invoke = " + invoke);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 反射实例02:动态创建

    public class Student {
    
        private String name;
        private int age;
    
        private Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    public class Practice02 {
    
        public static void main(String[] args) {
            // 静态创建对象就是 使用 new 关键字创建
            //      使用 new 关键字创建时, 类必须存在, 否则直接报错
            // 反射 是动态创建
            //      动态创建的优势 : 编译时无需确定有该类, 运行时再找
    
            // 动态创建学生对象
            try {
                Class<?> clazz = Class.forName("com.msr.lesson02.Student");
                Constructor<?> constructor = clazz.getDeclaredConstructor();
                constructor.setAccessible(true);
                Object instance = constructor.newInstance();// 使用空参构造器来创建对象
                System.out.println("instance = " + instance);
    
                constructor = clazz.getDeclaredConstructor(String.class, int.class);// 使用带参构造器来创建对象
                constructor.setAccessible(true);
                instance = constructor.newInstance("lisi", 20);
                System.out.println("instance = " + instance);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 反射实例03:多态

    public abstract class WPS {
        public abstract void start();
    }
    public class Excel extends WPS{
        @Override
        public void start(){
            System.out.println("Excel 开始工作了.......");
        }
    }
    public class Pic extends WPS {
        @Override
        public void start() {
            System.out.println("图片功能开始工作了 ");
        }
    }
    
    wps.properties:
    className=com.msr.lesson02.Excel;com.msr.lesson02.Pic
    
    public class Practice03 {
    
        public static void main(String[] args) {
            /*
                开发阶段, 功能尚未完全实现时, 用动态创建实现
                    在src下创建配置文件xxx.properties
                    将文件和内存对象关联起来, 读取并调用.
                        可以随进度在properties文件里添加新完成的内容
             */
    
            // 创建文件的内存对象
            Properties properties = new Properties();
            // 借助资源流加载文件
            ClassLoader classLoader = Practice03.class.getClassLoader();// 获取类加载器
            InputStream inputStream = classLoader.getResourceAsStream("wps.properties");// 默认路径 是 项目的 src 目录下
            // 将硬盘文件和内存对象关联起来
            try {
                properties.load(inputStream);
                // 读取硬盘文件内容
                String value = properties.getProperty("className");
                String[] split = value.split(";");
    
                for (String className : split) {
                    Class<?> clazz = Class.forName(className);
                    WPS wps = (WPS) clazz.getConstructor().newInstance();
                    wps.start();
                }
    
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            System.out.println("over");
        }
    }
    
  • 反射实例04:泛型

    public class Practice01 {
    
        public static void main(String[] args) {
            // 泛型只在编译时期有效
    
            List<String> list = new ArrayList<>();// 泛型限定String
            list.add("aaa");
            list.add("aaa");
            list.add("aaa");
            list.add("aaa");
            //list.add(123);        // 添加Integer失败
    
            Class<? extends List> aClass = list.getClass();
            try {
                Method add = aClass.getMethod("add", Object.class);
                Object invoke = add.invoke(list, 123);// 动态使用, 添加Integer成功
                System.out.println("invoke = " + invoke);
                System.out.println("list = " + list);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    
  • 反射实例05:开发框架

    public class Practice02 {
    
        public static void main(String[] args) {
            // 反射 : 键盘输入功能名称,执行对应的函数(开发框架常用)
            // 不是靠switch(数字)的形式, 将1,2,3,...和函数绑定起来. 而是靠反射, 键盘直接输入函数名(及参数等)
            Scanner scanner = new Scanner(System.in);
            // 测试函数的参数
            int A = 0;
            String B = "0";
    
            Class<?> clazz = Practice02.class;
            try {
                while (true) {
                    System.out.println("请输入功能名 : insertUser   updateUser  deleteUser queryAllUsers ");
                    String methodName = scanner.next();
                    Method method = clazz.getDeclaredMethod(methodName, Integer.class, String.class);// 键盘直接输入 反射使用的函数名(和两个参数)
                    method.setAccessible(true);
                    String invoke = (String) method.invoke(clazz.getConstructor().newInstance(), A, B);
                    System.out.println("invoke = " + invoke);
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
            scanner.close();
        }
    
        private static void insertUser(Integer A,String B){
            System.out.println("insertUser ..........");
        }
    
        private static void updateUser(Integer A,String B){
            System.out.println("updateUser ..........");
        }
    
        private static void deleteUser(Integer A,String B){
            System.out.println("deleteUser ..........");
        }
        
        private static void queryAllUsers(Integer A,String B){
            System.out.println("queryAllUsers ..........");
        }
    }
    
posted @ 2023-12-28 08:25  张心野  阅读(22)  评论(0)    收藏  举报