HashMap和Hashtable有什么不同?

类继承体系上的区别HashMap和Hashtable都实现了Map,Cloneable,Serializable接口。但两者不同的是HashMap继承的是AbstractMap而Hashtable继承的是Dictionary。Dictionary已经...

HashMap源码分析

概览12public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable { 从继承关系上看好像并不没有什么特点。它基于哈希表实现了Map接口,并且允许null的值和null的键。HashMap并不能保证有序性。并且它不是同步的。 [] 属性分析1static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 默认的初始容量为16.初始容量的大小和负载因子是非常影响其性能的两个参数。 1static final int MAXIMUM_CAPACITY = 1 << 30; 最大的允许的容量 1static final float DEFAULT_LOAD_FACTOR = 0.75f; 默认的负载因子(装填因子)。这是一个非常重要的参数。负载因子的定义为:填入表中的元素的个数/哈希表的长度(桶的个数)。所以装填因子越大产生冲突的可能性也越大。简单的来说就是装的越多其装满程度也越大,其装填因子也就越大。

LinkedList源码分析

概览123public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable 值得注意的时LinkedList除了实现了List还实现了Deque.也就是说LinkedList也可以当作队列来使用。LinkedList的底层是基于双向链表来实现的。所以它不支持随机访问,但也正是因为采用了双向链表实现,所以它有很高的插入和删除效率。 属性分析1transient int size = 0; size记录了链表中有效元素的个数。 12transient Node<E> first;transient Node<E> last; 双向链表的头指针和尾指针。这里有一个需要注意的地方,他们都使用了transient修饰,也就是说,他们不会被序列化。那么反序列化的时候怎么知道链表头和链表尾呢?其实在序列化的时候,只将链表本身和size进行了序列化,在反序列化的时候,首先获得size的值(此时firse和last为null),然后再将Node一个个读取出来,使用linkLast(E e)重构整个链表。而在这个方法中完成了first和last的赋值。

Vector源码分析

概览123public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable Vector和ArrayList非常的相似,两者都是基于数组实现的。两者最大的不同在于Vector是线程安全的。Vector为了确保线程安全,使用了大量的synchronized方法,这也使得Vector的性能较差。 属性解释1protected Object[] elementData; 和ArrayList类似,使用了数组来作为容器,但和ArrayList不同的是,它并没有transient 修饰,也就是说在序列化时,它也会被序列化。 1protected int elementCount; elementCount记录了Vector对象中存储的有效对象的数量。在创建Vector对象的时候如果没有指明大小的话,默认的大小为10. 1protected int capacityIncrement; capacityIncrement记录了每次扩容时增加的容量大小。如果在创建Vector对象时指定了capacityIncrement的大小,那么每次扩容增加的大小就为:capacityIncrement。如果在创建的时候,没有指定capacityIncrement的大小,那么每次扩容就会扩大两倍。这和ArrayList有些许的不同。

ArrayList源码分析

概览12public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable ArrayList是基于数组实现的,所以支持快速的随机访问。 属性解释1private static final int DEFAULT_CAPACITY = 10; 默认的初始容量。在创建ArrayList实例的时候可以不用指定其大小,默认的容量大小为10;但建议提前预估好合适的容量大小,因为扩容的开销比较大。后面会专门分析。 1private static final Object[] EMPTY_ELEMENTDATA = {}; 共享的空数组实例。在创建ArrayList对象实例的时候,如果容量大小指定为为0时,会让elementData引用共享的整个空数组。

java并发编程学习笔记二

编写正确的并发程序的关键在于共享对象、可变的状态进行访问管理 锁与可见性内置锁可以用来确保一个线程以某种可预见的方式看到另一个线程的影响。锁不仅仅是关于同步与互斥的,也是关于内存可见的。为了保证所有线程都能够看到共享的,可变变量的最新值,读取和写入线程必须使用公共的锁进行同步。 1234567891011@ThreadSafepublic class SynchronziedInteger{ private int value; public synchronized int get(){ return value; } public synchronized void set(int value){ this.value=value; }} 最低限安全性当一个线程在没有同步的情况下读取变量,它可能会得到一个过期值。但它至少可以看到某个线程在那里设定的一个真实数值,而不是一个凭空而来的值。这样的保证称为最低限的安全性。 volatile 变量它可以确保对一个变量的更新以可预见的方式告知其它的线程。当一个域被声明为volatile类型后,编译器运行时会监视这个变量,它是共享的,而且对它的操作不会与其它内存操作一起被重排序。volatile变量不会缓存在寄存器或者缓存在对其它处理器隐藏的地方。所以读一个volatile变量时,总会返回某一线程所写入的最新值。 当一个共享变量声明为volatile后:1.当写一个volatile变量时,JMM会把该线程对应的本地内存种的变量强制刷新到主内存中去。2.这个写操作会导致其它线程中的缓存无效。3.volatile会禁止语义重排序。

java synchronized关键字

在java编程中,当可能存在多个线程同时访问一部分资源时,可能会出现一些访问冲突。为了解决冲突,java提供了synchronized关键值,通过加锁的方式,保证访问的有序性。 synchronized关键字的两种作用范围1.作用于对象. 12345678910public synchronized void method(){ //}等价写法public void method(){ synchronized(this){ ... }} 作用于对象可以防止多个线程同时访问该对象的sychronized方法。所以不同实例时不干扰的,也就是说,以该类创建的其它对象依然可以同时访问该sychronized方法。 2.作用于类 1234567891011public static synchronized void method(){ }等价写法:public void method(){ synchronized(Myclass.class){ ... }} 作用于类可以防止多个线程同时访问该类的实例的synchronized方法。所以该类的实例之间时存在干扰的。也就是说,该类创建的对象不能同时访问该synchronized方法了。

Java static关键字的几种用法

static关键字的几种用法 修饰成员变量,和方法 修饰内部类 修饰代码块 静态导包 修饰成员变量和方法static修饰的成员变量或方法属于类,不属于对象。所有该类的实例都共享一个变量或方法。放在内存的方法区 123456789101112131415161718192021public class JavaStatic { /** * 静态成员变量 */ private static int age; /** * 静态方法 */ private static void printName(){ System.out.println("Name"); } public static void main(String[] args) { /*静态成员变量或方法直接使用类名进行调用*/ System.out.println(JavaStatic.age); JavaStatic.printName(); }}

正则表达式

正则表达式中的字符分类普通字符普通字符包括没有显示指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母,所有数字,所有标点符号和一些其它符号。 非打印字符非打印字符也可以是正则表达式的一部分。 \cx \f \n \r \s \S \t \v 匹配由x指明的控制字符 匹配一个换页符 匹配一个换行符 匹配一个回车 匹配任何空白字符,入空格,制表符,换页符 匹配任何非空白字符 匹配以恶搞制表符 匹配一个垂直制表符 特殊字符特殊字符就是有特殊含义的字符。 $ () * + . [ ? \ ^ { | 匹配输入字符串的结尾位置 标记一个子表达式的开始和结束 匹配前面的子表达式零次货多次 匹配前面的子表达式一次或多次 匹配除换行符之外的任何单字符 标记一个中括号表达式的开始 匹配前面的子表达式零次或一次 将下一个字符标记为特殊字符、或原意字符、或向后应用、或八进制转义字符 匹配输入字符串的开始 标记限定符表达式的开始 表明在两项之间的一个选择

TCP三次握手和四次挥手

TCP报文的六个标志位 URG:紧急指针(urgent pointer)有效。 ACK:确认序号有效。 PSH:接收方应该尽快将这个报文交给应用层。 RST:重置连接。 SYN:发起一个新连接。 FIN:释放一个连接。 TCP三次握手 所谓三次握手(Three-Way Handshake)即建立TCP连接时,需要客户端和服务端总共发送3个包以确认连接的建立。 第一次握手Client将标志SYN置为1,随机产生一个值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server的确认信息。 第二次握手Server收到数据包后根据SYN=1可知Client请求建立连接,Server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认收到了连接请求,Server进入SYN_RCVD状态。 第三次握手Clinet收到确认后,检查ACK标志是否为1且ack是否为J+1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK是否为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client和Server之间就可以开始传输数据了。

1910111213