反射、注解

127 阅读16分钟

反射、注解

Java基础学习---点击进入学习

640 (1).jpg

注解和反射

1. 注解

注解:注解是JDK1.5引入的新特性 注解本质还是一个Java类 使用@interface修饰 替代class关键字

注解的作用:简化Java复杂的开发

Java项目开发历程

早期:使用SSH(Spring Struts2 Hibernate) 每个框架都会有对应的配置文件

Java项目不仅有大量的.java文件 还有非常多的配置文件(.xml .yml .properties)

项目结构非常复杂,所带来的问题:项目可维护性 、 扩展性降低

后来:SUN公司在JDK1.5引入了注解新特性 最初的梦想:使用注解替代配置文件,实现零配置文件

一个注解就是一个或者两个单词 一个注解可以替代原来的几行 几十行 甚至是上百行的配置文件

现在:注解 + 配置文件 结合起来使用 SSM(Spring SpringMVC MyBatis) 使用注解和配置文件

SpringBoot 一个注解可以代替原来几百行的配置文件

回顾我们之前使用过的注解:

@Override @FunctionalInterface @Deprecated @SuppressWarnings("all")

对比以上注解发现,不同的注解可以添加在不同的位置 ,有不同的作用

有的注解只有单词 有的注解还需要小括号中写值

这些效果如何实现呢?

通过自定义注解 使用元注解实现

约定大与配置:是一种思想,很多功能,框架,有默认实现,可以满足大多数的开发场景,开箱即用。简化复杂的配置的过程。

元注解:修饰注解的注解 约定大于配置

@Target 用于规定注解可以书写的位置 默认不写表示可以添加在任何位置

​ TYPE 表示可以添加在类上

​ METHOD 表示可以添加在方法上

​ FIELD 表示可以添加在字段上

​ PARAMETER 表示可以添加在参数上

​ CONSTRUCTOR 表示可以添加在构造器上

​ LOCAL_VARIABLE 表示可以添加在局部变量上

@Retention 用于规定注解的生效阶段 默认不写表示在class文件中生效

​ SOURCE 表示在源代码中生效

​ CLASS 表示在二进制文件中生效

​ RUNTIME 表示在运行期间生效

@Documented 被此注解修饰的注解可以生成在帮助文档中

@Inherited 被此注解修饰的注解可以被子类继承

注解的属性和赋值

属性支持的类型:八种基本数据类型、枚举 、String、Class 及其对应的数组类型 共22种数据类型

赋值:

注解中每个属性都必须赋值,除非使用default关键字给属性添加默认值 格式:属性名 = 属性值

如果注解中只有一个属性并且属性名为value,可以直接写值,其他的情况都必须书写为 属性名 = 属性值

如果是数组类型 单个元素直接赋值 多个元素加上大括号即可


public @interface An1 {
   byte b1();
   byte [] b2();

   short s1();
   short [] s2();

   int i1();
   int [] i2();

   long l1();
   long [] l2();

   float f1();
   float [] f2();

   double d1();
   double [] d2();

   boolean bl1();
   boolean [] bl2();

   char ch1();
   char [] ch2();

   String str1();
   String []str2();

   Class clazz();
   Class [] clas();


   Week day();
   Week [] days();

   enum Week{
       MON,TUE,WED
   }



}



public @interface An2 {
    String field1();
    String field2();

    int num() default 123;
}


/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 10:35
 */
public class TestAn2 {
    @An2(field1 = "abc",field2 = "hello 赵四")
    private int a;
}


public @interface An3 {
    String value();
}


/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 10:37
 */
@An3("hello world")
public class TestAn3 {
    @An3("123 abc")
    int a ;



}

2.JUnit框架

JUnit是一个单元测试框架 Java Unit 框架是一个半成品 / 成品 别人写好的一系列功能的一个组合

我们可以直接引入别人写好的代码 供我们使用

引入JUnit两种方式

方式1:在本项目下右键new director 取名为lib 将JUnit相关的jar文件复制到此目录

右键 add as library 表示添加到资源库

方式2:在需要测试的方法上直接书写注解 使用idea的自动提示帮我们添加JUnit相关的jar文件 依赖

JUnit是一个单元测试框架 Java Unit

@Test 添加在实例方法上 表示此方法可以直接运行

@Before 每个使用@Test注解修饰的方法执行之前都会执行一次

@After 每个使用@After注解修饰的方法执行之后都会执行一次

@BeforeClass 本类中的方法执行之前只执行一次 只能添加在静态方法上

@AfterClass 本类中的方法执行之后只执行一次 只能添加在静态方法上


import org.junit.*;

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 11:02
 *  JUnit是一个单元测试框架 Java Unit
 *      @Test 添加在实例方法上 表示此方法可以直接运行
 *      @Before 每个使用@Test注解修饰的方法执行之前都会执行一次
 *      @After 每个使用@After注解修饰的方法执行之后都会执行一次
 *      @BeforeClass 本类中的方法执行之前只执行一次 只能添加在静态方法上
 *      @AfterClass  本类中的方法执行之后只执行一次  只能添加在静态方法上
 *
 *
 */
public class TestJunit {
    @BeforeClass
    public static void beforeClass(){
        System.out.println("执行各种初始化操作……");
    }

    @AfterClass
    public static void afterClass(){
        System.out.println("执行各种关闭资源操作");
    }


    @Before
    public void before(){
        System.out.println("获取数据库连接");
    }

    @After
    public void after(){
        System.out.println("释放数据库连接");
    }

    @Test
    public void add(){

        System.out.println("执行添加操作");

    }

    @Test
    public void del(){
        System.out.println("执行删除操作");
    }


    @Test
    public void modify(){
        System.out.println("执行修改操作");
    }

    @Test
    public void get(){
        System.out.println("执行查询操作");
    }

}

3.反射

反射:在程序运行期间,通过全限定名,动态的获取某个类的信息(属性、方法、构造、注解),并且访问。这个过程称之为反射。

通俗的理解:不通过new对象的方式,依然可以实现之前new对象才能实现的操作。

未来我们使用Spring框架 将不再通过new的方式创建对象。而是通过Spring框架的IOC技术创建对象

IOC技术创建对象有两个问题?

1.如何创建对象?

使用工厂模式

2.创建哪个对象呢?

需要我们调用对应的方法 传入对应的参数 这个参数就是全限定名 通过反射技术创建对象

反射的体现: IDE自动提示功能 拍X光片 镜子/倒车镜

万物皆对象:类也是一个对象 属性、方法、构造器、注解 也是一个对象

java.lang.Class 所有的类都属于此类对象

java.lang.reflect.Field 所有的属性都属于此类对象

java.lang.reflect.Method 所有的方法都属于此类对象

java.lang.reflect.Constructor 所有的构造器都属于此类对象

java.lang.reflect.Annotation 所有的注解都属于此类对象

获取Class对象的四种方式

1.类名.class

2.对象名.getClass()方法 Object类中的方法

3.Class.forName(权限名) 通过Class类中的静态方法 通过反射方式获取

4.通过类加载器的方式获取

获取Class对象的四种方式

1.类名.class

2.对象名.getClass()方法 Object类中的方法

3.Class.forName(权限名) 通过Class类中的静态方法 通过反射方式获取

4.通过类加载器的方式获取


import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 14:17
 *  反射:在程序运行期间,通过全限定名,动态的获取某个类的信息(属性、方法、构造、注解),并且访问。这个过程称之为反射。
 *
 *  通俗的理解:不通过new对象的方式,依然可以实现之前new对象才能实现的操作。
 *
 *  未来我们使用Spring框架 将不再通过new的方式创建对象。而是通过Spring框架的IOC技术创建对象
 *  IOC技术创建对象有两个问题?
 *      1.如何创建对象?
 *      使用工厂模式
 *      2.创建哪个对象呢?
 *      需要我们调用对应的方法 传入对应的参数 这个参数就是全限定名 通过反射技术创建对象
 *
 *  反射的体现: IDE自动提示功能   拍X光片  镜子/倒车镜
 *
 *  万物皆对象:类也是一个对象 属性、方法、构造器、注解 也是一个对象
 *
 *      java.lang.Class 所有的类都属于此类对象
 *      java.lang.reflect.Field 所有的属性都属于此类对象
 *      java.lang.reflect.Method 所有的方法都属于此类对象
 *      java.lang.reflect.Constructor 所有的构造器都属于此类对象
 *      java.lang.reflect.Annotation 所有的注解都属于此类对象
 *
 *
 *  获取Class对象的四种方式
 *      1.类名.class
 *      2.对象名.getClass()方法  Object类中的方法
 *      3.Class.forName(权限名) 通过Class类中的静态方法 通过反射方式获取
 *      4.通过类加载器的方式获取
 *
 */
public class Note {

    public static void main(String[] args) throws ClassNotFoundException {
        //  1.类名.class
        Class<Note> noteClass1 = Note.class;


        Note note = new Note();
        // 2.对象名.getClass()方法  Object类中的方法
        Class<? extends Note> aClass = note.getClass();


        // 3.Class.forName(权限名) 通过Class类中的静态方法 通过反射方式获取
        Class<?> aClass1 = Class.forName("com.atguigu.test5.Note");



    }
}

4.反射完善工厂模式

之前书写的工厂模式,不符合开闭原则,如果有更多的子类对象,还需要修改工厂的部分代码。使用反射可以解决这个问题。


/**
 * @author WHD
 * @description TODO
 * @date 2024/1/17 15:45
 */
public abstract class Vehicle {
    public abstract String getVehicleInfo();
}

class Buick extends  Vehicle{
    @Override
    public String getVehicleInfo() {
        return "君威";
    }
}

class Audi extends Vehicle{
    @Override
    public String getVehicleInfo() {
        return "A6";
    }
}
class Benz extends Vehicle{

    @Override
    public String getVehicleInfo() {
        return "S500";
    }
}

class BMW extends Vehicle{
    @Override
    public String getVehicleInfo() {
        return "740";
    }
}


/**
 * @author WHD
 * @description TODO
 * @date 2024/1/17 15:55
 *  汽车工厂
 */
public class VehicleFactory {
    public static Vehicle buildCar(String car){
        if(car.equalsIgnoreCase("audi")){
            return new Audi();
        }else if(car.equalsIgnoreCase("benz")){
            return new Benz();
        }else if(car.equalsIgnoreCase("bmw")){
            return new BMW();
        }
        return null;
    }

    public static Vehicle buildCarWithReflect(String subClassName){
        Vehicle vehicle = null;
        try {
            Class<?> subClass = Class.forName(subClassName);
            Object obj = subClass.newInstance();
            if(obj instanceof Vehicle){
                vehicle = (Vehicle) obj;
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return  vehicle;
    }

    public static void main(String[] args) {
//        System.out.println(VehicleFactory.buildCar("buick").getVehicleInfo());


        System.out.println(VehicleFactory.buildCarWithReflect("com.atguigu.test7.Audi").getVehicleInfo());
    }
}

5. 反射获取属性

通过反射获取所有public修饰属性

Field getField(String fieldName) 根据名称获取单个public修饰的属性

Field [] getFields() 获取所有public修饰的属性

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:17
 */
public class Student {
    private String name;
    int age;
    protected char sex;
    public double height;
    public double weight;
    public String address;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", height=" + height +
                ", weight=" + weight +
                ", address='" + address + '\'' +
                '}';
    }
}


import java.lang.reflect.Field;

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:18
 *  通过反射获取所有public修饰属性
 *
 *  Field getField(String fieldName) 根据名称获取单个public修饰的属性
 *  Field [] getFields() 获取所有public修饰的属性
 *
 */
public class TestField1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        Class<?> stuClass = Class.forName("com.atguigu.test7.Student");

        Field[] fields = stuClass.getFields();

        for (Field field : fields) {
            System.out.println(field.getName() + "----" + field.getType());
        }

        System.out.println("---------------------------------------");

        Field field1 = stuClass.getField("address");

        Object obj = stuClass.newInstance();

        field1.set(obj, "深圳");

        System.out.println(field1.get(obj));

        System.out.println("obj = " + obj);


    }
}

Field getDeclaredField(String name) 根据属性名获取单个任何修饰符修饰的属性对象

Field [] getDeclaredFields() 获取所有任何修饰符修饰的属性对象


import java.lang.reflect.Field;

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:30
 *  Field getDeclaredField(String name) 根据属性名获取单个任何修饰符修饰的属性对象
 *  Field [] getDeclaredFields()  获取所有任何修饰符修饰的属性对象
 */
public class TestDeclaredField1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {
        Class<?> stuClass = Class.forName("com.atguigu.test7.Student");

        Field[] declaredFields = stuClass.getDeclaredFields();

        for (Field declaredField : declaredFields) {
            System.out.println(declaredField.getName() + "===" + declaredField.getType());
        }

        System.out.println("--------------------------------------");

        Field nameField = stuClass.getDeclaredField("name");

        nameField.setAccessible(true); // 忽略JVM的安全检查 即可以访问

        Object obj = stuClass.newInstance();

        nameField.set(obj,"赵四");

        System.out.println(nameField.get(obj));

        System.out.println("obj = " + obj);


    }
}

6.反射获取方法

Method [] getMethods() 获取所有public修饰的 以及 继承自 父类的方法

Method getMethod(String name, Class<?>... parameterTypes) 根据方法名和形参列表 获取到单个公开的或者继承自父类的方法


/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:17
 */
public class Student {
    private void m1(){
        System.out.println("Student类无参m1方法");
    }
    private int m1(int a){
        System.out.println("Student类有参:int类型  m1方法");
        return a;
    }
    void m2(){
        System.out.println("Student类无参m2方法");
    }
    protected void m3(){
        System.out.println("Student类无参m3方法");
    }
    public void m4(){
        System.out.println("Student类无参m4方法");
    }
    public void m5(){
        System.out.println("Student类无参m5方法");
    }

    public void m5(double a,String b){
        System.out.println("Student类有参double  String m5方法");
    }

    public void m5(String b,double a){
        System.out.println("Student类有参String  double m5方法");
    }


}


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

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:42
 *  Method [] getMethods() 获取所有public修饰的 以及 继承自 父类的方法
 *  Method getMethod(String name, Class<?>... parameterTypes) 根据方法名和形参列表 获取到单个公开的或者继承自父类的方法
 */
public class TestMethod {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Class<?> stuClass = Class.forName("com.atguigu.test8.Student");

        Method[] methods = stuClass.getMethods();

        for (Method method : methods) {
            System.out.println(method.getName() + "参数个数:" +  method.getParameterCount());
        }

        System.out.println("---------------------------------------");

        Method m4 = stuClass.getMethod("m4");

        Object obj = stuClass.newInstance();

        m4.invoke(obj);

        System.out.println("---------------------------------------");

        Method m5 = stuClass.getMethod("m5", double.class, String.class);

        m5.invoke(obj, 100,"hello world");

        Method newM5 = stuClass.getMethod("m5",  String.class,double.class);

        newM5.invoke(obj, "hello world",200);
    }
}

Method [] getDeclaredMethods() 获取本类已定义的任何修饰符修饰的方法 (不包含继承自父类)

Method getDeclaredMethod(String name, 类<?>... parameterTypes) 根据方法名称和形参列表获取到本类中

已定义的任何修饰符修饰的方法 (不包含继承自父类)


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

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:51
 *  Method [] getDeclaredMethods() 获取本类已定义的任何修饰符修饰的方法 (不包含继承自父类)
 *  Method getDeclaredMethod(String name, 类<?>... parameterTypes) 根据方法名称和形参列表获取到本类中
 *  已定义的任何修饰符修饰的方法 (不包含继承自父类)
 */
public class TestDeclaredMethod {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        Class<?> stuClass = Class.forName("com.atguigu.test8.Student");

        Method[] declaredMethods = stuClass.getDeclaredMethods();

        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod.getName() + "参数个数:" + declaredMethod.getParameterCount());
        }

        System.out.println("----------------------------------------------");


        Method m1NoParam = stuClass.getDeclaredMethod("m1");

        m1NoParam.setAccessible(true); // 抑制JVM安全检查 即可以访问

        Object obj = stuClass.newInstance();

        m1NoParam.invoke(obj);

        System.out.println("----------------------------------------------");

        Method m1IntParam = stuClass.getDeclaredMethod("m1", int.class);

        m1IntParam.setAccessible(true);

        Object invoke = m1IntParam.invoke(obj, 100);

        System.out.println("invoke = " + invoke);


    }
}

7. 反射获取构造器

Constructor getConstructor(Class<?>... parameterTypes) 根据参数列表获取到一个public修饰的构造器对象

Constructor [] getConstructors() 获取本类中所有的public修饰的构造器对象


/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:17
 */
public class Student {
    private String name;
    int age;
    protected char sex;
    public double height;
    public double weight;
    public String address;


    private Student() {
    }

    private Student(double weight) {
        this.weight = weight;
    }

     Student(String name) {
        this.name = name;
    }

    protected Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

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

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", height=" + height +
                ", weight=" + weight +
                ", address='" + address + '\'' +
                '}';
    }
}


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

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:57
 *  Constructor<T>  getConstructor(Class<?>... parameterTypes) 根据参数列表获取到一个public修饰的构造器对象
 *  Constructor<T> []   getConstructors() 获取本类中所有的public修饰的构造器对象
 */
public class TestConstructor {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> stuClass = Class.forName("com.atguigu.test9.Student");


        Constructor<?>[] constructors = stuClass.getConstructors();

        for (Constructor<?> constructor : constructors) {

            System.out.println(constructor.getName() + "参数列表:" + constructor.getParameterCount());
        }

        System.out.println("---------------------------------------------------");

        Constructor<?> constructor = stuClass.getConstructor(String.class, int.class, char.class);

        Object obj1 = constructor.newInstance("赵穗", 100, '男');

        if(obj1 instanceof  Student){
            Student stu = (Student) obj1;
            System.out.println("stu = " + stu);
        }




    }
}

Constructor getDeclaredConstructor(Class<?>... parameterTypes) 根据参数列表获取任何修饰符修饰的单个构造器

Constructor<?>[] getDeclaredConstructors() 获取本类中所有已定义的任何修饰符修饰的构造器

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

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/27 15:57
 *  Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 根据参数列表获取任何修饰符修饰的单个构造器
 *  Constructor<?>[] getDeclaredConstructors() 获取本类中所有已定义的任何修饰符修饰的构造器
 *
 */
public class TestDeclaredConstructor {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> stuClass = Class.forName("com.atguigu.test9.Student");

        Constructor<?>[] declaredConstructors = stuClass.getDeclaredConstructors();

        for (Constructor<?> declaredConstructor : declaredConstructors) {
            System.out.println(declaredConstructor.getName() + "参数个数:" + declaredConstructor.getParameterCount());
        }
        System.out.println("---------------------------------------------");

        Constructor<?> declaredConstructor = stuClass.getDeclaredConstructor();

        declaredConstructor.setAccessible(true);

        Object obj1 = declaredConstructor.newInstance();

        if(obj1 instanceof  Student){
            Student stu1 = (Student) obj1;
            System.out.println("stu1 = " + stu1);
        }

        System.out.println("---------------------------------------------");

        Constructor<?> declaredConstructor1 = stuClass.getDeclaredConstructor(double.class);

        declaredConstructor1.setAccessible(true);

        Object obj2 = declaredConstructor1.newInstance(100);

        if(obj2 instanceof  Student){
            Student stu2 = (Student) obj2;
            System.out.println("stu2 = " + stu2);
        }


    }
}

9.类加载器

image.png

类加载器

1.类加载器的作用

加载类

2.如何获取类加载

通过Class类中的getClassLoader()方法

3.类加载器的分类

BootStrap ClassLoader 引导类加载器 底层由C++实现 在Java代码中 无法获取

负责加载:C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar

Extension ClassLoader 扩展类加载器

负责加载:C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext*.jar

Application ClassLoader 引用程序类加载器

负责加载:自定义的类

4.类加载的过程

5.双亲委派机制/模型

当类加载需要加载某个类 不会直接加载 而是先检查此类是否被加载过

如果没有加载器 则先委派为父类加载器加载 如果父类加载器可以加载 则直接加载

如果父加载器不能加载 则再向下 由子类加载器负责加载

6.双亲委派机制解决了什么问题?

使用这种机制避免了人为的书写和JDK完全同包同名的类 污染 入侵 JDK的源代码

7.通过ClassLoader获取Class对象

调用ClassLoader对象的loadClass()方法

类的加载过程

当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过如下三个步骤来对该类进行初始化。

①加载类(load) : 将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成

将class文件字节码内容加载到内存中,并将这些数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象。这个加载的过程需要类加载器参与。

②链接(link) : 将类的二进制数据合并到JRE中

验证:确保加载的类信息符合JVM规范,例如:以cafe开头,没有安全方面的问题

准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配(静态区)。

解析:将类、接口、字段和方法的符号引用转为直接引用。

③初始化(Initialize) : JVM负责对类进行初始化

执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。

当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。

虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。


import sun.net.spi.nameservice.dns.DNSNameService;

/**
 * @author WHD
 * @description TODO
 * @date 2024/1/29 10:08
 *  类加载器
 *
 *  1.类加载器的作用
 *      加载类
 *
 *  2.如何获取类加载
 *      通过Class类中的getClassLoader()方法
 *
 *  3.类加载器的分类
 *      BootStrap ClassLoader 引导类加载器 底层由C++实现 在Java代码中 无法获取
 *      负责加载:C:\Program Files\Java\jdk1.8.0_131\jre\lib\rt.jar
 *
 *      Extension ClassLoader 扩展类加载器
 *      负责加载:C:\Program Files\Java\jdk1.8.0_131\jre\lib\ext\*.jar
 *
 *      Application ClassLoader 引用程序类加载器
 *      负责加载:自定义的类
 *
 *  4.类加载的过程
 *
 *  5.双亲委派机制/模型
 *      当类加载需要加载某个类 不会直接加载 而是先检查此类是否被加载过
 *      如果没有加载器 则先委派为父类加载器加载 如果父类加载器可以加载 则直接加载
 *      如果父加载器不能加载  则再向下 由子类加载器负责加载
 *
 *  6.双亲委派机制解决了什么问题?
 *      使用这种机制避免了人为的书写和JDK完全同包同名的类  污染 入侵 JDK的源代码
 *
 *  7.通过ClassLoader获取Class对象
 *      调用ClassLoader对象的loadClass()方法
 *
 */
public class TestClassLoader {
    public static void main(String[] args) throws ClassNotFoundException {
        ClassLoader classLoader1 = Object.class.getClassLoader();

        Class<?> aClass = classLoader1.loadClass("com.atguigu.test3.TestClassLoader");

        System.out.println(classLoader1);

        ClassLoader classLoader2 = DNSNameService.class.getClassLoader();

        System.out.println(classLoader2);

        ClassLoader classLoader3 = TestClassLoader.class.getClassLoader();

        System.out.println(classLoader3);

        System.out.println("----------------------------------------------------------");

        System.out.println(classLoader3.getParent());
        System.out.println(classLoader3.getParent().getParent());


    }
}