类初始化顺序

单类中初始化顺序

在单个类中,对于静态变量、静态初始化块、变量、初始化块、构造器,它们的初始化顺序以此是:

(静态变量、静态初始化块)>(变量、初始化块)>构造器。

Read More

JVM额外知识学习

GC日志分析

1
2
0.303: [Full GC (System.gc()) [PSYoungGen: 464K->0K(76288K)] [ParOldGen: 8K->428K(175104K)] 472K->428K(251392K), 
[Metaspace: 3086K->3086K(1056768K)], 0.0058612 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
分析
  1. 0.303:表示 GC发生的时间,从java虚拟机启动以来经过的秒数。

  2. [Full GC (System.gc()) :表示 垃圾收集的停顿类型。有 [GC, [Full , [Full GC(System.gc())类型。 其中,有 [Full 说明GC过程中发生了STW。如果调用了System.gc()方法触发了收集,则显示:[Full GC(System.gc())

  3. [PSYoungGen:表示 GC发生区域。有 [DefNew、[Tenured、[Perm等类型。 此处显示的区域名称与使用GC的垃圾收集器有关。Serial收集器中的新生代名为“Default New Generation”,所以显示的是“[DefNew”,如果是ParNew收集器,新生代名称就会变为“[ParNew”,意为“Parallel New Generation”。如果采用Parallel Scavenge收集器,那它配套的新生代称为“PSYoungGen”,老年代和永久代同理,名称也是由收集器决定的。
  4. 464K->0K(76288K):表示 GC前该内存区域已使用容量->GC后该内存区域已使用容量(该内存区域总容量)

Read More

Integer类学习

自动装箱机制

自动装箱机制:在将int类型的数据直接赋值给Integer类型时,会触发自动装箱机制,自动装箱机制的实质是:调用了Integer.valueOf(i)方法(通过跟踪debug可知),阅读源码

1
2
3
4
5
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}

可知,使用了Integer中的静态内部类IntegerCache类,其实现为:

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

/**
* 使用了享元模式,实现了对象的复用
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];

static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}

可知,该静态内部类缓存了从-128到127这256个最常用数的Integer对象,Integer类被加载的时候这些缓存对象就初始化好了。因此可知在-128到127这256个最常用数在发生自动装箱的时候,它们的地址是相同的。

因此:

1
2
3
4
5
6
7
8
9
10
11
Integer a1 = new Integer(1);
Integer a2 = new Integer(1);
System.out.println(a1 == a2); //false

Integer b1 = 1;
Integer b2 = 1;
System.out.println(b1 == b2); //true

Integer c1 = 200;
Integer c2 = 200;
System.out.println(c1 == c2); //false

JVM 学习

前言

关于java虚拟机的学习,网上有许多学习文章。同时周志明老师编写的图书:《深入理解JVM虚拟机》也是JVM学习者必读图书之一。虽说之前也有相关的学习过,但是一直没有进行梳理,导致知识相对很零散,所以为了日后方便自己或他人学习,本文将对JVM进行简略的知识梳理。

内存模型

Java内存模型,往往是指Java程序在运行时内存的模型,而Java代码是运行在Java虚拟机之上的,由Java虚拟机通过解释执行(解释器)或编译执行(即时编译器)来完成,故Java内存模型,也就是指Java虚拟机的运行时内存模型。

JVM运行时数据区

JVM运行时数据区,包括5部分:堆,方法区,程序计数器,虚拟机栈,本地方法栈。在这5部分中,其中:堆,方法区是共享数据区,即所有线程共享的内存区域;程序计数器,虚拟机栈,本地方法栈是线程私有,即每个线程都会有自己的独立内存区域,各线程之间互不影响,独立存储。

Read More

TreeMap源码学习

前言

TreeMap 是 Java集合框架中比较重要一个的实现。TreeMap 底层基于红黑树实现,可保证在log(n)时间复杂度内完成 containsKey、get、put 和 remove 操作,效率很高。另一方面,由于TreeMap 基于红黑树实现,这为 TreeMap 保持键的有序性打下了基础。

由于 TreeMap 底层基于 红黑树 实现,因此,在学习 TreeMap 源码之前,我们需要先学习一下红黑树的基础知识。

红黑树知识学习

简介

红黑树是一种自平衡的二叉查找树,是一种高效的查找树。

Read More

LinkedHashMap源码学习

前言

LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap不能随时保持遍历顺序和插入顺序一致的问题。LinkedHashMap 直接复用了HashMap中的许多方法,仅为维护双向链表覆写了部分方法。关于HashMap源码 在此之前已经分析过,不在讲述。

数据结构图

在 HashMap源码分析文章中,我们已知道 HashMap的底层采用 Node数组+链表+红黑树 的存储结构,结构示意图大致如下:

HashMap底层数据结构


LinkedHashMap 在上面结构的基础上,

Read More

HashMap源码学习

前言

Java为数据结构中的映射定义了一个接口java.util.Map,此接口主要有四个常用的实现类,分别是HashMap、Hashtable、LinkedHashMap和TreeMap。其中HashMap是Java程序员使用频率最高的用于映射(键值对)处理的数据类型。HashMap是一种无序的,且允许null作为键值对的Map集合。该类除了不是同步的,且允许null键值对外,其他都与Hashtable基本一致。由于Hashtable是遗留类,且并发性不如ConcurrentHashMap,所以在新代码中基本上不使用。HashMap的底层采用 Node数组+链表+红黑树 的存储结构。该类除了没有并发功能外,与 ConcurrentHashMap 类基本一致。

665f644e43731ff9db3d341da5c827e1

源码解析

Read More

AbstractMap源码学习

前言

关于 java 的集合框架,我们前面已经学习了 Collection接口 及其子类,比如:ArrayList, LinkedList, HashSet 等。在本篇中,我们将学习日常编程中最常用的另一集合分支:Map。我们最常用的Map集合为HashMap,从类图中,我们可知,它的父类为AbstractMap,所以,我们从AbstractMap入手分析Map的相关源码。

源码分析

Read More

Set相关集合源码学习

前言

在前面几个章节中,已经对集合中的 List列表一支进行了相关的学习。在我们日常编程中,使用最多的集合还有 Set 。本章我们将学习Set的相关知识。

1
2
3
4
5
6
graph TD
A[Christmas] -->|Get money| B(Go shopping)
B --> C{Let me think}
C -->|One| D[Laptop]
C -->|Two| E[iPhone]
C -->|Three| F[Car]

java基础集合框架

java基础集合框架

HashSet源码学习

在上图中,我们可以看到,Collection接口 的另一分支:Set 集合,常用的有:HashSet,TreeSet等。在此,我们先学习一下平时最常用的 HashSet。

数据结构

Read More

LinkedList源码学习

前言

在上篇文章 ArrayList源码学习 中,我们队 ArrayList 的源码进行了相应的分析。在学习的过程中,我们已经知道,ArrayList的底层是数组结构。所有操作都是针对数组进行的。在本篇中,我们学习一下List接口的另一个重要的子类LinkedList。最后在总结一下二者的区别。

源码解析

数据结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//LinkedList是双链表结构,继承了List和Deque接口
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {

//元素个数
transient int size = 0;
//双链表的头结点。不变性:(first == null && last == null) || (first.prev == null && first.item != null)
transient Node<E> first;
//双链表的尾结点。不变性:(first == null && last == null) || (last.next == null && last.item != null)
transient Node<E> last;

//迭代器
private class ListItr implements ListIterator<E> {}

//内部节点类
//列表内部节点类
private static class Node<E> {}
}

从LinkedList的源码中,我们可以发现:LinkedList 不仅继承了List接口,而且还继承了Deque,即:Queue的子类。因此可知,LinkedList不仅可以当做列表使用,而且还能实现队列的功能。

与ArrayList底层数组结构不同的是,LinkedList的底层数据结构是链接,即由节点构成。底层数据结构的差异自然而然就会导致对存储对象的操作差异。

Node节点类

Read More

Fork me on GitHub