Tag - java

J.A.R.V.I.S

Life is not just Live

2019

Java古老的集合类之Hashtable

Hashtable虽然现在不经常被用到,但是它作为Java最早的集合类,今天来看一下它的源码。

首先说明一个问题,在Java中大部分都是驼峰式写法,但是Hasbtable并没有采用这种写法。

继承与实现关系

1
2
3
public class Hashtable<K,V> 
extends Dictionary<K,V>
implements Map<K,V>, Cloneable, java.io.Serializable {}

可以看出它继承的是DictionaryHashMap并不是同一个父类。但是它也实现了MapCloneableSerializable接口。说明它可以被克隆,可以执行序列化。

变量

1
2
3
4
5
6
7
8
9
private transient Entry<?,?>[] table;

private transient int count;

private int threshold;

private float loadFactor;

private transient int modCount = 0;

来一个一个的解释每一个变量的意义:

  • table

与HashMap一样,利用数组作为底层的存储容器,并且添加了关键字transient。这个关键字的意思是在进行序列化的时候不会被序列化。这个关键字具体可以看一下这篇文章

  • count

表示容器中存储的数量

  • threshold

扩容阈值,当容器中的数量到达这个值后会进行扩容机制。这个值默认情况下为 (capacity* loadFactor)

  • loadFactor

扩容系数,默认为0.75f。

  • modCount

修改次数,当增加或删除时,这个值会进行加一。表示这个容器结构修改的次数。这个变量在迭代,序列化等操作、多线程的操作下都尽量保证了安全性。

12月 20 · 11 min

微服务之SpringCloud-注册中心eureka

简单项目

首先我们建立一个项目,它作为我们的全部项目的容器,并负责公共依赖的版本管理等。

项目结构是这样的:

然后我们在pom.xml中导入我们所需要的依赖,我们全部使用 springboot 来启动项目,并且需要修改packaging的方式为pom。最终的文件如下所示:

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
47
48
49
50
51
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>learn.spring.cloud.eureka.demo</groupId>
<artifactId>learn-spring-cloud-eureka</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>simple-parent</name>
<description>学习eureka</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

12月 18 · 11 min

Java注解

注解,这个经常在开发中使用到的东西,它的使用语法是怎么样的?如何去自定义一个注解呢?

什么是注解

我们在日常开发中,比如 java 中的@Override,在 springboot 中用到的@SpringBootApplication等一系列标注在类或者方法上的注解。我们添加上注解后会有对应的事件处理,比如我们的@Override注解标明这个方法是重写了父类或者接口的方法,当参数不一致、返回类型不一致等不符合重写的要求时,编译器会报错。类似的@SpringBootApplication也是标明这个项目的一个 springboot 项目,默认会启动一个 tomcat 容器等。

注解是从 jdk5 开始引入的新特性。

注解的语法

1
public @interface FirstAnnotation {}

通过@interface即可声明一个注解。

12月 06 · 6 min

StringBuilder为什么线程不安全?

在脉脉上看到一篇文章,StringBulider 为什么线程不安全,然后想了一下,确实不知道。

之前问string 相关问题,只了解了 string 不可变,stringbuffer 线程安全,stringbuilder 线程不安全。但却没有搞清楚为什么是不安全的,今天就去看了一下 stringbuilder 的源码,来了解一下原因。

首先来测试一下多线程下的不安全问题:

1
2
3
4
5
6
7
8
9
10
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();

for (int i = 0; i < 100000; i++) {
new Thread(() -> stringBuilder.append("a")).start();
}

System.out.println(stringBuilder.length());

}

这个方法最终的理想结果应该是 100000,但是当我们多运行几次,发现他的结果出错了!结果变成了99999或者更小的数值。有时候甚至还抛出了数组越界异常(概率极小)。

11月 17 · 4 min

TreeMap源码学习

之前看过了HashMap,LinkedHashMap的源码,这次来看一下TreeMap的源码。

从这个名字就能看出,TreeMap底层使用的是树来进行存储的。

变量

1
2
3
4
5
6
7
8
9
//比较器,用于左右子树的判断。
//正常情况下,左子树为 1,父节点为 2,右子树为 3。如果比较器设置 3<1<2。则左子树为3,父节点为 1,右子树为 2。
private final Comparator<? super K> comparator;
//根节点
private transient Entry<K,V> root;
//容量
private transient int size = 0;
//修改的次数,在迭代和序列化时用到
private transient int modCount = 0;

看一下 root 节点的数据结构:

1
2
3
4
5
6
7
8
9
10
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK;

...
}

由于有一个color=BLACK属性,所以底层数据结构应该是红黑树

11月 12 · 4 min

JAVA线程

基础概念

线程的所有状态:

这些状态都在 Thread中的State枚举中定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
public enum State {
//表示刚刚创建的线程,这种线程还没开始执行
NEW,
//在 start() 方法调用后,线程开始执行,此时状态处于 RUNABLE
RUNNABLE,
//如果线程在执行过程中遇到 synchronized 同步块,就会进入 BLOCKED 阻塞状态,直到获取请求的锁
BLOCKED,
//等待状态,WAITING 会无时间限制的等待,TIMED_WAITING 会有时间限制
WAITING,
TIMED_WAITING,
//线程执行完毕,表示结束
TERMINATED;
}

初始线程

  1. Thread

  2. Runable接口

    Thread类中调用start()方法之后会让线程执行run()方法,而run()方法中又是对Runable实例的调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
     /* What will be run. */
    private Runnable target;

    @Override
    public void run() {
    if (target != null) {
    target.run();
    }
    }

9月 22 · 25 min

JAVA知识整理

JAVA基础

类的初始化顺序

静态变量和静态语句块会优先于实例变量和普通语句块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static String s = "静态变量";

static {
System.out.println("静态语句块");
}

public String z = "实例变量";

{
System.out.println("普通语句块");
}

public InitClass(){
System.out.println("构造函数");
}
  • 父类(静态变量,静态语句块)
  • 子类(静态变量,静态语句块)
  • 父类(实例变量,普通语句块)
  • 父类(构造函数)
  • 子类(实例变量,普通语句块)
  • 子类(构造函数)

9月 10 · 5 min

JAVA容器

8月 31 · 1 min

迭代器

迭代器

在java中主要有两种迭代器,IteratorListIterator。这两个都是接口。先来看一下这两个接口有什么区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface Iterator<E> {

boolean hasNext();

E next();

default void remove() {
throw new UnsupportedOperationException("remove");
}

default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}

Iterator主要有四个方法。判断有没有下一个元素、获取下一个元素,删除元素和forEachRemaining方法。

再来看一下ListIterator

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface ListIterator<E> extends Iterator<E> {

boolean hasNext();

E next();

boolean hasPrevious();

E previous();

int nextIndex();

int previousIndex();

void remove();

void set(E e);

void add(E e);
}

我们可以看到他是继承了Iterator。除了上面的两个方法还多了好几个方法。判断是否有上一个元素,获取上一个元素的值,获取上一个元素的索引,获取上一个元素的索引。除了移除还有添加和更新的方法。

他们在不同的类里面都有自己的实现,之前看ArrayListHashMap的时候把这一块给跳过了,现在来看一下他们是如何实现的。

8月 28 · 7 min

HashSet源码

8月 26 · 1 min

0 %