《编写高质量代码(改善Java程序的151个建议)》读书笔记(二)
第四章,字符串
52. 推存使用String直接量赋值,
Java为了避免在一个系统中产生大量的String对象,设计了一个字符串池(也称字符串常量池,String pool 或 String Constant Pool,存在于JVM常量池(Constant Pool)中),在字符串池中容纳的都是String对象,当创建一个字符串时,首先检查池中是否有字面值相等的字符串,有不在创建,直接返回池中该对象的引用,没有则创建,然后放到池中,返回新建对象的引用,所以当用“==”判断相等。当使用new String("") 时不会检查池,也不会放入池。不相等,intern方法(会检查池里,有返回)处理相等。String类是一个不可变(Immutable)的类,final不可继承,在String提供的方法中,如果返回字符串一般为新建的String对象,不对原对象进行修改。
53. 注意方法中传递的参数要求,replaceAll传递的是第一个参数为正则表达式。
54. 正确使用String ,StringBuffer , StringBuilder :
CharSequence接口有三个实现类:String , StringBuffer , StringBuilder ,
- String为不可改变量,修改要么创建新的字符串对象,要么返回自己(str.substring(0)),
- StringBuffer是一个可变字符序列,他与String一样,在内存中的都是一个有序的字符序列,不同点是值可以改变,
- StringBuilder 与 StringBuffer在性能上基本相同,都为可变字符序列。不同点为StringBuffer为线程安全的,而StringBuilder为线程不安全。
使用场景
:
- String:常量的声明,少量的变量运算。
- StringBuffer:频繁的字符串运算,多线程(xml,Http解析)。
- StringBuilder:频繁的字符串运算,单线程(SQL语句拼接)。
55. 注意字符串的位置:在+号处理中,String字符串具有最高的优先级。
56. 自由选择字符串拼接方式:
- 1,
“+”号拼接,时间最长
,等价于srt = StringBuilder(srt).append(“c”).toString(); - 2,
concat方法拼接,时间中等
,每次都会新建一个String对象; - 3,
append方法拼接字符串,时间最快,
只生成一个String对象。
57. 推存在复杂字符串操作中使用正则表达式来完成复杂处理。查找单词数,\b\w+\b
58. 强烈建议使用UTF编码。
59. 对字符串排序持一种宽容的心态,如果排序不是关键算法,用Collator类即可。
第五章,数组和集合
60. 性能考虑,数组是首选,集合类的底层都是通过数组实现的,基本类型在栈内存中操作的(速度快,容量小),而对象则是在堆内存中操作的(速度慢,容量大)。性能要求较高的时候用数组代替集合。
61. 若有必要,使用变长数组,
数组扩容:
public class demo {
public demo() {
// TODO Auto-generated constructor stub
}
public static <T> T[] expandpacity(T[] datas, int newLen) {
newLen = newLen<0?0:newLen;
return Arrays.copyOf(datas, newLen);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
demo []de= new demo[30];
de = expandpacity(de,60);
}
}
集合的长度自动维护功能的原理与此类似。
62. 警惕数组的浅拷贝,数组的copyOf方法产生的数组为一个浅拷贝,与序列化的浅拷贝相同,基本类型拷贝值, 其他拷贝地址,集合的clone方法也为浅拷贝,
- 浅拷贝(浅复制、浅克隆):被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。 换言之,浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。
- 深拷贝(深复制、深克隆):被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深拷贝把要复制的对象所引用的对象都复制了一遍。继承自java.lang.Object类的clone()方法是浅复制。
63. 在明确的场景下,为集合指定初始容量,ArrayList中java实现长度的动态管理。如果不设置初始容量,系统就按照1.5倍的规则扩充,每一次扩充都是一次数组拷贝。
public boolean add(E e) {
ensureCapacity(size + 1);//扩展长度。
elementData[size++] = e;//追加元素
return true;
}
public void ensureCapacity(int minCapacity){
modCount++;//修改计数器
int oldCapacity = elementData.length;//上次数组长度
if(minCapcity>oldCapacity) {
Object oldDate[] = elementDate;
//计算新数组长度。
int newCapacity = (oldCapacity*3)/2+1;
if(newCapacity<minCapacity)
newcapacity = minCapacity;
//数组拷贝,生成新数组
elementDate = Arrays.copyof(elementDate,newCapacity);
}
}
//并不是增加一个元素elementDate的长度就加1,而是在达到elementDate长度的临界点,才将elementDate元素扩充1.5倍。
//无参构造函数
public ArrayList() {
this(10);
}
//指定长度的有参构造函数
public ArrayList(int initialCapacity) {
super();
if(initialCapacity<0)
this.elementDate = new Object[initialCapacity];
}
vector的处理方式与ArrayList的长度处理相似,不同的地方是提供递增步长(capacityIncrement变量)。不设置容量翻倍。HashMap是按照倍数增加的。
64. 多种最值算法,适时选择,使用集合最简单,使用数组性能最优。
public static int max(int [] data) {
int max = data[0];
for(int i:data) {
max = max >i?max:i;
}
return max;
}//自行实现,速度最快
public static int max(int [] data) {
Arrays.sort(data.clone());
return data[data.length-1];
}//先排序后取值
//查找不重复的仅次于最大值的。
public static int getSecond(Integer[] data) {
List<Integer> dataList = Arrays.asList(data);//转换为列表
TreeSet<Intger> ts = new TreeSet<Integer>(dataList);//删除重复元素并升序排序,由TreeSet类实现。
return ts.lower(ts.last());//用lower获取小于最大值的值。
}
65. 避开基本类型数组转化为列表陷阱,原始数据类型数组不能做为asList的输入参数,否则会引起程序逻辑混乱。
public static void main(String[] args ){
int [] data = {1,2,3,4,5};
List<Integer> dataList= Arrays.asList(data);
System.out.println("列表中的元素个数为:"+list.size());
//asList方法输入的为泛型变长参数,在java中数组为一个对象,它是可以泛型化的,即把int型数组当做T的类型,所以转换后长度为1,调用getclass方法返回:class [I,jvm不能输出Arrays类型,因为Arrays是属于java.lang.reflect包的,它是通过反射访问数组元素的工具类,在java中任何一个数组的类都是“[I”数组类并没有定义,是在编译器编译时生成的,是一个特殊的类,
66. asList方法产生的List对象不可更给,
调用add方法会抛不支持的操作的异常,基于Arrays的ArrayList是一个静态私有内部类,除了Arrays能访问以外,其他类都不能访问,且add方法为ArrayList的父类提供,但是没有具体的实现,Arrays的内部类没有覆写add方法。
ArrayList静态内部类实现了5 个方法。s
ize(元素数量),toArray(转化为数组),get(获取指定元素),set(重置某一元素),container(是否包含某个元素),方法 ,没有实现add和remove方法,
即asList返回的为一个长度不可变的列表,数组为多长转换为列表为多长,即不在保持列表动态变长的特性。List<String>names = Arrays.asList("","","");不可取,列表长度不可修改;
package java_151;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.RandomAccess;
public class asList_Demo {
/*
* 报不支持 的操作异常, java.lang.UnsupportedOperationException
* List的
*/
enum Week {Sun,Mon,Tue,Wed,Thu,Fri,Sat}
public static void main(String[] args) {
// TODO Auto-generated method stub
Week[] workDays = {Week.Mon,Week.Tue,Week.Wed,Week.Thu,Week.Fri};
List<Week> list = Arrays.asList(workDays);
list.add(Week.Sat);
}
/*
* asList method 源码,直接new一个ArrayList对象并返回,
* 此ArrayList非java.util.ArrayList,而不是Arrays的工具类。
*/
public static <T> List<T>asList(T...a){
return new ArrayList<T>();
}
/*
* ArrayList类为Arrays的内置类,构造函数:为一个静态私有的内部类,没有提供add方法,即只能是
* AbstractList提供,但父类提供的add方法没有提供具体的实现,需要覆写。
*
*/
private static class ArrayList<E> extends AbstractList<E> implements
RandomAccess, Serializable{
private final E[];
ArrayList(E[] array){
if(array ==null) {
throw new NullPointerException();
}
a = array;
}
}
}
67.不同的列表选择不同的遍历方法,
对于 ArrayList数组for循环下标方式要比foreach遍历快,
对于LinkedList类讲,foreach方法要比fo循环方法快,
ArrayList数组为随机存取列表,LinkedList为有序存取列表(实现了双向链表,每个数据节点有三个数据项前节点引用(Previons),本节点元素(Node element),后继节点的引用(Next Node ))。ArrayList数组实现了RandomAccess接口(随机存取接口),即为一个随机存取的列表,数据元素之间没有关联,没有依赖和索引关系,
Java中,RandomAccess(随机存取)和Cloneble(可以拷贝)。Serializable(可以序列化)接口一样,为标志性接口,不需要任何实现,只是用来表明实现类具有某种性质,
java中foreach语句为iterator(迭代器)的变形使用
,即迭代器为23种设计模式的一种,提供一种方法访问一个容器中对象的各个元素,同时又无需暴露内部细节,对于ArrayList来讲,创建一个迭代器,然后屏蔽内部遍历细节,提供hasnext,next等方法,
package java_151;
import java.io.Serializable;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.RandomAccess;
public class asList_Demo {
public static void main(String[] args) {
int stuNum = 80*10000;
//实例化List集合,并指定初始容量。
List<Integer> scores = new ArrayList<Integer>(stuNum);
for(int i = 0; i <stuNum ;i++) {
//返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
scores.add(new Random().nextInt(150));
}
long start = System.currentTimeMillis();
System.out.println("平均分是:"+average(scores));
System.out.println("执行时间:"+(System.currentTimeMillis()-start)+"ms");
}
//foreach语句遍历
public static int average(List<Integer> list) {
int sum = 0;
for(int i:list) {
sum = sum+i;
}
return sum/list.size();
}
//下标遍历
public static int average(List<Integer> list) {
int sum = 0;
for(int i=0,size=list.size();i<size;i++) {
sum += list.get(i);
}
return sum/list.size();
/*
* foreach 原理
*/
for(Iterator<Integer>i = list.iterator();i.hasNext();) {
}
}
}
//适用用于有序存取列表和随机存取列表。
public static int average(List<Integer> list) {
int sum =0;
if(list instanceof RandomAccess) {
for(int i = 0,size = list.size();i<size;i++) {
sum += list.get(i);
}
}else {
for(int i:list) {
sum +=i;
}
}
return sum/list.size();
}
}
//LinkList 下标遍历法;
public E get(int index) {
return entry(index).element;
}
private Entry(E) entry( int index){
Entry<E> e = heder;
if(index < (size>>1)) {
for(int i =0 ; i<= index; i++)
e = e.next;
}else {
for(int i = size; i>index; i++) {
e = e.previous;
}
return e;
}
68.频繁插入和删除时使用LinkedList,
LinkedList的插入效率要比ArrayList快 50倍,删除要比ArrayList快40倍,修改要慢ArrayList许多,ArrayList在写操作时要慢Lnkedlist;
69.列表相等只需关心元素数据,
在java中,列表只是一个容器,只要是同一种类型的容器(List),不会关心容器的细微差(ArrayList和Kinkedlist两者都实现了LIst接口继承了AbstractList抽象类,equals方法在抽象类中定义。),只要确定所有元素数据,个数相等即可,Set,Map与此相同。判断集合是否相等,只需要判断元素是否相等。
public boolean equals(Object o) {
//是否为自身
if (o == this)
return true;
//是否为List的实现类,即是否为List列表
if (!(o instanceof List))
return false;
//返回列表元素的迭代器,访问所有的元素进行比较。
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
//当都为空不执行,一个为空false,都不为空equals比较。
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
//判断长度是否相等。
return !(e1.hasNext() || e2.hasNext());
}
70.子列表只是原列表的一个视图,
List提供一个subList方法,与String的subString有点类似,subList方法是由AbstractList实现的,它会根据是不是随机存储提供不同的实现方法,SubList返回的类也是AbstractList的子类,其所有的方法(get,add,set,remove等)都是在原始列表上操作的,它自身并没有生成一个数组或是链表,也就是子列表只是原列表的一个视图(View),所有的修改都反映在原列表上。
,
List <String> c = new ArrayList<String>();
c.add("A");
c.add("B");
List<String> c1 = new ArrayList<String>(c);
List<String> c2 = c.subList(0, c.size());
c2.add("C");
System.out.println("c==c1"+c.equals(c1));
System.out.println("c==c2"+c.equals(c2));
71.推存使用subList处理局部列表,
List<Integer> initate = Collections.nCopies(100, 0);
//public static <T> List<T> nCopies(int n, T o)
//返回由指定对象的 n 个副本组成的不可变列表。
List<Integer> list = new ArrayList<Integer>(initate);
//转换为可变列表。
//list.subList(20, 30).clear();
for(int i = 0,size=list.size();i<size;i++) {
if(i>=20&&i<30) {
list.remove(i);
}
}
72.生成子列表后不要在操作原列表
,操作抛出java.util.ConcurrentModificationException并发修改异常,因为subLis取出的列表只是原列表的一个视图,原数据集修改了,但是subList取出的子列表不会重新生成一个新列表,后面的对子列表继续操作时,就会检测到修改计数器与预期的不相同,会抛出并发修改异常,subList的其他方法也会检测修改计数器,例如Set,get,add方法,如果生成子列表在操作原列表,必然会导致视图不稳定,有效的办法是通过Collections.unmodifiableList方法设置列表为只读状态当有多个字列表时,任何一个子列表就都不能修改啦。生成子列表后,原列表保持只读状态。防御式编程。
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
List<String>subList = list.subList(0, 2);
list.add("D");
System.out.println("原列表的长度:"+list.size());
System.out.println("子列表偶的长度:"+subList.size());
抛出异常:Exception in thread "main" java.util.ConcurrentModificationException;
//设置列表为只读状态。
List<String>list = new ArrayList<String>();
List<String> subList = list.subList(0, 2);
//unmodifiableList(List<?y extends T> list)
//返回指定列表的不可修改视图。
list = Collections.unmodifiableList(list);
73.使用Comparator进行排序,
在java中,要想给数据进行排序,有两种事项方式,一种为实现Comparable接口,一种是实现Comparator接口,
public interface Comparable<T>
此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
int compareTo(T o)比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
@FunctionalInterface
public interface Comparator<T>
比较功能,对一些对象的集合施加了一个整体排序 。 可以将比较器传递给排序方法(如Collections.sort或Arrays.sort ),以便对排序顺序进行精确控制。 比较器还可以用来控制某些数据结构(如顺序sorted sets或sorted maps ),或对于不具有对象的集合提供的排序natural ordering ,与Comparable不同,比较器可以可选地允许比较空参数,同时保持对等价关系的要求。
int compare(T o1, T o2) 比较其两个参数的顺序。
package com.liruilong;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* @Description : 集合排序整理
* @Author: Liruilong
* @Date: 2019/7/31 22:21
*/
public class Compara implements Comparable<Compara>{
private Integer data;
public Integer getData() {
return data;
}
public void setData(Integer data) {
this.data = data;
}
/**
* @Author Liruilong
* @Description public interface Comparable<T>
* 此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,
* 类的 compareTo 方法被称为它的自然比较方法。
* 实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。
* 实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
* int compareTo(T o)比较此对象与指定对象的顺序。
* 如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。
* @Date 22:54 2019/7/31
* @Param [o]
* @return int
**/
@Override
public int compareTo(Compara o) {
// (x == 1) ? -1 : ((x == 2) ? 0 : ((x == 3) ? 1:((x == 4) ? 3 : ))) 代替 if -else if。
return (this.data < o.data) ? -1 : ((this.data == o.data) ? 0: 1);
}
public interface Comparator<T> {
int compare(T o1, T o2);
}
public static void main(String[] args) {
List<Compara> comparaList = new ArrayList<>();
//方法一 集合元素实现了Comparable 接口,直接用工具类排序
Collections.sort(comparaList);
// 方法二 在排序时将比较器传入
Collections.sort(comparaList, (Compara o1, Compara o2) ->o1.compareTo(o2) );
//方法三,通过Comparator传入一个比较器
comparaList.sort((Compara o1,Compara o2) ->o1.compareTo(o2));
comparaList.sort(new java.util.Comparator<Compara>() {
/**
* @Author Liruilong
* @Description 针对一些本身没有比较能力的对象(数组)为它们实现比较的功能,
* 所以它叫做比较器,是一个外部的东西,通过它定义比较的方式,
* 再传到Collection.sort()和Arrays.sort()中对目标排序,
* 而且通过自身的方法compare()定义比较的内容和结果的升降序;
* @Date 23:16 2019/7/31
* @Param [o1, o2]
* @return int
**/
@Override
public int compare(Compara o1, Compara o2) {
if (o1.getData()== o2.getData()){
return 0;
}else if(o1.getData() < o2.getData()) {
return -1;
}else {
return 1;
}
}
});
}
}
74.不推存使用binarySearch对队列进行检索
。一般使用indexOf方法进行检索,binarySearch使用二分搜索法搜索指定列表,以获得指定的对象,二分法查询,数据要已经实现了升序排序。但是binarySearch在性能上要比indexOf好。
75.集合中的元素必须 做到compareTo和equals同步:实现了Comparable接口的元素就可以排序,compareTo方法是Comparable接口要求必须实现的。当返回0时,表示进行比较的两个元素是相等的,indexOf检索方法是通过equals方法判断的,binarySearch则依赖compare方法查找,不懂?????
76.集合运算时使用更优雅的方式,并集,交集,差集。
List<String> list1 = new ArrayList<>();
list1.add("A");
list1.add("B");
List<String> list2 = new ArrayList<>();
list2.add("C");
list2.add("D");
//并集
list1.addAll(list2);
//交集
list1.retainAll(list2);
list1.removeAll(list2);
//无重复的并集
list2.removeAll(list1);
list1.addAll(list2);
77.使用shuffle打乱列表,
int tagCloudNum = 10;
List<String> tagClouds = new ArrayList<String>(tagCloudNum);
Random random = new Random();
for(int i = 0;i <tagCloudNum;i++) {
//获取随机位置;
int randPotion = random.nextInt(tagCloudNum);
//当前元素与随机位置元素交换。
String temp = tagClouds.get(i);
tagClouds.set(i, tagClouds.get(randPotion));
tagClouds.set(randPotion, temp);
}
int tagCloudNum = 10;
List<String> tagClouds = new ArrayList<String>(tagCloudNum);
Random random = new Random();
for(int i = 0;i <tagCloudNum;i++) {
int randPotion = random.nextInt(tagCloudNum);
//当前元素与随机位置元素交换。
Collections.swap(tagClouds, i, randPotion);
}
int tagCloudNum = 10;
List<String> tagClouds = new ArrayList<String>(tagCloudNum);
Collections.shuffle(tagClouds);
78.减少HashMap中的元素的数量
HashMap在底层也是以数组的方式保存元素的,每一个键值对就是一个元素,HashMap把键值对封装为Entry对象,然后把Entry放到数组中,HashMap的底层数组变量为table,是Entry类型的数组,保存一个一个的键值对,HashMap也可以动态的增加,大于等于阈值,数组增大一倍,阈值为当前长度与加载因子的乘机,默认加载因子为 0.75,即HashMap的size大于等于数组长度的0.75倍,就开始扩容。
79.集合中的哈希码不要重复
随机存取的列表是遍历查找,顺序存储列表是链表查找,或者Collections的二分法查找,HashMap等set集合要快于List集合,HashMap每次增加元素都会先计算器哈希码,然后使用hash方法再次对hashCode进行抽取和统计,同时兼顾哈希码的高位和低位的信息产生唯一值,之后通过indexFor方法与数组长度做一次与运算,计算数组位置,hash的方法和iindexFor方法就是把哈希码转化为数组,
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
final Node<K,V> getNode(int hash, Object key) {
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
if ((tab = table) != null && (n = tab.length) > 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash && // always check first node
((k = first.key) == key || (key != null && key.equals(k))))
return first;
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
do {
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
return null;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int size = 10000;
List<String> list = new ArrayList<String>(size);
for(int i = 0;i < size; i++) {
list.add("value"+i);
}
long statc = System.nanoTime();
//开始查找
list.contains("value"+(size-1));
long end = System.nanoTime();
System.out.println("List时间为:"+(end-statc)+"ns");
//Map 的查找时间
Map map = new HashMap<String, String>(size);
for(int i = 0;i < size; i++) {
map.put("key"+i, "value"+i);
}
statc = System.nanoTime();
//开始查找
map.containsKey("key"+(size-1));
end = System.nanoTime();
System.out.println("Map 时间为:"+(end-statc)+"ns");
}
80.多线程使用Vector或HashTable,
Vector是ArrayList的多线程版本,HashTable是HashMap的多线程版本,线程安全和同步修改异常是两个概念,基本上所有集合类都有一个叫做快速失败的校验机制(Ffail-Fast),当一个集合在被多个线程修改并访问时,就可能会出现ConcurrentModificationException 异常,这是为了确保集合方法一致设置对的保护措施,实现原理为modCount修改统计器,当读取列表是发生变化(其他线程也在操作),则会抛出异常,也与 线程同步不同,线程同步是为了保护数据不被脏写,脏读而设置的,Vector的每个方法都加上了synchronized,两个线程进行同样的操作才可以讨论线程同步,一个线程删除一个线程增加,不属于多线程范畴。
package java_151;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Vector {
public static void main(String[] args) {
//火车票列表
final List<String>tickets = new ArrayList<String>();
//线程安全:final Vector<String>tickets = new Vector<String>();
//初始化数据池,
for(int i = 0; i < 10000 ;i++) {
tickets.add("火车票"+i);
}
//退票
Thread returnThread = new Thread() {
public void rnu() {
while(true) {
tickets.add("车票"+new Random().nextInt());
}
}
};
//售票
Thread saleThread = new Thread() {
public void run() {
for(String ticket:tickets)
tickets.remove(ticket);
}
};
//启动退票线程
returnThread.start();
saleThread.start();
}
}
Exception in thread "Thread-1" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:937)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:891)
at java_151/java_151.Vector$2.run(Vector.java:28)
//10个窗口售票
for(int i=0; i <10 ; i++) {
new Thread() {
public void run() {
while(true) {
System.out.println(Thread.currentThread().getId()+"---"+tickets.remove(0));
}
};
}.start();
}
//为线程同步问题
81.非稳定排序推:
存使用List,Set与List的最大区别为Set中的元素不可以重复(基于equals的返回值),Set的实现类有一个比较常用的类TreeSet,该类实现了类默认排序为升序Set集合,插入一个元素,默认按照升序排序,SortedSet(TreeSet实现了该接口)接口只是定义了在给集合加入元素时将其进行排序,不能保证修改后的排序结果。所以TreeSet适合不变量的集合数据排序。Sstring或Integer等
82.由点几面,集合大家族:
-
`List:实现List的集合主要有ArrayList(动态数组),LinkedList(双向链表),Vector(线程安全的动态数组),Stack(对象栈,先进后出)。
-
Set: 不包含重复元素的集合,其主要的实现类有:EnumSet(枚举类型专用,所有为枚举类型),HashSet(以哈希码决定元素位置,与HashMap相似,提供快速插入和查找),TreeSet(自动排序Set,实现了SortedSet接口)
-
Map:分为排序Map和非排序Map,排序Map主要是TreeMap类,根据Key值进行自动排序,非排序Map主要包括:HashMap,HsahTable,Properties,EnumMap等,其中Properties是HashTable的子类,它的主要用途从property文件中加载数据,并提供方便的读写操作:EnumMap则要求Key必须为某一个枚举类型。Map中还有一个weakHashMap类,采用弱键方式实现的Map类,WeakHashMap对象的存在并不会阻止垃圾回收器对键值对的回收,即不用担心内存溢出问题。
-
Query:队列,分为阻塞式队列和非阻塞式队列,阻塞式队列主要包括:ArrayBlockingQuery(以数组方式实现的有借阻塞数组),PrinonityBoockingQuery(依照优先级组建的队列),LinkedBlockingQuery(通过链表实现的阻塞队列),非阻塞式队列,PrinonityQuery类.
-
数组:数组与集合的最大区别就是数组能够容纳基本类型,而集合不行,且数组为非动态,集合的底层都是数组。
-
工具类:数组的工具类时java.util.Arrays和java.lang.reflect.Array,集合的工具类是java.util.Collections.
- 点赞
- 收藏
- 关注作者
评论(0)