【Java】知识点

189 阅读10分钟

扩展

  1. 笔记
  2. “不同族”基本数据类型转换
  3. 基本数据类型和引用类型赋值时的底层分析
  4. Socket套接字
  5. 二进制相关概念、运算与应用
  6. 浮点数二进制
  7. 23种设计模式
  8. 自定义注解
  9. 泛型
  10. Lambda表达式
  11. 反射
  12. 线程生命周期与线程通信
  13. 线程池生命周期。(见【生命周期状态】一栏)
  14. @CallerSensitive注解
  15. # [源码解析]Class
  16. 异常处理
  17. # volatile关键字
  18. POI入门
  19. 类加载
  20. 常用关键字

2、多态

2.1 继承

参考笔记一,P33.7、P34.1、P35.2/3;笔记二,P26.5。

  1. 子类拥有父类所有,只是无法使用private修饰部分;父类拥有子类所有,只是无法使用子类扩展部分。故经过上溯或下溯转型,都可使用相应资源;
  2. 只能先进行上溯转型,再进行下溯转型。由于上溯或下溯转型后,很难判断引用所指向的对象到底属于哪个类,故可用instanceOf判断;
  3. 若子类未重写父类方法,尽管子类拥有父类所有,但那些方法在根本上还是属于父类,因此子类调用的还是父类方法;
  4. super并不代表父类引用,只是用于调用父类成员getClass()是 Object 类的 final 方法(不可重写),故super.getClass()等同于this.getClass(),返回的是当前对象所属类的 Class 对象。

2.2 重载

参考笔记二,P26.6、P29.4。

参数列表不同、或返回值类型不同、或都不同的同名方法称之为“重载”。与访问权限无关,其作用是增加代码可读性。注意:

  1. main()也可重载,默认情况下执行参数类型为String[]main()
  2. 若方法名、参数列表都相同,仅返回值类型不同,则不是“重载”,且不允许

2.3 重写

参考笔记二,P29.3。

当子类方法与父类参数列表和返回值类型都相同的同名方法称之为“重写”。注意:

  1. 重写方法的访问权限不能低于被重写方法;
  2. 重写方法的异常范围不能大于被重写方法;
  3. 若子类某方法与父类某方法方法名、参数列表都相同,仅返回值类型不同,这不是“重写”,且不允许。

3、实例化相关

3.1 构造方法说明

参考笔记一,P34.3。

1:为什么JVM会默认为类创建无参构造方法?

因为实例初始化时需要。

2:为什么子类会默认调用父类无参构造方法?

因为子类拥有父类所有,这需要初始化父类,即调用构造方法。注意:无论子类或父类有没用自定义构造方法,子类都会隐式调用父类无参构造方法。

3:为什么super()必须在构造方法的第一行?

从第2点可知,子类初始化时会同时初始化父类,但并不能知道super()在第一行的原因。因为父类的初始化数据存储于子类内存空间(具体指堆),即便后续调用(先初始化子类,后初始化父类)也可访问。因此,super()在第一行的原因是:子类要为父类分配内存空间,自然要先知道父类占多少空间,即先初始化父类。

3.2 创建对象方法

参考笔记二,P39.7、P45.2。

1new xx()
2、反射
3、xx.clone()
4、反序列化

其中,clone()属Object类方法,使用clone()的类必须实现Cloneable接口和重写clone()。其中,克隆的对象是一个新对象,克隆分为浅克隆深克隆 两种,两者的区别是当克隆的类中引用其他类时,深克隆会同时克隆引用类,而浅克隆不会,仍是同一个。深克隆的实现原理是在相应clone()内克隆引用类

3.3 注意

  1. 若仅实例化子类,由于this代表的是当前实例,故当在父类中使用this时,this代表的是子类实例,而非父类实例。
  2. 实例化时,会先从方法区中检查构造方法是否相符(相同),再初始化成员变量和成员方法。

6、断言

参考笔记二,P7.5。

6.1 什么是“断言”?

断言是类似异常处理的一种特殊语句,表现为一条语句。一般有3种形式:

1assert a;
2assert a: b;
3assert(a);

a 是一个boolean表达式或boolean值,b 是一个基本数据类型变量或对象。

语句表达的意思是:如果 a 为false,抛出异常,打印 b 作为异常信息,程序终止。

断言的作用是保证程序的正确性(判断是否可执行成功),常用于开发和测试阶段(实际上一般很少用)。

与异常处理不同的是,断言是先验条件(先执行 assert,后运行程序;而异常处理是后验条件(先运行程序,后处理异常),比如文件操作中比较常见的 FileNotFoundException,就是先运行程序,再发现文件不存在抛出的异常。

6.2 为什么assert无效?

由于断言会影响程序性能,故“断言校验”是默认关闭的。因此使用断言需要先打开断言:
在这里插入图片描述
输入:

-enableassertions
或
-ea

7、VM 参数

推荐一篇博文《深入理解 Java 虚拟机(第二弹) - 常用 vm 参数分析》(转发)。

目前我暂未作研究,大家可以查阅这篇博文。

9、序列化

参考笔记一,P1、P2.3。

9.1 什么是“序列化”?

“序列化”指将对象转为字节序列、实现将对象持久化(永久保存)到磁盘、使对象能在网络进程间 传递的过程。
(注:实现序列化的类必须实现Serializable接口;若此类引用了其他类,则相应类也必须实现此接口)

特点:

  1. 持久性
    将对象转为字节序列存于磁盘,即使JVM死机,对象仍然存于磁盘。当JVM宕机时,可以通过反序列化还原对象,并且,序列化的对象占据更小的磁盘空间;
  2. 序列化的对象在网络上传输会更快捷、更安全;
  3. 可实现在进程间传递对象
    “进程间”是什么意思?因为无论程序复杂或简单,在启动时,JVM都只会创建一个进程,而进程间无法直接传输对象。

9.2 序列化ID

示例:

private static final long serialVersionUID = -5809782578272943999L;

这就是序列化ID,其在类加载时生成,用于作为类在JVM内存中的唯一标识。其作用是通过比较字节序列中的序列化ID和实体类中的序列化ID是否一致来判断是否为同一个类,即是否可反序列化,从而还原对象。

9.3 测试

“序列化”与“反序列化*”是一种实现对象持久化的概念,具体实现方法任意。如下示例中使用ObjectOutputStream实现序列化,使用ObjectInputStream实现反序列化是其中一种实现方法。

1、序列化:将对象 Person 序列化到 Person.txt 文件中。
示例:

@AllArgsConstructor
class Person implements Serializable {
    private static final long serialVersionUID = -5809782578272943999L;

    private Integer id;
    private String name;
}
class TestSerializable {
    public static void main(String[] args) throws Exception {
        Person person = new Person(1001, "yuchen");
        System.out.println(person);// 打印:Person(id=1001, name=yuchen)

        // 序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("C:\\Users\\于辰\\Downloads\\新建文件夹\\Person.txt")));
        oos.writeObject(person);
    }
}

测试结果:
字节序列文件:
在这里插入图片描述
字节序列:
在这里插入图片描述

2、反序列化:将 Person.txt 文件中的字节序列通过反序列化还原成 Person 对象。
示例:

class TestSerializable {
    public static void main(String[] args) throws Exception {
        // 反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("C:\\Users\\于辰\\Downloads\\新建文件夹\\Person.txt")));
        Person person = (Person) ois.readObject();
        System.out.println(person);// 打印:com.neusoft.boot.Person@69d0a921
    }
}

12、ORM

全称Object Relational Mapping(对象关系映射),指实体类与数据表一一对应,属性与字段一一对应,而实例/对象对应记录,即将对象“存入”数据表中。常用的ORM框架:mybatis、mybatis-plus、hibernate。

优点:

  1. 提高开发效率;
  2. 解耦合。如:客户需求变更,需要增删字段来实现功能,使用ORM框架,不用 sql 直接编码,能够像操作对象一样从数据库读取数据。

缺点:降低程序性能。

  1. 一般ORM框架系统都是多层的,系统层次多会降低程序性能。且ORM框架是完全面向对象,也会降低程序性能;
  2. ORM框架生成的 sql 语句一般很难写出高效的算法,只能先将对象提取到内存对象中(指select到程序中),再进行过滤和加工,这会降低程序性能;
  3. 在对象持久化时,ORM框架一般会持久化对象的所有属性,有时这是不需要的,这会降低程序性能。
    注:“持久化”指将数据存储进数据库。

14、IPv4

参考笔记一,P75.2。

IPv4由4部分组成,包含网络地址主机地址,每部分解释为一个字节。故都是0 ~ 255的整数。因此,ipv4 占4个字节(32位)。

分类:(注:a指网络地址,b指主机地址)

  1. A类:a 占前8位,b 占后24位,a 的最高位必须是0。因此,范围是:0.0.0.0 ~ 127.255.255.255
  2. B类:a 占前16位,b 占后16位,a 的最高位必须是10。因此,范围是:128.0.0.0 ~ 191.255.255.255
  3. C类:a 占前24位,b 占后8位,a 的最高位必须是110。因此,范围是:192.0.0.0 ~ 223.255.255.255
  4. D类:暂未知,a 的最高位必须是1110。因此,范围是:224.0.0.0 ~ .239.255.255.255
  5. E类:暂未知,a 的最高位必须是1111。因此,范围是:240.0.0.0 ~ 255.255.255.255

17、编译与解释

参考笔记二,P20。

1:什么是“编译”?
“编译”是指将源代码一次性转换成目标程序的过程,编译只执行一次,故编译的着重点不是编译速度,而是目标程序的运行速度。因此,编译器一般都会尽可能多地集成优化技术,使生成的目标程序具有更高的执行速度。

特点:

  1. 对于相同的源代码,目标程序执行速度更快;
  2. 目标程序运行不需要编译器支持,在同类操作系统上使用灵活。

2:什么是“解释”?
“解释”是指将源代码逐条转换并同时运行的过程,不会生成目标程序,故解释的着重点是解释速度。因此,解释在每次程序运行时都需要解释器和源代码,也不能集成太多的优化技术,这样会降低程序的运行速度。

特点:

  1. 由于解释不会生成目标程序,因此解释执行需要保留源代码,这样也便于程序的纠错和维护;
  2. 只要有解释器,源代码在任何操作系统皆可运行,可移植性强。

3:“编译”与“解释”的运用

高级语言按照执行方式分为静态语言脚本语言。静态语言使用编译,如:C/C++、java;脚本语言使用解释,如:python、js、php。 在实际运用中,会将两者混合使用,以实现在保证程序逐条运行的同时保留目标程序,因为程序逐条运行能大大提升程序运行速度,保留目标程序便于程序纠错和维护。

最后

本文中的例子是为了方便大家理解和阐述知识点而简单举出的,旨在阐明知识点,并不一定有实用性,仅是抛砖引玉。

推荐一个Java学习平台 → HOW2J.CN

本文持续更新中。。。