Java单元测试、反射、注解
单元测试
Junit
public class UserService { public String login(String loginName, String password) { if ("admin".equals(loginName) && "123456".equals(password)) { return "success"; } return "用户名或密码错误"; } } public class UserServiceTest { /** * 测试方法要求: * 1.必须public修饰 * 2.没有返回值没有参数 * 3.必须使注解@Test修饰 */ @Test public void testLogin() { UserService userService = new UserService(); String rs = userService.login("admin", "123456"); // 断言预期结果的正确性 /** * 参数一:测试失败的提示信息 * 参数二:期望值 * 参数三:实际值 */ Assert.assertEquals("登录业务功能方法有误", "success", rs); } }
Junit常用注解
如Junit4,如5个注解都有,则执行顺序为@BeforeClass、@Before、@Test、@After、@AfterClass
反射
反射获取类对象
public class ReflectDemo01 { public static void main(String[] args) throws ClassNotFoundException { // 反射的第一步永远是先得到类的Class文件对象:字节码文件 // 1.类名.class Class c1 = Student.class; System.out.println(c1); // 2.对象.getClass() Student swk = new Student(); Class c2 = swk.getClass(); System.out.println(c2); // 3.Class.forName("类的全限名") Class c3 = Class.forName("Student"); System.out.println(c3); } }
反射获取构造器对象
public class ReflectDemo01 { public static void main(String[] args) throws ClassNotFoundException { // 反射的第一步永远是先得到类的Class文件对象:字节码文件 // 1.类名.class Class c1 = Student.class; System.out.println(c1); // 2.对象.getClass() Student swk = new Student(); Class c2 = swk.getClass(); System.out.println(c2); // 3.Class.forName("类的全限名") Class c3 = Class.forName("Student"); System.out.println(c3); } @Test public void getConstructors() { // 1.反射第一步得到Class类对象 Class c = Student.class; // 2.定位全部构造器,只能拿public修饰 Constructor[] cons = c.getConstructors(); // 3.遍历构造器 for (Constructor con: cons) { System.out.println(con.getName() + "===>" + con.getParameterCount()); } } @Test public void getDeclaredConstructors() { // 1.反射第一步得到Class类对象 Class c = Student.class; // 2.定位全部构造器,只要申明了就可以拿到 Constructor[] cons = c.getDeclaredConstructors(); // 3.遍历构造器 for (Constructor con: cons) { System.out.println(con.getName() + "===>" + con.getParameterCount()); } } @Test public void getDeclaredConstructor() throws NoSuchMethodException { // 1.反射第一步得到Class类对象 Class c = Student.class; // 2.定位全部构造器,只要申明了就可以拿到 // Constructor con = c.getDeclaredConstructor(); Constructor con = c.getDeclaredConstructor(String.class, int.class); // 3.遍历构造器 System.out.println(con.getName() + "===>" + con.getParameterCount()); } } public class Student { private String name; private int age; public Student() { } private Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
反射获取构造器然后通过构造器初始化对象
// 调用无参构造器得到一个类的对象返回 @Test public void createObj01() throws Exception { // a.反射第一步是先得到Class类对象 Class c = Student.class; // b.定位无参数构造器对象 Constructor constructor = c.getDeclaredConstructor(); // c.通过无参数构造器初始化对象返回 constructor.setAccessible(true); // d.通过无参数构造器初始化对象返回 Student swk = (Student) constructor.newInstance(); System.out.println(swk); } // 调用有参构造器得到一个类的对象返回 @Test public void createObj02() throws Exception { // a.反射第一步是先得到Class类对象 Class c = Student.class; // b.定位无参数构造器对象 Constructor constructor = c.getDeclaredConstructor(String.class, int.class); // c.通过有参数构造器初始化对象返回 Student swk = (Student) constructor.newInstance("测试", 100); System.out.println(swk); }
反射获取Field成员变量对象及赋值
/** * 获取全部的成员变量 * @throws Exception */ @Test public void createObj03() throws Exception { // a.反射第一步是先得到Class类对象 Class c = Dog.class; // b.获取全部申明的成员变量对象 Field[] fields = c.getDeclaredFields(); for (Field field: fields) { System.out.println(field.getName()+""); } Field nameF = c.getDeclaredField("name"); // c. 为这个成员变量赋值 Dog taidi = new Dog(); /** * 参数一:被赋值的对象 * 参数二:该成员变量的值 */ nameF.setAccessible(true); nameF.set(taidi, "勇敢的泰迪"); System.out.println(taidi); String value = nameF.get(taidi) + ""; System.out.println(value); }
反射获取Method方法对象
/** * 获取所有方法对象 */ @Test public void getDeclaredMethods() { Class d = Dog.class; Method[] methods = d.getDeclaredMethods(); for (Method method: methods) { System.out.println(method.getName() + "====>" + method.getParameterCount() + "===>" + method.getReturnType()); } } /** * 获取某个方法对象 */ @Test public void getDeclardMethod() throws Exception { // 1.先获取class类对象 Class c = Dog.class; // 2.定位它的某个方法 Method run = c.getDeclaredMethod("run"); // 3.触发方法执行 Dog jinmao = new Dog(); run.invoke(jinmao); // 触发jinMao对象的run()方法执行 /** * 参数一:方法名称 * 参数二:方法的参数个数和类型(可变参数) */ Method eat = c.getDeclaredMethod("eat", String.class); eat.setAccessible(true); /** * 参数一:被触发方法所在的对象 * 参数二:方法需要的入参值 */ eat.invoke(jinmao, "肉"); System.out.println(); } public class Dog { private void eat() { System.out.println("狗吃骨头"); } private void eat(String name) { System.out.println("狗吃" + name); } public void run() { System.out.println("狗在跑"); } }
反射破坏类的封装性与泛型的约束性
@Test public void getDeclardMethod1() throws Exception { // 泛型只能工作在编译阶段,运行阶段泛型就消失了 // 反射工作在运行阶段 List<Double> scores = new ArrayList<>(); scores.add(24.1); scores.add(123.4); // 拓展:通过反射暴力注入一个其它类型数据 Class c = scores.getClass(); // 从ArrayList的class对象中定位add方法 Method add = c.getDeclaredMethod("add", Object.class); // 出发scores集合对象中的add执行(运行阶段,泛型不能约束了) add.invoke(scores, "波仔"); System.out.println(scores); }
反射的作用
public static void main(String[] args) throws ClassNotFoundException { Dog dog = new Dog("haha", 15, "红"); MyBatis.save(dog); } public class Dog { private String name; private int age; private String color; public Dog(String name, int age, String color) { this.name = name; this.age = age; this.color = color; } public Dog() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } } import java.io.FileOutputStream; import java.io.PrintStream; import java.lang.reflect.Field; public class MyBatis { // 提供一个方法:可以保存一切对象数据的字段和具体值 public static void save(Object obj) { try ( PrintStream ps = new PrintStream(new FileOutputStream("反射/src/test.txt", true)); ) { // 1.先得到对象的Class文件对象 Class c = obj.getClass(); // 2.定位它的全部成员变量 Field[] fields = c.getDeclaredFields(); // 3.遍历这些字段并取值 for (Field field: fields) { // 字段名称 String name = field.getName(); // 字段的值 field.setAccessible(true); // 暴力反射 String value = field.get(obj) + ""; ps.println(name + "=" + value); } }catch (Exception e) { e.printStackTrace(); } } }
注解
自定义注解
注解的属性
注解的特殊属性
元注解——是用在自定义注解上的注解
注解的解析
@Book(value="test1", authors = {"1", "2"}, price = 5.1) public class MyBook { public static void main(String[] args) throws NoSuchMethodException { // 1.定位Class类对象 Class c = BookStore.class; // 2.判断这个类上是否使用了某个注解 if (c.isAnnotationPresent(Book.class)) { // 3.获取这个注解对象 Book book = (Book) c.getDeclaredAnnotation(Book.class); System.out.println(book.value()); System.out.println(book.price()); } Method run = c.getDeclaredMethod("run"); // 2.判断这个方法上是否使用了某个注解 if (run.isAnnotationPresent(Book.class)) { // 3.获取这个注解对象 Book book = (Book) run.getDeclaredAnnotation(Book.class); System.out.println(book.value()); System.out.println(book.price()); } } } @Book(value = "Java基础精通", price = 50, authors = {"脖子", "哈哈"}) class BookStore { @Book(value = "Java基础精通1", price = 500, authors = {"脖1子", "哈2哈"}) public void run() { } } // 自定义一个注解 @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) // 申明只能注解方法与成员变量与类 @Retention(RetentionPolicy.RUNTIME) @interface Book { String value(); String[] authors(); double price(); String address() default "广州"; }
注解模拟Junit框架的基本使用
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface MyTest { } MyBook t = new MyBook(); Class d = MyBook.class; // 2.获取类中全部方法对象 Method[] methods = d.getDeclaredMethods(); for (Method method: methods) { if (method.isAnnotationPresent(MyTest.class)) { // 触发此方法执行 method.invoke(t);
}
} @MyTest public void test01() { System.out.println("====test01===="); } @MyTest public void test02() { System.out.println("====test02===="); } @MyTest public void test03() { System.out.println("====test03===="); }