java进阶开发-----单元测试、反射、注解、动态代理

(一)、单元测试
单元测试就是针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性。(相当于main方法测试小方法的运行)

1. JUnit框架---测试类中方法的正确性的。
JUnit可以选择执行哪些测试方法,可以一键执行全部测试方法的测试。  
JUnit可以生测试报告,如果测试良好则是绿色;如果测试失败,则是红色。

单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。

//待测方法
public class UserService {
    public String loginName(String loginName, String password){
        if("admin".equals(loginName) && "123456".equals(password)){
            return "登录成功";
        }else {
            return "用户名或者密码有问题";
        }
    }
    public void selectName(){
        System.out.println(10/0);
        System.out.println("查询全部用户名称成功");
    }
}

//使用框架
import org.junit.Assert;
import org.junit.Test;

public class TestUserService {
    //测试方法
    //1.必须公开的,无参数 无返回值的方法
    //2.测试方法必须使用@Test注解标记
    @Test
    public void testuserservice(){
        UserService userService = new UserService();
        String rs = userService.loginName("admin","123456");
        //预测结果的正确性测试:断言
        Assert.assertEquals("您的功能业务可能出现问题","登录成功",rs);
    }
    @Test
    public void testuserservic() {
        UserService userService = new UserService();
        userService.selectName();
    }
}

 2.JUnit常用注解

@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执行");
}
@AfterClass
public static void afterClass(){
    System.out.println("afterClass执行");
}

 (二)、反射
反射是在运行时获取类的字节码文件对象:然后可以解析类中的全部成分。
反射的核心思想和关键就是:得到编译以后的class文件对象。
1.获取类Class对象

public class refilectTect {
    public static void main(String[] args) throws Exception{
        //Class类中的一个静态方法:forName(全限名:包名+类名)
        Class c = Class.forName("day05.Student");
        System.out.println(c);
        //类名.class
        Class c1 = Student.class;
        //对象.getClass()获取对应类的Class对象
        Student s = new Student();
        Class c2 = s.getClass();
        System.out.println(c2);
    }
}

2.获取构造器Constructor对象 

import org.junit.Test;
import java.lang.reflect.Constructor;

public class TestStudent1 {
    //getConstructors,获取public修饰的构造器
    //Constructor[] getConstructors()
    @Test//测试本身的方法
    public void getConstructors(){
        //第一步,获取类构造器
        Class c = Student.class;
        //获取类中的全部构造器对象(只能拿public)
        Constructor[] constructors = c.getConstructors();
        //遍历构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());//名字+数量
        }
    }
    //getDeclaredConstructors,获取全部构造器,只要敢调都能拿
    @Test
    public void getDeclaredConstructors(){
        //第一步,获取类构造器
        Class c = Student.class;
        //获取类中的全部构造器对象
        Constructor[] constructors = c.getDeclaredConstructors();
        //遍历构造器对象
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "==>" + constructor.getParameterCount());
        }
    }
    //单个构造器,上面的方法去掉s
    @Test
    public void getConstructor() throws Exception {
        //第一步,获取类构造器
        Class c = Student.class;
        //定位单个构造器对象(按照参数定位无参构造器)public
        Constructor cons = c.getConstructor();
        //遍历构造器对象
        System.out.println(cons.getName() + "==>" + cons.getParameterCount());
    }
    @Test
    public void getDeclaredConstructor() throws Exception {
        //第一步,获取类构造器
        Class c = Student.class;
        //定位单个构造器对象(按照参数定位无参构造器)public
        Constructor cons = c.getDeclaredConstructor();
        //无参
        System.out.println(cons.getName() + "==>" + cons.getParameterCount());
        Constructor cons1 = c.getDeclaredConstructor(String.class,int.class);
        //有参
        System.out.println(cons.getName() + "==>" + cons.getParameterCount());
    }
}

3.构造器构造对象(构造器new对象)构造器 ==> 构造方法

import org.junit.Test;
import java.lang.reflect.Constructor;

public class TestStudent2 {
    @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);//Student{name='null', age=0}
        System.out.println(cons.getName() + "==>" + cons.getParameterCount());
        //有参
        Constructor cons1 = c.getDeclaredConstructor(String.class, int.class);
        System.out.println(cons1.getName() + "==>" + cons1.getParameterCount());
        Student s1 =(Student) cons1.newInstance("asd",23);
        System.out.println(s1);
    }
}

 4.获取对象成员变量并赋值、取值

import org.junit.Test;
import java.lang.reflect.Field;
//获取对象成员变量
public class FieldDemo1 {
    @Test
    //获取全部成员变量
    public void getDeclaredFields(){
        //定位Class对象
        Class c = Student.class;
        //定位全部成员变量
        Field[] fields = c.getDeclaredFields();
        //遍历一下
        for (Field field : fields) {
            System.out.println(field.getName() + "==>" + field.getType());
        }
    }
    @Test
    public void getDeclaredField() throws Exception {
        //定位Class对象
        Class c = Student.class;
        //定位全部成员变量
        Field fields1 = c.getDeclaredField("age");
        System.out.println(fields1.getName() + "==>" + fields1.getType());
    }
}

import java.lang.reflect.Field;

public class FieldDemo2 {
    public void setField() throws Exception{
        //获取对象
        Class c = Student.class;
        //提取成员变量
        Field ageF = c.getDeclaredField("age");
        ageF.setAccessible(true);//非public强转
        //赋值
        Student s = new Student();
        ageF.set(s,12);
        System.out.println(s);
        //取值
        int age = (int) ageF.get(s);
        System.out.println(s);
    }
}

5.获取对象方法并执行一些操作

import org.junit.Test;
import java.lang.reflect.Method;

public class MethodDemo1 {
    @Test
    public void getDelaredMethods(){
        Class c = Dog.class;
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName() + " 返回值类型:" + method.getReturnType() + "参数个数" + method.getParameterCount());
        }
    }
    @Test
    public void getDelaredMethod() throws Exception{
        Class c = Dog.class;
        //提取方法的执行
        Method method = c.getDeclaredMethod("eat");
        Method method1 = c.getDeclaredMethod("eat",String.class);
        //暴力打开权限
        method.setAccessible(true);
        method1.setAccessible(true);
        //触发方法的执行
        Dog d = new Dog();
        Object e = method.invoke(d);
        //没结果返回null
        System.out.println(e);
        Object e1 = method1.invoke(d,"骨头");
        System.out.println(e1);
    }
}

 6.反射实现泛型擦除

import java.lang.reflect.Method;
import java.util.ArrayList;

public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        //反射实现泛型擦除后,加入其他类型的元素
        ArrayList<String> lists1 = new ArrayList<>();
        ArrayList<Integer> lists2 = new ArrayList<>();
        System.out.println(lists1.getClass());
        System.out.println(lists2.getClass());
        System.out.println(lists1.getClass() == lists2.getClass());
        ArrayList<Integer> lists3 = new ArrayList<>();
        lists3.add(23);
        lists3.add(24);
        //lists2.add("字符");
        Class c = lists3.getClass();//ArrayList.class ===> public boolean add(E e)
        Method add = c.getDeclaredMethod("add" ,Object.class);
        add.invoke(lists3,"翻墙");
        System.out.println(lists3);
        ArrayList list4 = lists3;
        list4.add("再翻");
        System.out.println(list4);
    }
}

7.反射的作用-通用框架的底层原理
eg.给你任意一个对象,在不清楚对象字段的情况可以把对象的字段名称和对应值存储到文件中去

import org.junit.Test;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class MybatisUtil {
    @Test
    public static void save(Object obj){
        //提取对象的所有成员变量。只有反射能做到
        try (
                PrintStream ps = new PrintStream(new FileOutputStream("./data.txt"))
        ){
            Class c = obj.getClass();//c.getSimpleName() 获取当前类名 c.getName()获取全限名:包名+类名
            ps.println(c.getSimpleName());
            //提取当前全部成员变量
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                String name = field.getName();
                //提取本成员变量的值
                field.setAccessible(true);
                String value = field.get(obj) + "";
                System.out.println(name + "====" + value);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

public class ReflectDemo {
    public static void main(String[] args) throws Exception{
        Student s = new Student();
        s.setName("sss");
        s.setClassName("www");
        s.setAge(2);
        s.setHobby("吃");
        s.setSex('b');
        MybatisUtil.save(s);

        teacher t = new teacher();
        t.setName("dada");
        t.setSex('s');
        t.setSalary(23232);
        MybatisUtil.save(s);
    }
}

8.反射作用总结

  • 可以在运行时得到一个类的全部成分然后操作。
  • 可以破坏封装性。(很突出)
  • 也可以破坏泛型的约束性。(很突出)
  • 更重要的用途是适合:做Java高级框架基本上主流框架都会基于反射设计一些通用技术功能。

(三)、注解
对Java中类、方法、成员变量做标记进行特殊处理,至于到底做何种处理由业务需求来决定。
1.自定义注解

//掌握注解语法
@Mybook(name="精通JavaSE",authors = {"喜欢","喜欢"},price = 122.3)
@Book(value = "/detate")//==>@Book("/detate")//只有一个属性时
public class AnnotationDemo1 {
    @Mybook(name="sss",authors = {"aaa","aaaaa"},price = 233.2)
    private AnnotationDemo1(){

    }
    @Mybook(name="sss",authors = {"aaa","aaaaa"},price = 233.2)
    public static void main(String[] args) {
        @Mybook(name="sss",authors = {"aaa","aaaaa"},price = 233.2)
        int age = 21;
    }
}
public @interface Mybook {
    String name();
    String[] authors();
    double price();
}
public @interface Book {
    String value();//特殊属性
    double price() default 9.9;//默认值
    //public 属性类型 属性名() default 默认值
}

2,元注解 
注解注解的注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD,ElementType.FIELD})//元注解,只能注解方法和成员变量
@Repeatable(RetentionPolicy.RUNTIME)//一直活着,在运行阶段这个注解也不会消失
public @interface MyTest {
}

public class AnnotationDemo2 {
    @MyTest//注解约束
    private String name;
    @MyTest
    public void test(){
    }
}
@Target约束自定义注解可以标记的范围。
@Retention用来约束自定义注解的存活范围。

3.注解的解析
注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。

public class AnnotationDemo3 {
    @Test
    public void parseClass() throws Exception{
        Class c = BookStore.class;
        //判断是否存在这个注解
        if(c.isAnnotationPresent(Bookk.class)){
            Bookk book = (Bookk)c.getDeclaredAnnotation(Bookk.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.author()));
        }
    }
    @Test
    public void parseMethod() throws NoSuchMethodException {
        Class c = BookStore.class;
        Method m = c.getDeclaredMethod("test");
        //判断是否存在这个注解
        if(m.isAnnotationPresent(Bookk.class)){
            Bookk book = (Bookk)m.getDeclaredAnnotation(Bookk.class);
            System.out.println(book.value());
            System.out.println(book.price());
            System.out.println(Arrays.toString(book.author()));
        }
    }
}

@Bookk(value = "晚熟的人",price = 21.1,author = {"余华","莫言"})
class BookStore{
    @Bookk(value = "莫比特斯",price = 21.1,author = {"感染力","莫言"})
    public void test(){

    }
}

 定义若干个方法,只要加了MyTest注解,就可以在启动时被触发执行

public class AnnotationDemo4 {
    @MyTest
    public void teat1(){
        System.out.println("==test1===");
    }
    public void teat2(){
        System.out.println("==test1===");
    }
    @MyTest
    public void teat3(){
        System.out.println("==test1===");
    }
    //有注解的才调用
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        AnnotationDemo4 t =new AnnotationDemo4();
        //1.获取类对象
        Class c = AnnotationDemo4.class;
        //提取全部方法
        Method[] methods = c.getDeclaredMethods();
        //遍历方法
        for (Method method : methods) {
            if(method.isAnnotationPresent(MyTest.class)){
                   method.invoke(t);
            }
        }
    }
}

(四)、动态代理
一个对象,用来对被代理的行为额外作一些辅助工作

//实现接口
public interface skill {
    void jump();
    void sing();
}

//创建类,继承接口
public class Star implements skill{
    //创建对象(明星)
    private String name;
    public Star(String name) {
        this.name = name;
    }
    @Override
    public void jump() {
        System.out.println("跳舞");
    }
    @Override
    public void sing() {
        System.out.println("唱歌");
    }
}

//实现代理对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class StarAgenProxy {
    //设计方法返回一个明星对象的代理对象
    public static skill getProxy(Star obj){
        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 正在使用的方法对象 arg 代表这个方法的参数
                        Object rs = method.invoke(obj,args);//动作进行
                        System.out.println("结束");
                        return rs;
                    }
                });
    }
}
//运行
public class Test {
    public static void main(String[] args) {
        Star star = new Star("美波");
        //找代理对象
        skill s2 = StarAgenProxy.getProxy(star);
        star.jump();
        star.sing();
    }
}

1.实现动态代理的基本步骤

  • 必须存在接口
  • 被代理对象需要实现接口
  • 使用Proxy类提供的方法的对象的代理对象

2.动态代理小项目(表明优势)

//定义接口
public interface UserService {
    String lcgin(String loginName,String passWord);
    void deleteUsers();
    String selectUsers();
}
//继承接口并实现类
public class UserServiceImpl implements UserService{
    @Override
    public String lcgin(String loginName, String passWord) {
        String rs = "登录名和密码错误!";
        if ("admin".equals(loginName) && "123456".equals(passWord)){
            rs = "登录成功";
        }
        return rs;
    }
    @Override
    public void deleteUsers() {
        System.out.println("正在删除用户数据中");
        try {
            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;
    }
}
//类的代理
//泛型的复用
//public static <V> V getProxy(V cbj){
//    return (V) Proxy.newProxyInstance(cbj.getClass().getClassLoader(), //cbj.getClass().getInterfaces(), new InvocationHandler() 
public class ProxyUtil {
    //通过一个静态方法,为用户业务对象返回一个代理对象
    public static UserService getProxy(UserService cbj){
        return (UserService) Proxy.newProxyInstance(cbj.getClass().getClassLoader(), cbj.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                long startTime = System.currentTimeMillis();
                //真正触发对象的行为执行
                Object rs = method.invoke(cbj,args);
                long endTime = System.currentTimeMillis();
                System.out.println("deleteUsers耗时:" + (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.lcgin("admin","123456"));
        System.out.println(userService.selectUsers());
        userService.deleteUsers();
    }
}
//类再加方法也能一起运行,提高复用性

3.动态代理的使用优点

  • 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。
  • 可以为被代理对象的所有方法做代理。
  • 可以在不改变方法源码的情况下,实现对方法功能的增强。
  • 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

符气满满

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值