- 集合和数组的区别:
- 请你列出你常用的集合框架中的类与接口(Java集合框架的基础接口有哪些?)
- Collection方法
- List,Set,Map三者的区别?
- List:存取有序、可重复
- Set:存取无序,不包含重复元素
- Map:键值对
- 迭代器 Iterator 是什么?
- Iterator 和 ListIterator 有什么区别?
- 遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么?
- 说一下 ArrayList 的优缺点
- ArrayList 和 LinkedList 的区别是什么?
- ArrayList 和 Vector 的区别是什么?
- 插入数据时,ArrayList、LinkedList、Vector谁速度较快?阐述 ArrayList、Vector、LinkedList 的存储性能和特性?
- 为什么要重写equals和hashcode方法?
- HashSet与TreeSet的区别
- HashSet
- TreeSet
- 区别
- HashSet与HashMap的区别
- Collection 和 Collections 有什么区别?
- HashMap 与 HashTable 有什么区别?
集合和数组的区别:
- 数组是固定长度的;集合可变长度的。
- 数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型。
- 数组存储的元素必须是同一个数据类型;集合存储的对象可以是不同数据类型。
请你列出你常用的集合框架中的类与接口(Java集合框架的基础接口有哪些?)
Map接口和Collection接口是所有集合框架的父接口:
- Collection接口的子接口包括:Set接口和List接口
- List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等
- Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等
- Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等
Collection集合常用方法:
boolean add(E e):添加元素
boolean remove(Object o):从集合中移除指定的元素
void clear():清空集合中的元素
boolean contains(Object o):判断集合中是否存在指定的元素
boolean isEmpty():判断集合是否为空
int size():集合的长度,也就是集合中元素的个数
package 集合;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionDemo01 {
public static void main(String[] args) {
//创建Collection集合的对象
Collection c = new ArrayList();
//boolean add(E e):添加元素
c.add("hello");
c.add("world");
c.add("java");
System.out.println(c);//[hello, world, java]
System.out.println("------------------------------");
//boolean remove(Object o):从集合中移除指定的元素
System.out.println(c.remove("world"));//true
System.out.println(c.remove("javaee"));//false
System.out.println(c);//[hello, java]
System.out.println("------------------------------");
//void clear():清空集合中的元素
c.clear();
System.out.println(c);//[]
System.out.println("------------------------------");
//boolean contains(Object o):判断集合中是否存在指定的元素
c.add("hh");
c.add("oo");
c.add("java");
System.out.println(c.contains("world"));//false
System.out.println(c.contains("java"));//true
System.out.println("------------------------------");
//boolean isEmpty():判断集合是否为空
System.out.println(c.isEmpty());//false
System.out.println("------------------------------");
//int size():集合的长度,也就是集合中元素的个数
System.out.println(c.size());//3
//输出集合对象
System.out.println(c);//[hh, oo, java]
System.out.println("------------------------------");
//Iterator iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到
Iterator it = c.iterator();
//E next():返回迭代中的下一个元素
System.out.println(it.next());//hh
System.out.println(it.next());//oo
System.out.println(it.next());//java
//System.out.println(it.next());//NoSuchElementException:表示被请求的元素不存在
System.out.println("------------------------------");
//boolean hasNext():如果迭代具有更多元素,则返回 true
//用while循环改进判断
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
}
}
List,Set,Map三者的区别?
-
Collection集合主要有List和Set两大接口
-
List:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector。
-
Set:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet。
-
Map是一个键值对集合,存储键、值和之间的映射。 Key无序,唯一;value 不要求有序,允许重复。Map没有继承于Collection接口,从Map集合中检索元素时,只要给出键对象,就会返回对应的值对象。
Map的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap
List集合特有方法:
void add(int index,E element):在此集合中的指定位置插入指定的元素
E remove(int index):删除指定索引处的元素,返回被删除的元素
E set(int index,E element):修改指定索引处的元素,返回被修改的元素
E get(int index):返回指定索引处的元素
package 集合.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo01 {
public static void main(String[] args) {
//创建集合对象
List list = new ArrayList();
//添加元素
list.add("hello");
list.add("world");
list.add("java");
list.add("world");
//输出集合对象
System.out.println(list);//[hello, world, java, world]
System.out.println("------------------------------");
//迭代器的方式遍历
Iterator it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
System.out.println("------------------------------");
//void add(int index,E element):在此集合中的指定位置插入指定的元素
list.add(1,"add");
System.out.println(list);//[hello, add, world, java, world]
System.out.println("------------------------------");
//IndexOutOfBoundsException
//list.add(11,"addout");
//System.out.println(list);
//System.out.println("------------------------------");
//E remove(int index):删除指定索引处的元素,返回被删除的元素
System.out.println(list.remove(1));
System.out.println(list);//[hello, world, java, world]
System.out.println("------------------------------");
//IndexOutOfBoundsException
//System.out.println(list.remove(11));
//System.out.println(list);//[hello, add, world, java, world]
//System.out.println("------------------------------");
//E set(int index,E element):修改指定索引处的元素,返回被修改的元素
System.out.println(list.set(1,"repair"));//word
System.out.println("------------------------------");
//IndexOutOfBoundsException
//System.out.println(list.set(11,"javaee"));
//System.out.println("------------------------------");
//E get(int index):返回指定索引处的元素
System.out.println(list.get(1));//repair
System.out.println("------------------------------");
//IndexOutOfBoundsException
//System.out.println(list.get(11));
//System.out.println("------------------------------");
//输出集合对象
System.out.println(list);//[hello, repair, java, world]
System.out.println("------------------------------");
//遍历集合
System.out.println(list.get(0));//hello
System.out.println(list.get(1));//repair
System.out.println(list.get(2));//java
System.out.println("------------------------------");
//用for循环改进遍历
for (int i=0; i
String s = list.get(i);
System.out.println(s);
}
System.out.println("------------------------------");
//遍历集合,得到每一个元素,看有没有"world"这个元素,
for(int i=0; i
String s = list.get(i);
if(s.equals("world")) {
list.add("add");
}
}
System.out.println(list);//[hello, repair, java, world, add]
}
}
Set:存取无序,不包含重复元素
package 集合.Set;
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
//创建集合对象
Set set = new HashSet();
//添加元素
set.add("hello");
set.add("world");
set.add("java");
//不包含重复元素的集合
set.add("world");
//遍历
for(String s : set) {
System.out.println(s);
}
}
}
Map:键值对
package 集合.Map;
import java.util.HashMap;
import java.util.Map;
public class MapDemo01 {
public static void main(String[] args) {
//创建集合对象
Map map = new HashMap();
//V put(K key, V value) 将指定的值与该映射中的指定键相关联
map.put("001","hh1");
map.put("002","hh2");
map.put("003","hh3");
map.put("003","hh4");
//输出集合对象
System.out.println(map);//{001=hh1, 002=hh2, 003=hh4}
}
}
Map集合的基本功能:
V put(K key,V value):添加元素
V remove(Object key):根据键删除键值对元素
void clear():移除所有的键值对元素
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值(自学)
boolean isEmpty():判断集合是否为空
int size():集合的长度,也就是集合中键值对的个数
Map集合的获取功能:
V get(Object key):根据键获取值
Set keySet():获取所有键的集合
Collection values():获取所有值的集合
Map集合的遍历1:
1:获取所有键的集合。用keySet()方法实现
2:遍历键的集合,获取到每一个键。用增强for实现
3:根据键去找值。用get(Object key)方法实现
//获取所有键的集合。用keySet()方法实现 SetkeySet = map.keySet(); //遍历键的集合,获取到每一个键。用增强for实现 for (String key : keySet) { //根据键去找值。用get(Object key)方法实现 String value = map.get(key); System.out.println(key + "," + value); }
Map集合的遍历2:
1:获取所有键值对对象的集合
Set> entrySet():获取所有键值对对象的集合
2:遍历键值对对象的集合,得到每一个键值对对象
用增强for实现,得到每一个Map.Entry
3:根据键值对对象获取键和值
用getKey()得到键
用getValue()得到值
//获取所有键值对对象的集合
Set> entrySet = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry me : entrySet) {
//根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "," + value);
}
代码练习
package 集合.Map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo02 {
public static void main(String[] args) {
//创建集合对象
Map map = new HashMap();
//V put(K key,V value):添加元素
map.put("001","hh1");
map.put("002","hh2");
map.put("003","hh3");
//V remove(Object key):根据键删除键值对元素
System.out.println(map.remove("001"));//hh1
System.out.println(map.remove("001"));//null
System.out.println("-------------------------------");
//void clear():移除所有的键值对元素
map.clear();
System.out.println(map);//{}
System.out.println("-------------------------------");
//boolean containsKey(Object key):判断集合是否包含指定的键
map.put("001","hh1");
map.put("002","hh2");
map.put("003","hh3");
System.out.println(map.containsKey("002"));//true
System.out.println(map.containsKey("001"));//true
System.out.println("-------------------------------");
//boolean isEmpty():判断集合是否为空
System.out.println(map.isEmpty());//false
System.out.println("-------------------------------");
//int size():集合的长度,也就是集合中键值对的个数
System.out.println(map.size());//3
System.out.println("-------------------------------");
//Collection values():获取所有值的集合
Collection values = map.values();
for(String value : values) {
System.out.println(value);
}
System.out.println("-------------------------------");
//获取所有键的集合。用keySet()方法实现
Set keySet = map.keySet();
//遍历键的集合,获取到每一个键。用增强for实现
for (String key : keySet) {
//根据键去找值。用get(Object key)方法实现
String value = map.get(key);
System.out.println(key + "," + value);
}
System.out.println("-------------------------------");
//获取所有键值对对象的集合
Set> entrySet = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for (Map.Entry me : entrySet) {
//根据键值对对象获取键和值
String key = me.getKey();
String value = me.getValue();
System.out.println(key + "," + value);
}
}
}
迭代器 Iterator 是什么?
Iterator 接口提供遍历任何 Collection 的接口。
Iterator
Iterator中的常用方法
E next():返回迭代中的下一个元素
boolean hasNext():如果迭代具有更多元素,则返回 true
ListIterator 和 ListIterator 有什么区别?list = new ArrayList<>(); Iterator it = list. iterator(); while(it. hasNext()){ String s = it. next(); System. out. println(s); }
- Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
- Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
- ListIterator 实现 Iterator 接口,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
ListIterator:列表迭代器 通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器
用于允许程序员沿任一方向遍历列表的列表的迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
ListIterator中的常用方法 E next():返回迭代中的下一个元素 boolean hasNext():如果迭代具有更多元素,则返回 true E previous():返回列表中的上一个元素 boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true void add(E e):将指定的元素插入列表
package 集合.List;
import java.util.LinkedList;
public class LinkedListDemo {
public static void main(String[] args) {
//创建集合对象
LinkedList linkedList = new LinkedList();
linkedList.add("hello");
linkedList.add("world");
linkedList.add("java");
// public void addFirst(E e):在该列表开头插入指定的元素
// public void addLast(E e):将指定的元素追加到此列表的末尾
linkedList.addFirst("addfirst");
System.out.println(linkedList);//[addfirst, hello, world, java]
System.out.println("-------------------------");
linkedList.addLast("addlast");
System.out.println(linkedList);//[addfirst, hello, world, java, addlast]
System.out.println("-------------------------");
// public E getFirst():返回此列表中的第一个元素
// public E getLast():返回此列表中的最后一个元素
System.out.println(linkedList.getFirst());//addfirst
System.out.println(linkedList.getLast());//addlast
System.out.println("-------------------------");
// public E removeFirst():从此列表中删除并返回第一个元素
// public E removeLast():从此列表中删除并返回最后一个元素
System.out.println(linkedList.removeFirst());//addfirst
System.out.println(linkedList.removeLast());//addlast
System.out.println("-------------------------");
System.out.println(linkedList);//[hello, world, java]
}
}
遍历一个 List 有哪些不同的方式?每种方法的实现原理是什么?Java 中 List 遍历的最佳实践是什么?
- for 循环遍历,基于计数器。在集合外部维护一个计数器,然后依次读取每一个位置的元素,当读取到最后一个元素后停止。
- 迭代器遍历,Iterator。Iterator 是面向对象的一个设计模式,目的是屏蔽不同数据集合的特点,统一遍历集合的接口。Java 在 Collections 中支持了 Iterator 模式。
- foreach 循环遍历。foreach 内部也是采用了 Iterator 的方式实现,使用时不需要显式声明 Iterator 或计数器。优点是代码简洁,不易出错;缺点是只能做简单的遍历,不能在遍历过程中操作数据集合,例如删除、替换。
//迭代器:集合特有的遍历方式
Iterator it = list.iterator();
while (it.hasNext()) {
Student s = it.next();
System.out.println(s.getName()+","+s.getAge());
}
System.out.println("--------");
//普通for:带有索引的遍历方式
for(int i=0; i
Student s = list.get(i);
System.out.println(s.getName()+","+s.getAge());
}
System.out.println("--------");
//增强for:最方便的遍历方式
for(Student s : list) {
System.out.println(s.getName()+","+s.getAge());
}
说一下 ArrayList 的优缺点
- ArrayList的优点:
ArrayList 底层以数组实现,是一种随机访问模式。ArrayList 实现了 RandomAccess 接口,因此查找的时候非常快。
ArrayList 在顺序添加一个元素的时候非常方便。 - ArrayList 的缺点:
删除元素的时候,需要做一次元素复制操作。如果要复制的元素很多,那么就会比较耗费性能。
插入元素的时候,也需要做一次元素复制操作,缺点同上。
ArrayList 比较适合顺序添加、随机访问的场景
- 数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
- 随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
- 增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList 增删操作要影响数组内的其他数据的下标。
- 内存空间占用:LinkedList 比 ArrayList 更占内存,因为 LinkedList 的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。
- 线程安全:ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。
- 这两个类都实现了 List 接口(List 接口继承了 Collection 接口),他们都是有序集合
- 线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
- 性能:ArrayList 在性能方面要优于 Vector。
- 扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。
- Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。
- Arraylist不是同步的,所以在不需要保证线程安全时时建议使用Arraylist。
- ArrayList和Vector 底层的实现都是使用数组方式存储数据。数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢。
- Vector 中的方法由于加了 synchronized 修饰,因此 Vector 是线程安全容器,但性能上较ArrayList差。
- LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但插入数据时只需要记录当前项的前后项即可,所以 LinkedList 插入速度较快。
先通过hashcode方法返回的值,直接定位元素应该存储的物理位置,位置上没有元素则存放,若有元素,再比较对象的equals方法,从而大大减少equals方法调用,提高比较效率。
- hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。
-
如何获取哈希值
Object类中的public int hashCode():返回对象的哈希码值,返回的就是根据对象的内存地址换算出的一个值 -
对象的哈希值特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同 -
为什么要有 hashCode
-
我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode: 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来 判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。 但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。 如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
hashCode()与equals()的相关规定
- 如果两个对象相等,则hashcode一定也是相同的
- 两个对象相等,对两个对象分别调用equals方法都返回true
- 两个对象有相同的hashcode值,它们也不一定是相等的
因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
package 集合.Set;
import 集合.StudentTest;
import 面向对象.Student;
public class HashDemo {
public static void main(String[] args) {
//创建学生对象
StudentTest s1 = new StudentTest("hashcode",30);
//同一个对象多次调用hashCode()方法返回的哈希值是相同的
System.out.println(s1.hashCode()); //1163157884
System.out.println(s1.hashCode()); //1163157884
System.out.println("--------");
StudentTest s2 = new StudentTest("hashcode",30);
//默认情况下,不同对象的哈希值是不相同的
//通过方法重写,可以实现不同对象的哈希值是相同的
System.out.println(s2.hashCode()); //1956725890
System.out.println("--------");
System.out.println("hello".hashCode()); //99162322
System.out.println("world".hashCode()); //113318802
System.out.println("java".hashCode()); //3254818
System.out.println("world".hashCode()); //113318802
System.out.println("--------");
System.out.println("重地".hashCode()); //1179395
System.out.println("通话".hashCode()); //1179395
}
}
HashSet与TreeSet的区别
HashSet
HashSet集合特点
- 底层数据结构是哈希表
- 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以是不包含重复元素的集合
HashSet 集合保证元素唯一性的原理
- 根据对象的哈希值计算存储位置
- 如果当前位置没有元素则直接存入
- 如果当前位置有元素存在,则进入第二步
- 当前元素的元素和已经存在的元素比较哈希值
- 如果哈希值不同,则将当前元素进行存储
- 如果哈希值相同,则进入第三步
- 通过 equals() 方法比较两个元素的内容
- 如果内容不相同,则将当前元素进行存储
- 如果内容相同,则不存储当前元素
package 集合.Set;
import java.util.HashSet;
public class HashSetDemo01 {
public static void main(String[] args) {
//创建集合对象
HashSet hs = new HashSet();
//添加元素
hs.add("hello");
hs.add("world");
hs.add("hashset");
hs.add("world");
//遍历
for(String s : hs) {
System.out.println(s);
}
}
}
TreeSet
- 元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法
- TreeSet():根据其元素的自然排序进行排序
- TreeSet(Comparator comparator) :根据指定的比较器进行排序
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以不包含重复元素的集合
package 集合.Set;
import 集合.StudentTest;
import 面向对象.Student;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetDemo01 {
public static void main(String[] args) {
//创建集合对象
TreeSet ts = new TreeSet();
//添加元素
ts.add(10);
ts.add(40);
ts.add(30);
ts.add(50);
ts.add(20);
ts.add(30);
//遍历集合
for(Integer i : ts) {
System.out.println(i);
}
//创建集合对象
TreeSet ts2 = new TreeSet();
//创建学生对象
StudentTest s1 = new StudentTest("hh1", 1);
StudentTest s2 = new StudentTest("hh2", 2);
StudentTest s3 = new StudentTest("hh3", 5);
StudentTest s4 = new StudentTest("hh4", 2);
StudentTest s5 = new StudentTest("hh5",2);
StudentTest s6 = new StudentTest("hh6",2);
//把学生添加到集合
ts2.add(s1);
ts2.add(s2);
ts2.add(s3);
ts2.add(s4);
ts2.add(s5);
ts2.add(s6);
//遍历集合
for (StudentTest s : ts2) {
System.out.println(s.getName() + "," + s.getAge());
}
}
}
区别
区别一:
-
TreeSet 是二叉树实现的,Treeset中的数据是要求泛型对象实现自然顺序或自定义排序,不允许放入null值。
-
HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
区别二:
-
HashSet要求放入的对象重写equals()、hashCode()方法,对象放入集合中首先是以hashcode码作为标识。
-
TreeSet判断两个对象不相等的方式是通过排序实现
- 自然排序
comparable接口实际上是出自java.lang包,它有一个 compareTo(Object obj)方法用来排序。
自然排序要实现Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。obj1.compareTo(obj2),若返回0,则说明被比较的两个对象相等,若返回一个正数,则表明obj1大于obj2,若返回负数,则表明obj1小于obj2。
- 自然排序
@Override
public int compareTo(StudentTest s) {
// return 0;
// return 1;
// return -1;
//按照年龄从小到大排序
int num = this.age - s.age;
// int num = s.age - this.age;
//年龄相同时,按照姓名的字母顺序排序
int num2 = num==0?this.name.compareTo(s.name):num;
return num2;
}
- 自定义排序
comparator接口实际上是出自 java.util 包,它有一个compare(Object obj1, Object obj2)方法用来排序。
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法。
//创建集合对象
TreeSet ts3 = new TreeSet(new Comparator() {
@Override
public int compare(Student s1, Student s2) {
//this.age - s.age
//s1,s2
int num = s1.getAge() - s2.getAge();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return num2;
}
});
HashSet与HashMap的区别
| HashMap | HashSet |
|---|---|
| 实现了Map接口 | 实现Set接口 |
| 存储键值对 | 仅存储对象 |
| 调用put()向map中添加元素 | 调用add()方法向Set中添加元素 |
| HashMap使用键(Key)计算Hashcode | HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false |
| HashMap相对于HashSet较快,因为它是使用唯一的键获取对象 | HashSet较HashMap来说比较慢 |
- java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
- Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
Collections类:是针对集合操作的工具类 Collections类的常用方法: public staticHashMap 与 HashTable 有什么区别?> void sort(List list):将指定的列表按升序排序 public static void reverse(List> list):反转指定列表中元素的顺序 public static void shuffle(List> list):使用默认的随机源随机排列指定的列表
- 线程安全: HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap );
- 效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它;(如果你要保证线程安全的话就使用 ConcurrentHashMap );
- 对Null key 和Null value的支持: HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛NullPointerException。
- 初始容量大小和每次扩充容量大小的不同:
创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。
创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小。 - 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。



