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 .........."); } }