关于java core的一些知识

来源:互联网 发布:超人 知乎 编辑:程序博客网 时间:2022/05/27 13:40

我们常说计算机基础很重要。今天也来谈谈关于java的一些基础知识。其实java基础知识,thinking java无疑是一本非常值得读的书。java core设计到的范围也很广,下面讨论一些常用的java core的一些知识。由于java core知识太多,无法枚举。

下面是将要出现的一些知识:

1,String,StringBuilder,StringBuffer

2,ArrayList,LinkedList,Vector,LinkedBlockingQueue

3,HashMap,HashTable,TreeMap,ConcurrentHashMap

4,int,Integer等

第一个知识:


关于String,StringBuffer,StringBuilder这三个类是在java code中出现频率很高的。但是作者发现,即使是很多高级程序员都在乱用这些类。或许是早期的习惯所致,特别是StringBuffer和StringBuilder这两个类。可能是因为早期版本只有StringBuffer的原因,至今很多程序员都对他不离不弃。先说说这三个类的一些区别。

String,是一个final类,不可变对象。一旦声明了一个String对象,意味着其值不会改变。通常String有三种做法,一.String str = "abc" 。二,String str = new String("adc")。三,加号字符串拼接。这两种用法有非常大的区别。对于第一种用法,jvm会现在常量池中去找"abc"这个值,如果没有找到,会在堆中创建“adc”对象,然后把值返回常量池。所以这种申明会更节约内存,但是它也有限制,不能超过65534。估计在编码的时候没有人会写这么长的字符串定义。对于第二种用法,其实是申请了两个对象。括号里面的"abc"和之前的一样,然后new String会在堆里建一个对象。所以它是会每次都申请一块内存的。对于第三种情况,如果是两个常量字符串相加,如 String str = "ab"+"c",那么编译器会优化为String str = "abc".如果是变量相加,如String str="ab";String c = "c",str = str+c,(如果c是final修饰的会等同于之前的编译器优化情况),那么其本质是,+是一个StringBuilder的重载,也就相当于StringBuilder append 然后再toString()。呵呵,加号和StringBuilder一样,是否就一直应该用加号呢 ,方便?对于一个加号或连加的情况是可以的。对于在循环中用加号这就是一个悲剧,特别是循环的次数越多越悲剧。在循环中会在每次循环都new StringBuilder.这得产生多少中间变量呀,gc就频繁了。性能急剧下降。

StringBuilder和StringBuffer都是可变的字符串。不过StringBuffer是线程安全的。所以在栈封闭的情况下,不需要用它。直接用StringBuilder这个速度要快些。不会有锁的开销。这两者内部都是使用char数组,所以要动态扩容。两者的默认初始化容量都是char[16]。当容量不够的时候会扩到原来容量的二倍。所以能够预估容量的时候就给一个预估值,避免动态扩容。


第二个知识:


ArrayList的实现是动态数组,也就是容器是数组扩容的,这个和StringBuilder一样,所以能给预估值最好也给预估值。需要强调的是它不是线程安全的,不能在多线程环境种使用。数组的最大优势,他是连续存储的,查询快,在末尾插入和删除都快。但是如果要在中间或者数组首位插入和删除,需要移动这个元素后面的所有元素,所以性能不言自明。

Vector的实现也是动态数组,不过它每次扩容是原来容量的一半,它是线程安全的可以在多线程环境中使用。

LinkedList的实现是链表,就是指针和结构体。它是双向链表。也就是在每一个元素(除了首尾元素)都有前驱和后继。它是在存储上可以离散的,所以在插入的时候需要重新分配空间,然后调整指针指向,需要更多的内存来存指针。它的优势在于插入和删除对任何节点都是一样快。但是查询速度就要比动态数组慢。

LinkedBlockingQueue,这是一个线程安全的有边界队列(可以指定)。主要是要介绍一下它的一些阻塞用法,put是阻塞的一直要到队列到了边界以内才能插入。offer是立即返回的(也有等代多少时间直到可用的),如果不能插入了就返回false。同样对于的还有取数据,即删除数据,分别是take和poll与之对应。


对于第三个知识:

首先需要明白的是,无论什么hash,hash为访问速度而生的。hash是无序的,需要维持顺序需要额外的开销。

HashMap是采用hash算法,用LinkedList解决hash碰撞,到了默认扩容因子0.75会rehash。这是一个耗时的操作,所以在HashMap时,能预估容量的尽量预估,记住扩容因子默认是0.75这意味着你至少要把预估容量设置成实际容量的4/3倍,通常用1.6或3/2。理论上讲容量越大hash碰撞的机会就越小,那么线性查找的耗时就越少,hash的性能也就越高。需要强调的是HashMap是非线程安全的,再多线程环境用HashMap会产生严重的后果,如,cpu飚到100%。具体可以见 http://code.alibabatech.com/blog/dev_related_969/hashmap-result-in-improper-use-cpu-100-of-the-problem-investigated.html 非常详细。

HashTable是HashMap的一种安全实现,但是它并不高效,因为他锁住写请求(put remove)时会把所有的Entry都锁上,并且对于读也是加锁的。它也有容量和rehash问题。同上

ConcurretHashMap是HashTable的高效实现,同样不能有null的key出现,它之所以高效是因为它只对写请求加锁,并且只锁被写入的这个Entry的对应桶位,所以两个不相干的写入(写的不同位置)是可以并发写的。所以它是一种高效的实现。同样有容量的和rehash问题

TreeMap是红黑树的实现。红黑树是局部平衡的二叉树,是在插入和查询之间做的性能平衡。TreeMap是对key排序,所以key如果没有实现Comparator接口,就必须指定用于排序的Comparator实现。


对于第四个知识:

主要是想说明的是Integer i = [-128,127]是在常量池中命中对象。所以再对Integer上锁的时候要注意,有可能是一个全局锁。

原创粉丝点击