一、单元测试
1.单元测试概述
(1)单元测试
- 针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性
(2)Junit单元测试框架
- JUnit是使用Java语言实现的单元测试框架,是开源的
- 所有的IDE工具都集成了JUnit
(3)JUnit优点
- 灵活选择执行哪些测试方法,可一键执行全部测试方法;
- Junit可生成全部方法的测试报告;
- 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。
2.单元测试入门
- 将JUnit的jar包导入项目
- 编写测试方法:该测试方法必须是公共的无参数无返回值的非静态方法
- 在测试方法上使用@Test注解,标注该方法是一个测试方法
- 在测试方法中完成被测试方法的预期正确性测试
- 选中测试方法,选择“JUnit”运行。
3.单元测试常用注解
二、反射
1.反射概述
(1)反射概述
- 反射是指对于任何一个Class类,在“运行的时候”都可以直接得到这个类全部成分;
- 在运行时,可以直接得到这个类的构造器对象:Constructor
- 在运行时,可以直接得到这个类的成员变量对象:Field
- 在运行时,可以直接得到这个类的成员方法对象:Method
- 这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制
(2)反射的关键
- 反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分
2.反射获取类对象
反射的第一步:获取Class类的对象
public class Test {
public static void main(String[] args) throws Exception {
Class c = Class.forName("d1_reflect_class.Student");
System.out.println(c);
//2.类名.class
Class c1 = Student.class;
System.out.println(c1);
//3. 对象.getClass()获取对象对应类的Class对象
Student s = new Student();
Class c2 = s.getClass();
System.out.println(c2);
}
}
3.反射获取构造器对象
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象
//1.getConstructors:
//获取全部的构造器:只能获取public修饰的构造器
//Constructor[] getConstructors
@Test
public void getConstructors(){ //只能拿public修饰的构造器
//o1.获取类对象
Class c = Student.class;
//o2.提取类中的全部构造器对象
Constructor[] constructors = c.getConstructors();
//o3. 遍历构造器看有没有拿到
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"1===>"+constructor.getParameterCount());
}
}
//2.getDeclaredConstructors():
//获取全部的构造器,只要你敢写,这里就能拿到,无所谓权限是否可及
@Test
public void getDeclaredConstructors(){
//o1.获取类对象
Class c = Student.class;
//o2.提取类中的全部构造器对象
Constructor[] constructors = c.getDeclaredConstructors();
//o3. 遍历构造器看有没有拿到
for (Constructor constructor : constructors) {
System.out.println(constructor.getName()+"2===>"+constructor.getParameterCount());
}
}
//3.getConstructor(Class...parameterTypes)
//获取某个构造器,只能拿public修饰的某个构造器
@Test
public void getConstructor() throws Exception{
Class c = Student.class;
//o2.定位单个构造器对象
Constructor cons = c.getConstructor();
System.out.println(cons.getName()+"3===>"+cons.getParameterCount());
}
//4.getDeclaredConstructor
//获取某个构造器,只要你敢写,这里就能拿到,无所谓权限是否可及
@Test
public void getDeclaredConstructor() throws Exception{
//o1.获取类对象
Class c = Student.class;
//o2.提取类中的单个构造器对象
Constructor con = c.getDeclaredConstructor();
System.out.println(con.getName()+"4===>"+con.getParameterCount());
//定位某个有参构造器
Constructor con2 = c.getDeclaredConstructor(String.class,int.class);
System.out.println(con2.getName()+"5===>"+con2.getParameterCount());
}
- 获取构造器的作用依旧是初始化一个对象返回
@Test
public void getDeclaredConstructor() throws Exception{
//o1.获取类对象
Class c = Student.class;
//o2.提取类中的单个构造器对象
Constructor con = c.getDeclaredConstructor();
System.out.println(con.getName()+"4===>"+con.getParameterCount());
//如果遇到私有的构造器,可以暴力反射
con.setAccessible(true); //权限被打开
Student s = (Student) con.newInstance();
System.out.println(s);
//定位某个有参构造器
Constructor con2 = c.getDeclaredConstructor(String.class,int.class);
System.out.println(con2.getName()+"5===>"+con2.getParameterCount());
Student s1 = (Student) con2.newInstance("sun",100);
System.out.println(s1);
}
- 如果是非public的构造器,需要打开权限,然后再创建对象
setAccessible(boolean)
4.反射获取成员变量对象
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象
- Class类中用于获取成员变量的方法
@Test
public void getDeclaredFields(){
//a.定位Class对象
Class c = Student.class;
//b.定位全部成员变量
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + "==>" + field.getType());
}
}
/**
* 2.获取某个成员变量对象
*/
@Test
public void getDeclaredField() throws Exception{
//a.定位Class对象
Class c = Student.class;
//b.定位某个成员变量
Field f = c.getDeclaredField("age");
System.out.println(f.getName() + "==>" + f.getType());
}
- 成员变量赋值、取值
@Test
public void setField() throws Exception{
Class c = Student.class;
Field ageF = c.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);
}
5.反射获取方法对象
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象
- Object invoke(Object obj, Object… args) ----在某个对象中出发该方法执行
- 非public的成员方法,需要暴力打开权限
6.反射的作用-绕过编译阶段为集合添加数据
- 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的
- 泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList,泛型相当于被擦除了
7.反射的作用-通用框架的底层原理
三、注解
(1)注解概述、作用
- Java注解又称Java标注,是JDK5引入的一种注解机制
- Java语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注
(2)注解的作用
- 对Java中类、方法、成员变量做标记,然后进行特殊处理
- eg. @Test方法就可以被当做测试方法执行
(3)自定义注解—格式
public @interface 注解名称{
public 属性类型 属性名() default 默认值;
}
- 特殊属性:
value属性:如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写;但是有多个属性,且多个属性没有默认值,那么value是不能省略的
(4)元注解
- 就是注解注解的注解
- 元注解常见的有两个
a. @Target:约束自定义注解只能在哪些地方使用
b. @Retention:申明注解的生命周期
(5)注解解析 - 判断是否存在注解,存在注解就解析出内容
- 与注解解析相关的接口:
Annotation:注解的顶级接口,注解都是Annotation类型的对象
AnnotatedElement:定义与注解解析相关的解析方法
所有的类成分Class、Method、Field、Constructor,都实现了AnnotatedElement接口,都拥有解析注解的能力。
/**
* 完成注解的解析
*/
public class Demo2 {
@Test
public void parseClass(){
//先得到类对象
Class c = BookStore.class;
//判断类上是否存在注解
if(c.isAnnotationPresent(book.class)){
//直接获取该注解对象
book bk = (book)c.getDeclaredAnnotation(d4_annotation.book.class);
System.out.println(bk.value());
System.out.println(bk.price());
System.out.println(Arrays.toString(bk.author()));
}
}
@Test
public void parseMethod() throws Exception{
//先得到类对象
Class c = BookStore.class;
Method m = c.getDeclaredMethod("test");
//判断类上是否存在注解
if(m.isAnnotationPresent(book.class)){
//直接获取该注解对象
book bk = (book)m.getDeclaredAnnotation(d4_annotation.book.class);
System.out.println(bk.value());
System.out.println(bk.price());
System.out.println(Arrays.toString(bk.author()));
}
}
}
@book(value = "《某某》",price = 99.9,author = {"江添","盛旺"})
class BookStore{
@book(value = "《不见上仙三百年》",price = 199.9,author = {"木苏里","魔道"})
public void test(){
}
}
@Target({ElementType.METHOD,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)//一直活着,在运行阶段也不消失
public @interface Mytest {
}
(6)注解的应用场景:junit框架
四、动态代理
(1)动态代理概述、入门
什么是代理?
某些场景下对象会找一个代理对象,来辅助自己完成一些工作
//Test
//目标:学习开发出一个动态代理的对象出来,理解动态代理的执行流程
//1.创建一个对象,对象的类必须实现接口
public static void main(String[] args) {
Star s = new Star("杨超越");
//生成s的代理对象
Skill s2 = StarAgent.getProxy(s);
s2.jump();
s2.sing();
}
//StarAgent
public static Skill getProxy(Star obj){
//为s生成一个代理对象
return (Skill) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("收定金");
//触发对象真正去干活
//method 正在调用的方法 args 代表这个方法的参数
Object rs = method.invoke(obj,args);
System.out.println("收尾款");
return rs;
}
});
}
public class Star implements Skill {
private String name;
public Star(String name) {
this.name = name;
}
@Override
public void jump() {
System.out.println(name + "开始跳舞");
}
@Override
public void sing() {
System.out.println(name + "开始唱歌");
}
}
//接口
public interface Skill {
void jump();
void sing();
}
(2)动态代理应用案例:做性能分析、代理的好处小结
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.deleteUser();
}
}
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 (Exception e) {
e.printStackTrace();
}
return rs;
}
@Override
public void deleteUser() {
try {
System.out.println("您正在删除用户数据");
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String selectUsers() {
String rs = "查询了10000个用户数据";
try {
Thread.sleep(3000);
} catch (Exception e) {
e.printStackTrace();
}
return rs;
}
}
public interface UserService {
String login(String loginName, String passWord);
void deleteUser();
String selectUsers();
}
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 starTime = System.currentTimeMillis();
//真正触发对象的行为执行
Object rs = method.invoke(obj,args);
long endTime = System.currentTimeMillis();
System.out.println( method.getName() +"方法耗时:" + (endTime-starTime)/1000.0 +"s");
return rs;
}
});
}
}