Java高级技术

目录

1.单元测试

2.反射

2.1 认识反射、获取类

2.2 获取类中的成分,并对其进行操作

2.3 反射的作用

3.注解

3.1 概述、自定义注解

3.2 元注解

 3.3 注解的解析

 3.4 注解的应用场景

4.动态代理

4.1什么是代理?

4.2 动态代理解决实际问题


1.单元测试

/**
 * 字符串工具类
 */
public class StringUtil {
    public static void printNumber(String name){
        if(name == null){
            System.out.println("参数不能为null");
            return;
        }
        System.out.println("名字长度是:" + name.length());
    }

    /**
     * 求字符串的最大索引
     */
    public static int getMaxIndex(String data){
        if(data == null ||  "".equals(data)) {
            return -1;
        }
        return data.length() -1;
    }
}
 @Test
    public void testPrintNumber(){
        StringUtil.printNumber(null);
        StringUtil.printNumber("");
        StringUtil.printNumber("admin");//5
    }

    @Test
    public void testGetMaxIndex(){
//        System.out.println(StringUtil.getMaxIndex(null));
//        System.out.println(StringUtil.getMaxIndex(""));
//        System.out.println(StringUtil.getMaxIndex("admin"));
        // 断言:预言。
        int i1 = StringUtil.getMaxIndex(null);
        //public static void assertEquals(String message, long expected, long actual)
        Assert.assertEquals("null测试失败!", -1, i1);

        int i2 = StringUtil.getMaxIndex("");
        Assert.assertEquals("空字符串测试失败!", -1, i2);

        int i3 = StringUtil.getMaxIndex("admin");
        Assert.assertEquals("admin测试失败!", 4, i3);

        System.out.println("测试通过!");
    }

JUnit单元测试的实现过程是什么样的?

  •  必须导入Junit框架的jar包
  • 定义的测试方法必须是无参数返回值,且公开的方法
  • 测试方法使用@Test注解标记

JUnit测试某个方法,测试全部方法怎么处理?成功的标志是什么?

  • 测试某个方法直接右键该方法启动测试
  • 测试全部方法,可以选择类或者模块启动
  • 红色失败,绿色通过

2.反射

2.1 认识反射、获取类

 

public class Student {
    private String name;
    private int age;
    private char sex;
    private double height;
    private String hobby;

    public Student() {
    }

    public Student(String name, int age, char sex, double height, String hobby) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
        this.hobby = hobby;
    }

    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 char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }
}
package com.itheima.d2_reflect;

/**
 * 目标:获取Class对象。
 */
public class Test1Class {
    public static void main(String[] args) throws Exception {
        // 目标:反射第一步:获取Class对象。
        // 1、方式一:类名.class
        Class c1 = Student.class;
        System.out.println(c1);

        // 2、方式二:Class.forName(全类名)
        Class c2 = Class.forName("com.itheima.d2_reflect.Student");
        System.out.println(c2);

        // 3、方式三:对象.getClass();
        Student s1 = new Student();
        Class c3 = s1.getClass();
        System.out.println(c3);

        System.out.println(c1 == c2);// true
        System.out.println(c2 == c3);// true
    }
}

2.2 获取类中的成分,并对其进行操作

package com.itheima.d2_reflect;

public class Cat {
    public static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;
    private String hobby;

    public Cat() {
        System.out.println("无参数构造器执行了~~");
    }

    private Cat(String name) {
        System.out.println("一个参数构造器执行了~~");
        this.name = name;
    }

    public Cat(String name, int age) {
        System.out.println("有参数构造器执行了~~");
        this.name = name;
        this.age = age;
    }

    public void run() {
        System.out.println("🐱跑的贼快~~");
    }

    private void eat() {
        System.out.println("🐱爱吃猫粮~");
    }

    public String eat(String name) {
        return "🐱最爱吃:" + name;
    }

    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 getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", hobby='" + hobby + '\'' +
                '}';
    }
}
package com.itheima.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 目标:掌握获取类的构造器,并对其进行操作。
 */
public class Test2Constructor {

    @Test
    public void getClassInfo(){
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        System.out.println(c.getName());//类名的全类名 com.itheima.d2_reflect.Cat
        System.out.println(c.getSimpleName());//类名 Cat
    }

    @Test
    public void getConstructorInfo() throws Exception {
        //目标:获取类的构造器对象并对其进行操作
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        // 2、获取类的全部构造器
        // Constructor[] constructors = c.getConstructors(); // 只能拿public的
        Constructor[] cons = c.getDeclaredConstructors(); // 存在即可拿
        // 3、遍历构造器
        for (Constructor con : cons) {
            System.out.println(con.getName() + " ===> " + con.getParameterCount());
        }
        //4.获取单个构造器
        Constructor con = c.getDeclaredConstructor();//无参数构造器
        System.out.println(con.getName() + " ===> " + con.getParameterCount());

        Constructor con2 = c.getDeclaredConstructor(String.class, int.class);//带参数构造器
        System.out.println(con2.getName() + " ===> " + con2.getParameterCount());

        //5.获取构造器的作用依然是创建对象:创建对象。
        //暴力反射:暴力反射可以访问私有的构造器、方法、属性
        con.setAccessible(true);//绕过访问权限,直接访问!临时攻破权限
        Cat cat = (Cat) con.newInstance();//需要强转
        System.out.println(cat);

        Cat tom = (Cat)con2.newInstance("Tom", 5);
        System.out.println(tom);
    }

    //获取类的成员变量对象并对其进行操作
    @Test
    public void getFieldInfo() throws Exception {
        //目标:获取类的成员变量对象并对其进行操作
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        //2.获取所有成员变量对象
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getType() + " ===> " + field.getName());
        }
        //3.获取某个成员变量对象
        Field fname = c.getDeclaredField("hobby");
        System.out.println(fname.getType() + " ===> " + fname.getName());

        //4.获取成员变量的目的:取值和赋值。
        Cat cat = new Cat("泰迪",3);
        fname.setAccessible(true);//绕过访问权限,直接访问!临时攻破权限
        fname.set(cat,"社交");//hobby是私有的,所以需要暴力反射才能访问
        System.out.println(cat);

        String hobby = (String) fname.get(cat);//cat.getHobby()作用相同
        System.out.println(hobby);
    }

    //获取类的成员方法对象并对其进行操作
    @Test
    public void getMethodInfo() throws Exception {
        //目标:获取类的成员方法对象并对其进行操作
        // 1、反射第一步:必须先得到这个类的Class对象
        Class c = Cat.class;
        //2.获取所有成员方法对象
        Method[] methods = c.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getReturnType() + " ===> " + method.getName() + " " + method.getParameterCount());
        }
        //3.获取某个成员方法对象
        Method eat = c.getDeclaredMethod("eat");//获取无参数的eat方法
        System.out.println(eat.getReturnType() + " ===> " + eat.getName() + " " + eat.getParameterCount());
        //4.获取带参数的成员方法对象
        Method eat2 = c.getDeclaredMethod("eat", String.class);
        System.out.println(eat2.getReturnType() + " ===> " + eat2.getName() + " " + eat2.getParameterCount());

        //5.获取成员方法的目的:执行它!
        Cat cat = new Cat("Tom",5);
        eat.setAccessible(true);//暴力反射
        Object rs =eat.invoke(cat);//唤醒对象cat的eat方法执行,相当于cat.eat();
        System.out.println(rs);//null

        Object rs2 = eat2.invoke(cat,"牛肉");//唤醒对象cat的带String参eat方法执行,相当于cat.eat("牛肉");
        System.out.println(rs2);
    }
}

2.3 反射的作用

package com.itheima.d2_reflect;

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;

public class SaveObjectFrame {
    //保存任意对象的静态方法
    public static void saveObject(Object obj) throws Exception {
        PrintStream ps = new PrintStream(new FileOutputStream("day14-" +
                "junit-reflect-annotation-proxy/src/obj2.txt",true));
        //obj可能是老师,学生,猫
        //只有反射可以知道对象有多少个字段
        //1.获取Class对象
        Class c = obj.getClass();
        String simpleName = c.getSimpleName();
        ps.println("==================" + simpleName + "====================");
        //2.获取Class对象的所有字段
        Field[] fields = c.getDeclaredFields();
        //3.遍历字段
        for (Field field : fields) {
            //4.获取字段的值
            //4.1 获取字段名称
            String fieldName = field.getName();
            //4.2 获取字段的值
            field.setAccessible(true);//暴力反射
            Object fieldValue = field.get(obj) + "";
            //5.打印到文件中去
            ps.println(fieldName + "=" + fieldValue);
        }
        ps.close();
    }
}
package com.itheima.d2_reflect;

/**
 * 目标:使用反射技术:设计一个保存对象的简易版框架。
 */
public class Test5Frame {
    public static void main(String[] args) throws Exception {
        //目标:搞清楚反射的应用:做框架的通用技术
        Cat c1 = new Cat("加菲", 3);
        // 需求:把任意对象的字段名和其对应的值等信息,保存到文件中去。
        SaveObjectFrame.saveObject(c1);
        //创建学生对象
        Student s1 = new Student("黑马吴彦祖", 45, '男', 185.3, "蓝球,冰球,阅读");
        SaveObjectFrame.saveObject(s1);
        //创建老师对象
        Teacher t1 = new Teacher("小王", 35, "打篮球", 5000, "JAVA班",'男',"屁股");
        SaveObjectFrame.saveObject(t1);

    }
}

3.注解

3.1 概述、自定义注解

package com.itheima.d3_annotation;
// 自定义注解
public @interface MyTest {
    String name();
    double money() default 100;
    String[] authors();
}
package com.itheima.d3_annotation;

public @interface MyTest2 {
    String value();//特殊属性,在使用时如果只有一个value属性,那么在使用时value可以省略
    int age() default 70;//有默认值可以不写
}
package com.itheima.d3_annotation;
@MyTest(name = "从入门到跑路", money = 9.9, authors = {"阿猫", "阿狗"})
//@MyTest2(value = "删除")
//@MyTest2(value = "删除", age = 23)
@MyTest2("删除")
public class AnnotationDemo1 {

    @MyTest(name = "从入门到跑路2", authors = {"阿猫2", "阿狗2"})
    private String name;

    @MyTest(name = "从入门到跑路", authors = {"阿猫", "阿狗"})
    public static void main(String[] args) {
        // 目标:掌握注解的使用。
        @MyTest(name = "从入门到跑路3", authors = {"阿猫3", "阿狗3"})
        int age = 12;
    }
}

3.2 元注解

package com.itheima.d3_annotation;

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

@Target({ElementType.METHOD,ElementType.TYPE}) // 声明注解的范围,只能注解方法和类
@Retention(RetentionPolicy.RUNTIME) // 这个注解始终活着
public @interface MyTest3 {
}
package com.itheima.d3_annotation;

@MyTest3
public class AnnotationDemo2 {

//    @MyTest3
    private String name;

//    @MyTest3
    public AnnotationDemo2(){
    }

    @MyTest3
    public void run(){

    }

    @MyTest3
    public static void main(String[] args) {
        // 目标:元注解
    }
}

 3.3 注解的解析

package com.itheima.d3_annotation;

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

@Target({ElementType.TYPE, ElementType.METHOD})// 声明注解的范围,只能注解方法和类
@Retention(RetentionPolicy.RUNTIME)// 这个注解始终活着
public @interface MyTest4 {
    String value();
    double aaa() default 100;
    String[] bbb();
}

 3.4 注解的应用场景

package com.itheima.d3_annotation;

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

@Target(ElementType.METHOD)// 声明注解的范围,只能注解方法
@Retention(RetentionPolicy.RUNTIME)// 这个注解始终活着
public @interface TestDlei {
    int value() default 1;
}
package com.itheima.d3_annotation;

import java.lang.reflect.Method;

public class AnnotationDemo4 {
    // 目标:搞清楚注解的应用场景:模拟junit框架。有TestDlei注解的方法,就执行这个方法。

    //测试方法:public 无参 无返回值
    public void test1() {
        System.out.println("===========test1=======");
    }

    @TestDlei
    public void test2() {
        System.out.println("===========test2=======");
    }

    public void test3() {
        System.out.println("===========test3=======");
    }

    @TestDlei(2)// value() = 2
    public void test4() {
        System.out.println("===========test4=======");
    }

    public static void main(String[] args) throws Exception {
        AnnotationDemo4 t = new AnnotationDemo4();
        //1.获取类对象
        // 有注解的跑他,没有注解的不跑他
        Class c = AnnotationDemo4.class;
        //2.获取所有方法
        Method[] methods = c.getDeclaredMethods();
        //3.遍历所有方法,判断方法上是否有注解
        for (Method method : methods) {
            // 4.判断这个方法上是否陈列了注解,是就跑
            if(method.isAnnotationPresent(TestDlei.class)){
                //获取到这个方法的注解
                TestDlei testDlei = method.getDeclaredAnnotation(TestDlei.class);
                int value = testDlei.value();
               //5.有就执行这个method方法
                for (int i = 0; i < value; i++) {
                    method.invoke(t);//invoke(Object obj, Object... args)必须用对象调用
                }
            }
        }
    }
}

4.动态代理

4.1什么是代理?

 4.2 动态代理解决实际问题

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyUtil {
    public static <T> T createProxy(T obj) {
        T proxy = (T) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader()
                , obj.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long startTime = System.currentTimeMillis();

                        // 真正走业务对象的方法
                        Object result = method.invoke(obj, args);

                        long end = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时:" + (end - startTime) / 1000.0);

                        return result;
                    }
                });
        return proxy;
    }
}

 可以把这个代理类改为泛型类,这样无论哪个接口的实现类都可以实现代理类想要实现的功能,如计算运行速度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值