一、单元测试
1.单元测试概述
- Java程序最小功能单元是方法,单元测试是针对最小的功能单元(方法)编写测试代码,进而检查方法的正确性;
- 实现自动化测试,获取测试结果报告
2. Junit单元测试框架
Junit是使用java编写的单元测试框架,开源;
- 几乎所有IED工具都集成了
JUnit,可以在IDE工具中直接编写并运行测试;
2.1 JUnit优点
- 灵活的选择执行哪些测试方法,可以一键执行全部测试方法;
- 可以生成全部方法的测试报告,绿色良好,红色失败;
- 某个方法测试失败,不会影响其他方法;
3.单元测试实例
- 将
JUnit的jar包导入项目;
- 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法;
- 测试方法使用@Test注解:标注是测试方法
- 测试方法中完成被测试方法的预期正确性测试;
- 选中测试方法,选择“
JUnit运行”,良好绿色,失败红色;
public class TestUserService {
@Test
public void testLoginName(){
UserService userService = new UserService();
String rs = userService.loginName("admin", "123456");
Assert.assertEquals("该功能方法可能存在问题","登录成功",rs);
}
@Test
public void testSelectName(){
UserService userService = new UserService();
userService.selectName();
}
@Before
public void before(){
System.out.println("@Before:在每个测试方法之前执行一次");
}
@After
public void after(){
System.out.println("@After:在每个测试方法之后执行一次");
}
@BeforeClass
public static void beforeClass(){
System.out.println("@BeforeClass:静态,在所有执行前,只执行一次");
System.out.println("=====================");
}
@AfterClass
public static void afterClass(){
System.out.println("=====================");
System.out.println("@AfterClass:静态,在所有执行后,只执行一次");
}
}
public class UserService {
public String loginName(String loginName,String passWord){
if ("admin".equals(loginName)){
System.out.println("登录成功");
return "登录成功";
}else {
return "out!";
}
}
public void selectName(){
System.out.println(10/2);
}
}
4.单元测试常用注解
4.1 JUnit4
- 开始执行方法:初始化资源;
- 执行完后方法:释放资源;
| 注解 | 说明 |
|---|
| @Test | 测试方法 |
| @Before | 修饰实例方法,每个测试方法前执行一次 |
| @After | 修饰实例方法,每个测试方法后执行一次 |
| @BeforeClass | 修饰静态方法,所有测试方法前,只执行一次 |
| @AfterClass | 修饰静态方法,所有测试方法后,只执行一次 |
4.2 JUnit5
| 注解 | 说明 |
|---|
| @Test | 测试方法 |
| @BeforeEach | 修饰实例方法,每个测试方法前执行一次 |
| @AfterEach | 修饰实例方法,每个测试方法后执行一次 |
| @BeforeAll | 修饰静态方法,所有测试方法前,只执行一次 |
| @AfterAll | 修饰静态方法,所有测试方法后,只执行一次 |
二、反射
1.反射概述
- 反射指对任何一个Class类,在“运行的时候”可以直接得到这个类全部成分;
- 在运行时,可以直接得到该类的构造器对象Constructor、成员变量对象Field、成员方法对象Method;
- 这种运行时动态获取类信息以及动态调用类中成分的能力称为java语言的反射机制;
2.反射关键
- 反射第一步是先得到编译后的class类对象,然后得到class的全部成分;
- 运行时获取类的字节码文件,解析类中全部成分
3.反射获取类对象的三种方法
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> c1 = Class.forName("d2_reflect_class/Student.java");
System.out.println(c1);
Class<Student> c2 = Student.class;
System.out.println(c2);
Student student = new Student();
Class c3 = student.getClass();
System.out.println(c3);
}
}
4.反射获取构造器
4.1利用反射技术获取构造器的推荐方法
Constructor<?>[] getDeclaredConstructors()
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
- 二者都可获取任意修饰的构造器
public class TestStudent01 {
@Test
public void getConstructors(){
Class c = Student.class;
Constructor[] constructors = c.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"====>"+constructor.getParameterCount());
}
}
@Test
public void getDeclaredConstructors(){
Class c = Student.class;
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"====>"+constructor.getParameterCount());
}
}
@Test
public void getConstructor() throws Exception {
Class c = Student.class;
Constructor cons = c.getConstructor();
System.out.println(cons.getName()+"====>"+cons.getParameterCount());
}
@Test
public void getDeclaredConstructor() throws NoSuchMethodException {
Class c = Student.class;
Constructor cons = c.getDeclaredConstructor();
System.out.println(cons.getName()+"====>"+cons.getParameterCount());
Constructor cons2 = c.getDeclaredConstructor(String.class,int.class,double.class);
System.out.println(cons2.getName()+"====>"+cons2.getParameterCount());
}
}
4.2反射得到构造器可以做什么?
- 创建对象:
public T newInstance(Object ... initargs)
- 非public构造器,需要打开权限(暴力反射),再创建对象
setAccessible(boolean flag)
- 反射会破坏封装性,私有的也可以访问
public class TestStudent02 {
@Test
public void getDeclaredConstructor() throws Exception {
Class c = Student.class;
Constructor cons = c.getDeclaredConstructor();
cons.setAccessible(true);
Student s = (Student) cons.newInstance();
System.out.println(s);
Constructor cons2 = c.getDeclaredConstructor(String.class,int.class,double.class);
System.out.println(cons2.getName()+"====>"+cons2.getParameterCount());
Student ss = (Student) cons2.newInstance("悟空",6800,1.88);
System.out.println(ss);
}
}
5.反射获取成员变量
5.1利用反射获取成员变量
- 获取所有成员变量
Field[] getDeclaredFields()
- 获取某个成员变量对象
Field getDeclaredField(String name)
public class FiledDemo01 {
@Test
public void getDeclaredFields(){
Class<Student> c = Student.class;
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName()+"===>"+field.getType());
}
}
@Test
public void getDeclaredField() throws NoSuchFieldException {
Class<Student> c = Student.class;
Field field = c.getDeclaredField("name");
System.out.println(field.getName()+"===>"+field.getType());
}
}
5.2对成员变量赋值和取值
- 赋值和取值:
- 赋值;set(Object obj, Object value)
- //取值:Object get(Object obj)
- 成员变量非public,需要打开权限暴力反射;
setAccessible(boolean flag)
public class FiledDemo02 {
@Test
public void setFiled() throws Exception {
Class<Student> studentClass = Student.class;
Field ageF = studentClass.getDeclaredField("age");
ageF.setAccessible(true);
Student s = new Student();
ageF.set(s,18);
System.out.println(s);
int age = (int) ageF.get(s);
System.out.println(age);
}
}
6.反射获取成员变量方法并触发执行方法
public class MethodDemo01 {
@Test
public void getDeclaredMethods(){
Class c = Student.class;
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName()+"返回值类型:"+method.getReturnType()+" 参数个数: "+method.getParameterCount());
}
}
@Test
public void getDeclaredMethod() throws Exception {
Class c = Student.class;
Method method = c.getDeclaredMethod("wKHeight");
System.out.println(method.getName()+"返回值类型:"+method.getReturnType()+" 参数个数: "+method.getParameterCount());
Method method2 = c.getDeclaredMethod("wKHeight",String.class);
System.out.println(method2.getName()+"返回值类型:"+method2.getReturnType()+" 参数个数: "+method2.getParameterCount());
method.setAccessible(true);
method2.setAccessible(true);
Student student = new Student();
Object invoke = method.invoke(student);
System.out.println(invoke);
Object invoke2 = method2.invoke(student, "悟空");
System.out.println(invoke2);
}
}
7.反射的作用:绕过编译阶段为集合添加数据
- 反射是作用在运行时的技术,此时集合的泛型不能产生约束,此时集合可以存入任意类型元素;
- 泛型只是在编译阶段可以约束集合只能操作某种类型,编译成Class文件进入运行阶段,真实类型都是ArrayList,泛型被擦除了;
- JDK1.5之前没有泛型,为了兼容之前代码,需要泛型擦除
public class ReflectDemo01 {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list1 = new ArrayList<>();
ArrayList<String> list2 = new ArrayList<>();
System.out.println(list1.getClass() == list2.getClass());
list1.add(5);
list1.add(55);
Class c = list1.getClass();
Method add = c.getDeclaredMethod("add", Object.class);
Boolean rs = (Boolean) add.invoke(list1, "黑夜");
System.out.println(rs);
System.out.println(list1);
ArrayList list3 = list1;
list3.add(false);
list3.add(56.55);
System.out.println(list1);
}
}
8.反射的作用:通用框架的底层原理
- 反射的作用:
- 运行时得到类的全部成分然后操作
- 可以破坏封装(很突出)
- 可以破坏泛型约束(很突出)
- 更重要的用途:做java高级框架
public class MybatisUtil {
public static void save(Object obj) {
try (
PrintStream ps = new PrintStream(new FileOutputStream("day12_junit_reflect_annotation_proxy_app/src/data.txt", true));
) {
Class c = obj.getClass();
ps.println("============" + c.getSimpleName() + "=============");
Field[] fields = c.getDeclaredFields();
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();
}
}
}
public class ReflectFrameWorkDemo {
public static void main(String[] args) {
Student s = new Student("重云", 17, 1.70);
MybatisUtil.save(s);
Teacher t = new Teacher("退休老大爷", 10000, 0.0);
MybatisUtil.save(t);
}
}
三、注解
1.注解概述、作用
- java注解(Annotation)又称java标注,JDK5引入的注释机制;
- java语言中的类、构造器、方法、成员变量、参数都可以被注解进行标注;
- 标注后进行特殊处理,处理方式由业务需求决定
- 如@Test,标记为测试方法
2.自定义注解
public @interface 注解名称{
public 属性类型 属性名() default 默认值;
}
@Book("钢铁是怎样炼成的")
@MyBook(name = "斗破乾坤",authors = {"小火火","东东"},price = 98.8)
public class AnnotationDemo01 {
@Book("钢铁是怎样炼成的")
private AnnotationDemo01(){
}
@Book("钢铁是怎样炼成的")
public static void main(String[] args) {
@Book("钢铁是怎样炼成的")
int age = 23;
}
}
public @interface MyBook {
String name();
String[] authors();
double price() default 9.99;
}
public @interface Book {
String value();
double price() default 9.99;
}
3.元注解
- 概述:注解 注解的注解;
- 常见的两个元注解:
- @Target:约束自定义注解只能在哪些地方使用;
- @Retention:申明注解的生命周期;
3.1元注解的常用参数
- @Target中可使用值定义在ElementType枚举类
- @Retention中可使用值定义在RetentionPolicy枚举类
| @Target | |
|---|
| TYPE | 类、接口 |
| FIELD | 成员变量 |
| METHOD | 成员方法 |
| PARAMETER | 方法参数 |
| CONSTRUCTOR | 构造器 |
| LOCAL_VARIABLE | 局部变量 |
| @Retention | |
|---|
| SOURCE | 作用在源码阶段, |
| CLASS | 作用在源码阶段,字节码文件阶段,运行阶段不存在,默认设置 |
| RUNTIME | 作用在源码阶段,字节码文件阶段,运行阶段(开发中常用) |
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
4.注解的解析
- 注解的操作中经常需要解析,判断是否存在注解,存在,解析出内容。
- 与注解解析相关的接口:
- Annotation:注解顶级接口,注解都是Annotation类型对象;
AnnotatedElement:该接口定义了与注解解析相关的解析方法;
- 所有的类成分都实现了
AnnotatedElement接口他们都拥有解析注解的能力;
public class AnnotationDemo03 {
@Test
public void parseClass(){
Class c = BookStore.class;
if (c.isAnnotationPresent(Books.class)){
Books books = (Books) c.getDeclaredAnnotation(Books.class);
System.out.println(books.value());
System.out.println(books.price());
System.out.println(Arrays.toString(books.authors()));
}
}
@Test
public void parseMethod() throws NoSuchMethodException {
Class c = BookStore.class;
Method m = c.getDeclaredMethod("test");
if (m.isAnnotationPresent(Books.class)){
Books books = (Books) m.getDeclaredAnnotation(Books.class);
System.out.println(books.value());
System.out.println(books.price());
System.out.println(Arrays.toString(books.authors()));
}
}
}
@Books(value = "《斗破大地》",price = 6.2,authors = {"王某","某陆"})
class BookStore{
@Books(value = "《斗破海洋》",price = 16.2,authors = {"海某","某洋"})
public void test(){
}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Books {
String value();
double price() default 100;
String[] authors();
}
5.注解场景:JUnit框架
public class AnnotationDemo04 {
@MyTest
public void test01() {
System.out.println("test01");
}
public void test02() {
System.out.println("test02");
}
@MyTest
public void test03() {
System.out.println("test03");
}
public static void main(String[] args) throws Exception {
AnnotationDemo04 a = new AnnotationDemo04();
Class c = AnnotationDemo04.class;
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(a);
}
}
}
}
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
四、动态代理
1.代理概述
- 代理:某些场景,对象会找一个代理对象,辅助完成工作;
- 事务先找代理,先处理一些辅助工作,再由代理通知对象完成主要工作,代理处理首尾工作(如果需要);
2.创建代理对象
- Java中代理的代表类:
java.lang.reflect.Proxy;
- Proxy提供一个静态方法,用于为对象产生一个代理对象返回;
public class ProxyTest {
public static void main(String[] args) {
Star s = new Star("iKun");
Skill proxy = StarAgentProxy.getProxy(s);
String sing = proxy.sing();
System.out.println("第一个返回值:"+sing);
proxy.jump();
proxy.rap();
proxy.basketBall();
}
}
public interface Skill {
String sing();
void jump();
void rap();
void basketBall();
}
public class Star implements Skill{
private String name;
public Star(String name) {
this.name = name;
}
@Override
public String sing() {
System.out.println(name+"唱,叽叽叽叽。。。");
return "感谢粉丝";
}
@Override
public void jump() {
System.out.println(name+"跳,jump,跳起来就是一脚!");
}
@Override
public void rap() {
System.out.println(name+"这个碗又大又圆。。。");
}
@Override
public void basketBall() {
System.out.println(name+"球。。。");
}
}
public class StarAgentProxy {
public static Skill getProxy(Star star){
return (Skill) Proxy.newProxyInstance(star.getClass().getClassLoader()
, star.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("收订金!!!!");
Object rs = method.invoke(star, args);
System.out.println("收尾款!!!正主回家");
return rs;
}
});
}
}
3.动态代理应用案例:性能分析
3.1性能分析
public interface UserService {
String login(String name,String passWord);
void deleteUser();
String selectUsers();
}
public class UserServiceImpl implements UserService {
@Override
public String login(String name, String passWord) {
long startTime = System.currentTimeMillis();
if (name.equals("admin") && passWord.equals("123")) {
try {
Thread.sleep(2 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("登录成功");
long endTime = System.currentTimeMillis();
System.out.println("耗费时间:" + (endTime - startTime) / 1000);
return "登录成功";
}
System.out.println("登录信息有误,请检查!");
long endTime = System.currentTimeMillis();
System.out.println("耗费时间:" + (endTime - startTime) / 1000);
return "登录信息有误,请检查!";
}
@Override
public void deleteUser() {
long startTime = System.currentTimeMillis();
try {
System.out.println("删除用户信息中。。。。");
Thread.sleep(3 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("耗费时间:" + (endTime - startTime) / 1000);
}
@Override
public String selectUsers() {
long startTime = System.currentTimeMillis();
try {
System.out.println("查询到100条用户信息。。。。");
Thread.sleep(5 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println("耗费时间:" + (endTime - startTime) / 1000);
return "100条信息汇总";
}
}
public class Test01 {
@Test
public void Test01(){
UserService userService = new UserServiceImpl();
System.out.println(userService.login("admin", "123"));
System.out.println(userService.selectUsers());
userService.deleteUser();
}
}
3.2动态代理实现性能分析,减少代码冗余
public interface UserService {
String login(String name,String passWord);
void deleteUser();
String selectUsers();
}
public class UserServiceImplProxy implements UserService {
@Override
public String login(String name, String passWord) {
if (name.equals("admin") && passWord.equals("123")) {
try {
Thread.sleep(2 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("登录成功");
return "登录成功";
}
return "登录信息有误,请检查!";
}
@Override
public void deleteUser() {
try {
System.out.println("删除用户信息中。。。。");
Thread.sleep(3 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String selectUsers() {
try {
System.out.println("查询到100条用户信息。。。。");
Thread.sleep(5 * 1000);
} catch (Exception e) {
e.printStackTrace();
}
return "100条信息汇总";
}
}
public class ProxyUtil {
public static UserService getProxy(UserService obj) {
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);
return rs;
}
});
}
}
public class Test01 {
@Test
public void TestProxy(){
UserService userService = ProxyUtil.getProxy(new UserServiceImplProxy());
System.out.println(userService.login("admin", "123"));
System.out.println(userService.selectUsers());
userService.deleteUser();
}
}
4.动态代理优点
- 不改变方法源码情况下,实现对方法功能增强,提高代码复用性;
- 简化编程,调高软件系统可扩展性;
- 可以为被代理对象所有方法做代理;
- 灵活,支持任意接口类型的实现类对象做代理,也可以为接口本身做代理;
public class ProxyUtil2 {
public static <T> T getProxy(T obj) {
return (T) 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);
return rs;
}
});
}
}
RecordDate:2021/08/22