Loading

JAVASE进阶day15(单元测试,反射,类加载器)

单元测试

1.为什么使用单元测试

为了替代古老僵硬的main方法来进行优雅的代码的测试,写的每个方法都能独立运行

2.JUnit

特点

使用流程

常用的三个注解

package com.lu.day15;

import org.junit.After;
import org.junit.Before;

import java.util.ArrayList;
import java.util.stream.Stream;

public class Test {
    private ArrayList<Integer> list = new ArrayList<>();
    //单元测试底层是反射+注解
    @org.junit.Test
    public void test(){
        Stream<Integer> integerStream = list.stream().filter(t -> t > 2);
        integerStream.forEach(System.out::println);
    }

    @Before
    public void test1(){
        System.out.println("执行开始");
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
    }

    @After
    public void test2(){
        System.out.println("执行结束");
    }
}

类加载器 

1.什么是类加载器

将编译好的.class文件,加载到内存当中

2.类加载的时机

什么时候用什么时候加载

3.类加载过程(典型面试题)

静态代码块和静态变量在类的加载阶段就已经赋值了,所有不能被非静态的变量或成员方法调用

4. 类加载器的分类

5.双亲委派模型 (面试题)

为了解决自定义类名和jdk类名重复

每个类加载器都很懒,加载类时都先让父加载器去尝试加载,父加载器加载不了时自己才去加载。 

6.类加载器中的一些常用方法

package com.lu.day15;

import com.lu.day07.setdome.Teacher;

public class Test {
    public static void main(String[] args) {
        Class<Teacher> teacherClass = Teacher.class;
        //获取系统类加载器
        ClassLoader classLoader = teacherClass.getClassLoader();
        //获取平台类加载器
        ClassLoader classLoader1 = ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);
        //获取不到启动类加载器
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);
    }
}

 反射

1.反射概念

动态获取类的任意属性和方法,以及动态调用对象的任意方法和属性就叫反射(反射忽视修饰符)

2.反射使用步骤

package com.lu.day15;

/**
 * 获取类对象的三种方式
 */
public class Test2 {
    public static void main(String[] args) {
        //类名.class
        Class<Dog> dogClass = Dog.class;
        //forName(权限定名)
        try {
            Class<?> aClass = Class.forName("com.lu.day15.Dog");
            System.out.println(dogClass==aClass);//true
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }

        //对象.getClass
        Dog dog = new Dog();
        Class<? extends Dog> aClass = dog.getClass();
        System.out.println(dogClass==aClass);//true

    }
}

 3.反射的基本使用

凡是类里面有的都能获取

package com.lu.day15;

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

public class Test3 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<Dog> dogClass = Dog.class;
        //获取构造方法
        Constructor<Dog> declaredConstructor = dogClass.getDeclaredConstructor(String.class, int.class);
        //将构造方法设置为可访问(默认就是可访问)
        declaredConstructor.setAccessible(true);
        //创建实例
        Dog dog = declaredConstructor.newInstance("小黑", 2);
        System.out.println(dog);

        //利用反射获取方法并调用方法
        Class<? extends Dog> aClass = dog.getClass();
        Method show = aClass.getDeclaredMethod("show");
        show.setAccessible(true);
        show.invoke(dog);
    }
}

4.反射配合注解实现动态调用方法 

package com.lu.day15;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;

public class TestStudent {//调用注解是AutoRun的方法
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        Class<Student> studentClass = Student.class;
        Method[] methods = studentClass.getMethods();
        for (Method method : methods) {
            AutoRun annotation = method.getAnnotation(AutoRun.class);
            if (Objects.nonNull(annotation)){
                method.invoke(new Student());
            }
        }
    }
}
package com.lu.day15;

public class Student {
    @AutoRun
    public void show() {
        System.out.println("我是学生1");
    }
    public void show1() {
        System.out.println("我是学生2");
    }
    public void show2() {
        System.out.println("我是学生3");
    }
    public void show3() {
        System.out.println("我是学生4");
    }
    public void show4() {
        System.out.println("我是学生5");
    }

    @AutoRun
    public void show5() {
        System.out.println("我是学生6");
    }

}
package com.lu.day15;


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 AutoRun {
}

面试题

1.如何创建线程安全的单例模式

双重检查锁定(Double-Checked Locking)

双重检查锁定模式既实现了延迟加载,又保证了线程安全,同时避免了每次调用getInstance()都进行同步的开销。

public class Singleton {  
    private static volatile Singleton instance;  
  
    private Singleton() {}  
  
    public static Singleton getInstance() {  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  
}

懒汉式(线程安全,但效率低)

通过在getInstance()方法上添加synchronized关键字来保证线程安全,但这样会导致每次调用该方法时都进行线程锁定,效率较低。

public class Singleton {  
    private static Singleton instance;  
  
    private Singleton() {}  
  
    public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

posted @ 2024-07-23 18:12  LL。。。  阅读(36)  评论(0)    收藏  举报  来源