单元测试、反射、注解、动态代理
- 单元测试
- 单元测试概述
- 单元测试快速入门
- 单元测试常用注解
- 反射
- 反射概述
- 反射获取类对象
- 反射获取构造器对象
- 反射获取成员变量对象
- 反射获取方法对象
- 反射的作用-绕过编译阶段为集合添加数据
- 反射的作用-通用框架的底层原理
- 注解
- 注解概述
- 自定义注解
- 元注解
- 注解解析
- 注解的应用场景一:junit框架
- 动态代理
单元测试
单元测试概述
Junit单元测试是做什么的?
测试类中方法的正确性的。
Junit单元测试的优点是什么?
JUnit可以选择执行哪些测试方法,可以一键执行全部测试方法的测试。
JUnit可以生测试报告,如果测试良好则是绿色;如果测试失败,则是红色。
单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。
单元测试快速入门
单元测试常用注解
反射
反射概述
反射获取类对象
反射的第一步是什么?
获取Class类对象,如此才可以解析类的全部成分
获取Class类的对象的三种方式
方式一:Class c1 = Class.forName(“全类名”);
方式二:Class c2 = 类名.class
方式三:Class c3 = 对象.getClass();
反射获取构造器对象
利用反射技术获取构造器对象的方式
getDeclaredConstructors()
getDeclaredConstructor (Class<?>… parameterTypes)
反射得到的构造器可以做什么?
依然是创建对象的
public newInstance(Object… initargs)
如果是非public的构造器,需要打开权限(暴力反射),然后再创建对象
setAccessible(boolean)
反射可以破坏封装性,私有的也可以执行了。
反射获取成员变量对象
利用反射技术获取成员变量的方式
获取类中成员变量对象的方法
getDeclaredFields()
getDeclaredField (String name)
反射得到成员变量可以做什么?
依然是在某个对象中取值和赋值。
void set(Object obj, Object value):
Object get(Object obj)
如果某成员变量是非public的,需要打开权限(暴力反射),然后再取值、赋值
setAccessible(boolean)
反射获取方法对象
利用反射技术获取成员方法对象的方式
获取类中成员方法对象
getDeclaredMethods()
getDeclaredMethod (String name, Class<?>… parameterTypes)
反射得到成员方法可以做什么?
依然是在某个对象中触发该方法执行。
Object invoke(Object obj, Object… args)
如果某成员方法是非public的,需要打开权限(暴力反射),然后再触发执行
setAccessible(boolean)
反射的作用-绕过编译阶段为集合添加数据
反射为何可以给约定了泛型的集合存入其他类型的元素?
编译成Class文件进入运行阶段的时候,泛型会自动擦除。
反射是作用在运行时的技术,此时已经不存在泛型了。
反射的作用-通用框架的底层原理
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//需求:反射实现泛型擦除后,加入其他类型的元素
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass());
System.out.println(list2.getClass());
System.out.println(list1.getClass() == list2.getClass());//ArrayList.class
System.out.println("-------------------------------");
ArrayList<Integer> list3 = new ArrayList<>();
list3.add(23);
list3.add(22);
// list2.add("黑马");
Class c = list3.getClass();//ArrayList.class ==> public boolean add(E e)
//定位c类中的 add方法
Method add = c.getDeclaredMethod("add",Object.class);//方法名和方法的参数
boolean rs = (boolean)add.invoke(list3,"黑马");
System.out.println(rs);
System.out.println(list3);
//更便捷的方法
ArrayList list4 = list3;
list4.add("白马");
list4.add(false);
System.out.println(list3);
}
}
注解
注解概述
对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。
例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。
自定义注解
特殊属性
value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!!
但是如果有多个属性, 且多个属性没有默认值,那么value名称是不能省略的。
元注解
元注解:注解注解的注解。
元注解有两个:
@Target: 约束自定义注解只能在哪些地方使用,
@Retention:申明注解的生命周期
注解解析
解析注解的技巧
注解在哪个成分上,我们就先拿哪个成分对象。
比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解
注解的应用场景一:junit框架
public class AnnotationDemo4 {
@MyTest
public void test1(){
System.out.println("===test1===");
}
public void test2(){
System.out.println("===test2===");
}
@MyTest
public void test3(){
System.out.println("===test3===");
}
/*
启动菜单:有注解的才被调用
*/
public static void main(String[] args) throws Exception {
AnnotationDemo4 t = new AnnotationDemo4();
//a.获取类对象
Class c = AnnotationDemo4.class;
//b.提取全部方法
Method[] methods = c.getDeclaredMethods();
//c.遍历方法,看是否有MyTest注解,有就跑它
for (Method method : methods) {
if(method.isAnnotationPresent(MyTest.class)){
//跑它
method.invoke(t);
}
}
}
}
动态代理
动态代理的优点
非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。
可以为被代理对象的所有方法做代理。
可以在不改变方法源码的情况下,实现对方法功能的增强。
不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。
public interface UserService {
String login(String loginName,String passWord);
void deleteUsers();
String selectUsers();
void deleteById(int id);
}
public class UserServiceimpl implements UserService{
@Override
public String login(String loginName, String passWord) {
String rs = "登录名和密码错误";
if("admin".equals(loginName)&& "123456".equals(passWord)){
rs = "登陆成功";
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return rs;
}
@Override
public void deleteUsers() {
try {
System.out.println("您正在删除用户数据中。。。。");
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String selectUsers() {
String rs = "查询了10000个用户数据~~~";
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return rs;
}
@Override
public void deleteById(int id) {
try {
System.out.println("根据用户的身份证号码:" + id + "删除了它~~");
Thread.sleep(1200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ProxyUtil {
/*
通过一个静态方法,为用户对象返回一个代理对象
*/
public static UserService getProxy(UserService obj){//可以讲这几个UserService用T替代,这样就可以为任意接口的实现类对象做代理
return (UserService) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
//真正触发对象的行为执行的。
Object rs = method.invoke(obj,args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+"方法耗时:" + (endTime - startTime) / 1000.0 + "s");
return rs;
}
});
}
}
public class Test {
public static void main(String[] args) {
//目标:掌握使用动态代理解决问题,理解使用动态的优势。
UserService userService = ProxyUtil.getProxy(new UserServiceimpl());
System.out.println(userService.login("admin", "123456"));
System.out.println(userService.selectUsers());
userService.deleteUsers();
userService.deleteById(9);
}
}