Ykuri98
文章46
标签14
分类1
学习总结(2022.04.19-2022.04.24)

学习总结(2022.04.19-2022.04.24)

类加载器

分类:

  1. Bootstrap ClassLoader 根类加载器,负责核心类的加载
  2. Extension ClassLoader 扩展类加载器,负责扩展目录中jar包的加载
  3. Sysetm(App) ClassLoader 系统类加载器/应用加载器,负责自定义类的加载
  4. User ClassLoader 自定义类加载器,自定义的类加载器

双亲委派模型:当自定义类进行类加载时,并不是一开始就由系统类加载器进行加载的,而是会交给扩展类加载器,扩展类加载器又会交给根类加载器,但是根类加载器在核心类的jar包中找不到自定义的类,于是又会原路返回至系统类加载器,最后还是由系统类加载器执行。

注解

注解是代码里面的一些特殊标记,可以在编译、类加载、运行时被读取,并执行相应的处理。注解可以在不改变原有逻辑的情况下,补充一些信息。注解作为一种数据类型,跟class、interface具有同等地位。

注解的使用方式与修饰符一样,可以给任何一种数据写上注解(类、接口、构造器、变量…)

自定义注解:

1
2
3
4
5
6
7
8
9
10
11
12
// 语法
权限修饰符 @interface 注解名字{
// 注解体
属性类型 属性名();
属性类型 属性名();
属性类型 属性名();
.....
}

//举例
public @interface MyAnno {
}

注解的使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// @注解名(属性1 = value1,属性2 = value2)

// 注解使用
@MyAnno3(name = "zs",age = 20)
public static void func() {

}


// 例子:获取注解信息
public class Demo {
public static void main(String[] args) throws Exception{
//获取Login注解里的信息 打印一下
// 获取字节码文件对象
Class<?> c = Class.forName("_23annotation.com.cskaoyan._04handle.Demo");
// 获取方法对象
Method method = c.getDeclaredMethod("login");
// 再判断方法上使用了注解 isAnnotationPresent
boolean annotationPresent = method.isAnnotationPresent(Login.class);
System.out.println(annotationPresent);
if (annotationPresent) {
// 是 , 获取这个注解实例 getAnnotation
Login annotation = method.getAnnotation(Login.class);
// 获取属性
String name = annotation.name();
String password = annotation.password();
System.out.println(name);
System.out.println(password);
}

}

@Login
public static void login() {

}
}

// 使用元注解修饰
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Login {
// 定义属性
String name() default "root";
String password() default "123456";
}

元注解:描述注解的注解。常用的元注解有:

  1. @Retention元注解,来定义我们自己定义的注解的保留级别.

    1
    2
    3
    RetentionPolicy.RUNTIME
    RetentionPolicy.CLASS // 默认
    RetentionPolicy.SOURCE
  2. @Target元注解,注解可以作用的目标

    1
    2
    3
    4
    ElementType.TYPE// 整个类
    ElementType.FIELD// 成员变量
    ElementType.CONSTRUCTOR// 构造方法
    ElementType.METHO// 成员方法

GC

如何确定垃圾:

  1. 引用计数算法:给对象添加一个引用计数器,每当有引用指向它,计数器+1;每当引用失效,计数器-1。当计数器为0,表示该对象不可被引用。但是引用计数算法无法应用在循环引用中。
  2. 根搜索算法:以一个叫”GC Roots”的对象为起点向下搜索,看一个对象是否存在连接至GC Root的引用链,如果没有表示该对象不可被引用。GC使用根搜索算法。

如何回收垃圾:

  1. 标记清除算法:首先标记出所有需要回收的对象,再统一回收;或者标记出所有存活的对象,统一回收未被标记的对象。虽然实现简单,但是会产生很多内存碎片。

  2. 标记复制算法:将一块内存划分成容量相等的两块,每次使用其中一块,当内存用完后,将还存活的对象复制至另一块内存中,再把已满的内存全部清理。虽然实现简单且不容易产生内存碎片,但是内存利用率降低了,且存活对象较多时,会产生许多不必要的开销,降低效率。

  3. 标记整理算法:同标记清除算法一样,将所有需要回收的对象标记,但是它不会直接清理,而是将存活的对象都往一端移动,移动完成后清除边界外的所有对象。这样虽然不会产生内存碎片,但是效率却降低了。

  4. 分代收集算法:根据对象的存活时间将内存划分为新生代、老年代和永久代,新生代中的对象大部分都是存活时间较短的,老年代中的对象则是存活时间较长的。

    新创建的对象会放入新生代中,新生代空间使用的是标记复制算法,将新生代空间划为一个eden空间和两个survivor空间(survivor1、survivor2),其中eden空间用来放置新建的对象,survivor1和survivor2则用来放置复制一遍和复制两遍后存活的对象。当过了一定时间后,survivor2中的对象会放至老年代。

    老年代中因为存活对象较多,一般使用标记整理算法。

何时回收垃圾:

  1. 申请堆空间失败,表示堆空间已满,触发GC。
  2. 系统进入休眠一段时间触发GC。
  3. 主动调用GC。

设计模式

五大原则:

  1. 单一职责原则:每个类只负责自己的部分。
  2. 开闭原则:一个类或模块应该对拓展开放,对修改关闭。
  3. 里氏替换原则:任何父类可以出现的地方,子类都可以出现。
  4. 接口隔离原则:一个接口只提供一个对外的功能。
  5. 依赖倒置原则:上层模块不应该依赖于底层模块,而应该依赖于抽象类或接口;抽象类或接口不应该依赖于具体实现类,具体实现类应该依赖于抽象类或接口。

单例设计模式:

保证一个类只有一个对象,防止频繁的创建和销毁对象,避免对共享资源的多重占用。

实现方法:构造方法私有;提供返回实例的静态方法;提供自身类型的全局变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Singleton1 {
//- 提供自身类型的全局的成员变量
private static Singleton1 instance;
// - 构造方法私有
private Singleton1() {
}


//- 提供静态方法,返回实例
public static Singleton1 getInstance() {
// 最终要返回singleton1对象
// 做判断
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}

工厂设计模式:

可以通过一个工厂批量生产对象,同时隐藏创建对象的一些细节,标准化产生实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class FruitFactory {
// 提供1个静态方法 返回具体水果对象
public static Fruit getInstance(String name) {
Fruit fruit = null;
if ("apple".equals(name)) {
fruit = new Apple();
} else if ("orange".equals(name)) {
fruit = new Orange();
} else if ("banana".equals(name)) {
fruit = new Banana();
} else {
System.out.println("生产不了!");
}
// 返回水果对象
return fruit;
}


// 不修改原有的代码逻辑 实现功能
public static Fruit getInstance2(String className) throws Exception {
// 根据全限定名 获取字节码文件对象
Class<?> c = Class.forName(className);
// 获取构造方法
Constructor<?> declaredConstructor = c.getDeclaredConstructor();

// 实例化对象
Fruit fruit = (Fruit) declaredConstructor.newInstance();

// 返回对象
return fruit;
}
}

本文作者:Ykuri98
本文链接:https://ykuri98.github.io/2022/04/22/%E5%AD%A6%E4%B9%A0%E6%80%BB%E7%BB%93%EF%BC%882022-04-19-2022-04-24%EF%BC%89/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
×