类初始化顺序

单类中初始化顺序

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

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

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接口 及其子类,比如:ArrayListLinkedList, 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