0%

在程序设计中经常用到一系列类型, 他们需要特殊对待.
可以把他们想象成基本类型.
之所以特殊对待, 是因为new将对象存储在里, 故用new创建一个对象–特别是小的, 简单的变量, 不是特别有效.
因此, 对于这些类型, Java采用与C/C++相同的方法.
这也就是说, 不用new来创建变量, 而是创建一个并非引用的自动变量.
这个变量直接存储, 并置于堆栈中, 因此更加高效.

Java要确定每种基本类型所占存储空间的大小.
他们的大小并不像其他大多数语言那样随机器硬件架构的变化而变化.
这种所占存储空间大小的不变性是Java程序比其他大多数程序语言编写的程序更具可移植性性的原因之一.

所有数值类型都有正负号, 所以不要去寻找服务号的数值类型.

基本类型 大小 最小值 最大值 包装器类型 默认值
boolean - - - boolean false
char 16-bit Unicode 0 Unicode 2162^{16}-1 Char \u000(null)
byte 8 bits -128 128 Byte (byte)0
short 16 bits -2152^{15} 2152^{15}-1 Short (short)0
int 32 bits -2312^{31} 2312^{31}-1 Int 0
long 64 bits -2632^{63} 2632^{63}-1 Long 0L
float 32 bits IEEE7541 IEEE754 Float 0.0F
double 64 bits IEEE754 IEEE754 Double 0.0D
void - - - Void -

1. 其他常用类型

1.1. 高精度数字

  • BigInteger
    支持任意精度的整数.
  • BigDecimal
    支持任何精度的定点数.

这两个类包含的方法, 提供的操作与基本类型所能执行的操作类似.
也就是说, 能作用于int或float的操作, 也同样能作用于BigInteger和BigDecimal.
只不过必须以方法调用的方式取代运算符方式来实现运算.
由于这么做复杂了许多, 所以运算速度会比较慢.
这里, 我们以速度换取了精度.

1.2. 数组

Java确保数组被初始化, 而且不能在它的范围之外被访问.
这种范围检查, 是以每个数组上少量的内存开销及运行时的下标检查为代价的, 但是由此换来的是安全性和效率的提高, 因此付出的代价是值得的.

当创建一个数组对象时, 实际上就是创建了一个引用数组, 并且每个引用都对自动被初始化为一个特定的值, 该值拥有自己的关键字null.
一旦Java看到null, 就知道这个引用还没指向某个对象.
在使用任何引用之前, 必须为其指定一个对象;如果试图使用一个还是null的引用, 在运行时将会报错.
因此, 常犯的数组错误在Java中就可以避免.

还可以创建用来存放基本数据类型的数组.
同样, 编译器也能确保这种数组的初始化, 因为它会将这种数组所占的内存全部置为0.

2. Resource

  • Java编程思想


  1. 1.IEEE 754 标准是IEEE二进位浮点数算术标准(IEEE Standard for Floating-Point Arithmetic)的标准编号. https://baike.baidu.com/item/IEEE%20754/3869922?fr=aladdin&fromid=10427270&fromtitle=IEEE754%E6%A0%87%E5%87%86

网络应用需要处理的无非就是两大类问题, 网络I/O, 数据计算.相对于后者, 网络I/O的延迟, 给应用带来的性能瓶颈大于后者.

在程序执行期间具有不同的状态而其他方面都相似的对象会被分组到对象的类中, 这就是关键字class的由来

1. 访问控制

子孙类 外部包
public
protected
<package> ×
private × ×

1.1. 访问控制的意义

将程序开发人员按角色划分为类创建者(或者说库设计者, 那些创建新数据类型的程序员)和客户端程序员(那些在其应用中使用数据类型的消费者)

  1. 让客户端程序员无法触及他们不应该触及的部分.
    可以让客户端程序员很容易的看出哪些东西是重要的, 哪些可以忽略.
  2. 允许库设计者可以改变内部的工作方式而不用担心会影响到客户端程序员

2. static 关键字

通常来说, 当创建类时, 就是在描述那个类的对象的外观和行为.
除非用new创建那个类的对象, 否则, 实际上并未获得任何对象.
执行new来创建对象时, 数据存储空间才被分配, 其方法才供外界调用.

有两种情形用上述方法是无法解决的.
一种情形是, 只想为某特定域分配单一存储空间, 而不去考虑究竟要创建多少对象, 甚至根本不创建任何对象.
另一种情形是, 希望某个方法不与包含它的类的任何对象关联在一起.
也就是说, 即使没有创建对象, 也能调用这个方法.

通过static关键字可以满足这两方面的需要.

有些面向对象语言采用类数据类方法两个术语, 代表哪些数据和方法只是作为整个类, 而不是类的某个特定对象而存在.

3. 类型转换

  • 窄化转换
    将能容纳更多信息的数据类型转换成无法容纳那么多信息的类型.
    这可能面临数据丢失, 所以编译器会强制我们显式的进行类型转换.
  • 扩展转换
    不必显式转换.
    新类型一定能容纳原来类型的信息.

4. 构造器

构造器是最常见的方法重载.

5. this关键字

this表示调用方法的那个对象.

如果在方法内部调用同一个类的另一个方法, 就不必使用this, 直接调用即可.

常用在构造器方法重载中:

  • 调用this方法, 即在构造器中调用另外一个构造器.此方式必须将构造器调用置于方法最起始位置, 否则编译器会报错.
  • 若参数名称与数据成员名称相同, 可以用this明确指定数据成员, 防止产生歧义.

6. super关键字

7. 类的加载

classloader
JIT

8. abstract class & interface

abstract class 和 interface 是支持抽象类定义的 2 种机制.

它俩的异同:

abstract class interface
实例化 不能

9. Resource

  • Java编程思想

  1. 1.平台相关的目标文件格式 是指平台编译出来的 Class 文件无法在其他平台中使用. 相反, 正因为强制, 明确地定义了本来会跟平台相关的细节, 所以才达到了平台无关的效果.

推理是形式.

需要注意的是: 推理必须掌握事物的所有对象.
如果不能考察某类事物的全部对象, 而只根据部分对象作出的推理, 不一定完全可靠.

思维形式是人们进行思维活动时对特定对象进行反映的基本方式, 即概念, 判断, 推理.思维的基本规律是指思维形式自身的各个组成部分的相互关系的规律, 即用概念组成判断, 用判断组成推理的规律.它有4条: 即同一律, 矛盾律, 排中律和充足理由律.简单的逻辑方法是指, 在认识事物的简单性质和关系的过程中, 运用思维形式有关的一些逻辑方法, 通过这些方法去形成明确的概念, 作出恰当的判断和进行合乎逻辑的推理.

学习形式逻辑知识, 可以指导我们正确进行思维, 准确, 有条理地表达思想; 可以帮助我们运用语言, 提高听, 说, 读, 写的能力; 可以用来检查和发现逻辑错误, 辨别是非.同时, 学习形式逻辑还有利于掌握各科知识, 有助于将来从事各项工作.

1. Resource

https://baike.baidu.com/item/推理/1905524

Stream API 是对数据源的元素支持聚合操作

1. 生成 Stream Source

  • Collection.steam() 为集合创建串行流

  • Collection.parallelStream() 为集合创建并行流, 集合元素越多, 使用的资源越多.

  • Arrays.stream(T array) or Stream.of()

  • java.io.BufferedReader.lines()

  • java.util.stream.IntStream.range()

  • java.nio.file.Files.walk()

  • java.util.Spliterator

  • Random.ints()

  • BitSet.stream()

  • Pattern.splitAsStream(java.lang.CharSequence)

  • JarFile.stream()

2. stream 操作

流的操作分 3 种:

  • Intermediate
    一个流可以后面跟随零个或多个 intermediate 操作.
    其目的主要是打开流, 做出某种程度的数据映射/过滤, 然后返回一个新的流, 交给下一个操作使用.
    这类操作都是惰性化的(lazy), 就是说, 仅仅调用到这类方法, 并没有真正开始流的遍历.

    • map (mapToInt, flatMap 等)
      • mapToInt
        转换成一个 int 数组后, 可使用 summaryStatistics() 返回 IntSummaryStatistics 对象, 进行统计操作, 如 getMax, getMin, getSum, getAverage
    • flatMap
    • filter
    • distinct
    • sorted
    • peek 对每个元素执行操作并返回一个新的 Stream
    • limit
    • skip
    • parallel
    • sequential
    • unordered
  • Terminal
    一个流只能有一个 terminal 操作, 当这个操作执行后, 流就被使用 了, 无法再被操作.
    所以这必定是流的最后一个操作.
    Terminal 操作的执行, 才会真正开始流的遍历, 并且会生成一个结果, 或者一个 side effect.

    • forEach 接收一个 Lambda 表达式, 然后在 Stream 的每一个元素上执行该表达式.

    • forEachOrdered

    • toArray

    • reduce

    • collect

    • min

    • max

    • count

    • anyMatch

    • allMatch

    • noneMatch

    • findFirst

    • findAny

    • iterator

  • short-circuiting

    • 对于一个 intermediate 操作, 如果它接受的是一个无限大(infinite/unbounded)的 Stream, 但返回一个有限的新 Stream.

    • 对于一个 terminal 操作, 如果它接受的是一个无限大的 Stream, 但能在有限的时间计算出结果.

    • anyMatch

    • allMatch

    • noneMatch

    • findFirst

    • findAny

    • limit

3. 自己生成流

1
2
3
4
5
6
Random seed = new Random();
Supplier<Integer> random = seed::nextInt;
Stream.generate(random).limit(10).forEach(System.out::println);
//Another way
IntStream.generate(() -> (int) (System.nanoTime() % 100)).
limit(10).forEach(System.out::println);
1
Stream.iterate(0, n -> n + 3).limit(10). forEach(x -> System.out.print(x + " "));

实现了很多归约操作,如 Collectors.toList(), Collectors.joining(", ")

4. Resource

1. 用途

  1. 保存线程上下文, 可以再任意需要的地方获取
    如系统日志可以在任何地方获取到请求ID

  2. 线程安全的, 避免某些情况需要考虑线程安全必须同步带来的性能损失
    如 SimpleDateFormat 本身是线程不安全的, 如果要用这个类, 可以这样声明:

    1
    2
    3
    4
    5
    6
    7
    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {

    @Override
    protected DateFormat initialValue() {
    return new SimpleDateFormat("yyyy-MM-dd")
    }
    }

2. 实现原理

ThreadLocal 将值维护在 ThreadLocalMap 中, 其中 key 为 ThreadLocal 对象.
每一个线程都有自己独立的 ThreadLocalMap; 在同一线程中, 多个 ThreadLocal 公用一个 ThreadLocalMap.

3. ThreadLocal 的回收机制

ThreadLocalMap 中的 Entry 是 WeakReference,
WeakReference 的特性是: 当系统进行垃圾回收时, 无论内存是否充足, 该对象仅仅被弱引用关联, 那么就会被回收.
这是为了防止 ThreadLocal 一致没有回收而导致的内存泄漏风险.

由于ThreadLocal 的回收机制, 通常 ThreadLocal 一般都声明成静态属性, 然后在请求处理完成之后, 主动 remove 掉.

1. 树

根结点: 没有父结点的结点
分支结点: 有子结点的结点
叶子结点: 没有子结点的结点
兄弟结点: 拥有相同父结点的结点

边: 父结点与自结点之间的连线. 一棵树有 n 个结点, 则有 n-1 条边
路径长度: 路径上边的条数; 路径上有 n 个结点, 则路径长度为 n-1
内部路径长: 一棵树的所有结点的深度的和
深度: 从根结点到任意结点的路径长度
层数: 根结点在1层, 其他任一结点的层数是其父结点的层数加1
高度: 从任意结点到叶子结点的层数
树的高度 = 树的层数: 从根结点到叶子结点的最大层数

度: 子结点个数
树的度: 最大子结点个数

1.1. 遍历方式

  • 前序遍历 结点的处理在它的子结点之前. 根左右
  • 后序遍历 结点的处理在它的子结点之后. 左右根
  • 中序遍历 先处理左子结点, 再处理当前结点, 最后处理右子结点. 左根右
  • 层序遍历 深度为 d 的结点要在 d+1 的结点前处理.

2. 二叉树 Binary Tree

一棵平均二叉树的深度要比结点个数小的多

2.1. 二叉查找树 Binary Search Tree

特点:

对于树中每个结点 X, 它的左子树中所有项的值都小于 X 中的项, 而它的右子树中的所有项的值都大于 X 中的项.

查找时间复杂度与二叉查找树的高度成正比: O(logn)O(\log n), n 为结点个数

3. 平衡树

平衡树有: AVL, SBT, 伸展树, 红黑树, TREAP, B-Tree, B+Tree, B*Tree等

3.1. 平衡二叉树 AVL

左右子树的树高不大于 1.
在插入或删除后自动平衡左右分支的高度.
用于解决普通二叉树在大量插入或删除后出现查询复杂度退化的问题

4. B-Tree

5. 红黑树 RB-Tree

6. Resource

  • 数据结构 – 清华大学出版社

1. abc

  • 不可变
  • 实现了Comparable接口, 可比较
  • 不可变
  • 实现了Comparable接口, 可比较
  • 不可变
  • 实现了Comparable接口, 可比较
  • 不可变
  • 实现了Comparable接口, 可比较