java容器总结
容器分类:
容器与集合的相似点:
- 都可以存储多个对象,对外作为一个整体。
数组的缺点:
- 长度必须在初始化时指定,固定不变。
- 采用连续存储空间,删除和添加效率低下。
- 数组无法直接保存映射关系。
- 数组缺乏封装,操作繁琐。
集合架构
- collection接口存储一组不唯一无序的对象
- List接口存储不唯一、有序(索引顺序)的对象
- set接口存储一组唯一、无序的对象
- map接口存储一组键值对象,提供key到value的映射。key唯一无序,value不唯一无序。
List
-
特点:有序、不唯一。
-
ArrayList线性表中的顺序表:
- 内存中分配连续的空间,长度可变的数组。
- 优点:遍历元素和随机访问元素的效率高
- 缺点:添加、删除、需要大量的移动元素效率低。
public class SxtArrayList01 {
private Object[] elementData;
private int size;
private static final int DEFALT_CAPACITY = 10 ;
public SxtArrayList01(){
elementData = new Object[DEFALT_CAPACITY];
}
public SxtArrayList01(int capacity) {
elementData = new Object[capacity];
}
public void add(Object obj){
elementData[size++] = obj;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
//[a,b,c]
sb.append("[");
for(int i=0;i<size;i++){
sb.append(elementData[i]+",");
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) {
SxtArrayList01 s1 = new SxtArrayList01(20);
s1.add("aa");
s1.add("bb");
System.out.println(s1);
}
}
-
LinkedList线性表中双向链表:
- 采用双向链表存储
- 缺点:遍历和随机访问效率低
- 优点:插入、删除效率高
-
List常用方法:
相对collection增加了关于位置的操作方法。 -
List遍历方法:
- for、foreach、迭代器。
- 使用equals进行集合内容的比较
public class SxtLinkedList01 {
private Node first;
private Node last;
private int size;
public void add(Object obj) {
Node node = new Node(obj);
if(first==null){
// node.previous = null;
// node.next = null;
first = node;
last = node;
}else{
node.previous = last;
node.next = null;
last.next = node;
last = node;
}
}
@Override
public String toString() {
//[a,b,c] first=a, last=c
//a,b,c
StringBuilder sb = new StringBuilder("[");
Node temp = first;
while(temp!=null){
sb.append(temp.element+",");
temp = temp.next;
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) {
SxtLinkedList01 list = new SxtLinkedList01();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
System.out.println(list);
}
}
定义节点:
public class Node {
Node previous; //上一个节点
Node next; //下一个节点
Object element; //元素数据
public Node(Node previous, Node next, Object element) {
super();
this.previous = previous;
this.next = next;
this.element = element;
}
public Node(Object element) {
super();
this.element = element;
}
}
-
Set
-
特点:无序、唯一
-
HashSet:
- 采用Hashtable哈希表存储结构
- 缺点:无序
- 优点:添加速度快、查询、删除速度快。
public class SxtHashSet {
HashMap map;
private static final Object PRESENT = new Object();
public SxtHashSet() {
map = new HashMap();
}
public int size(){
return map.size();
}
public void add(Object o){
map.put(o, PRESENT);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
for(Object key:map.keySet()){
sb.append(key+",");
}
sb.setCharAt(sb.length()-1, ']');
return sb.toString();
}
public static void main(String[] args) {
SxtHashSet set = new SxtHashSet();
set.add("aaa");
set.add("bbb");
set.add("ccc");
System.out.println(set);
}
}
-
LinkedHashSet:
- 采用哈希表存储结构,同时使用链表维护次序,有序。
-
TreeSet:
- 采用二叉树的存储结构
- 优点:有序、查询速度比list快
- 缺点:查询速度没有HashSet快
- Set常用方法:
相对cellection没有增加任何方法 - Set的遍历方法:
for、foreach、迭代器
public class TestTreeSet {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<>();
set.add(300);
set.add(200);
set.add(600);
//按照元素递增的方式排好序
for(Integer m:set){
System.out.println(m);
}
Set<Emp2> set2 = new TreeSet<>();
set2.add(new Emp2(100,"张三",3000));
set2.add(new Emp2(50,"李四",2000));
set2.add(new Emp2(150,"王五",8000));
set2.add(new Emp2(30,"赵六",20000));
for(Emp2 m:set2){
System.out.println(m);
}
}
}
class Emp2 implements Comparable<Emp2> {
int id;
String name;
double salary;
public Emp2(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "id:"+id+",name:"+name+",salary:"+salary;
}
@Override
public int compareTo(Emp2 o) { //负数:小于,0:等于,正数:大于
if(this.salary>o.salary){
return 1;
}else if(this.salary<o.salary){
return -1;
}else{
if(this.id>o.id){
return 1;
}else if(this.id<o.id){
return -1;
}else{
return 0;
}
}
}
}
- HashSet、HashMap、Hashtable对象唯一性判断: 重写hashcode()、equals()方法。
-
Map:
- 特点:key-value映射
- HashMap:
- key无序,唯一(set)
- value无序、不唯一(collection)
public class HashMap04<K,V> {
Node3[] table; //位桶数组。bucket array
int size; //存放的键值对的个数
public SxtHashMap04() {
table = new Node3[16]; //长度一般定义成2的整数幂
}
public V get(K key){
int hash = myHash(key.hashCode(), table.length);
V value = null;
if(table[hash]!=null){
Node3 temp = table[hash];
while(temp!=null){
if(temp.key.equals(key)){ //如果相等,则说明找到了键值对,返回相应的value
value = (V)temp.value;
break;
}else{
temp = temp.next;
}
}
}
return value;
}
public void put(K key, V value){
//如果要完善,还需要考虑数组扩容的问题!!!
//定义了新的节点对象
Node3 newNode = new Node3();
newNode.hash = myHash(key.hashCode(),table.length);
newNode.key = key;
newNode.value = value;
newNode.next = null;
Node3 temp = table[newNode.hash];
Node3 iterLast = null; //正在遍历的最后一个元素
boolean keyRepeat = false;
if(temp==null){
//此处数组元素为空,则直接将新节点放进去
table[newNode.hash] = newNode;
size++;
}else{
//此处数组元素不为空。则遍历对应链表。。
while(temp!=null){
//判断key如果重复,则覆盖
if(temp.key.equals(key)){
keyRepeat = true;
temp.value = value; //只是覆盖value即可。其他的值(hash,key,next)保持不变。
break;
}else{
//key不重复,则遍历下一个。
iterLast = temp;
temp = temp.next;
}
}
if(!keyRepeat){ //没有发生key重复的情况,则添加到链表最后。
iterLast.next = newNode;
size++;
}
}
}
@Override
public String toString() {
//{10:aa,20:bb}
StringBuilder sb = new StringBuilder("{");
//遍历bucket数组
for(int i=0;i<table.length;i++){
Node3 temp = table[i];
//遍历链表
while(temp!=null){
sb.append(temp.key+":"+temp.value+",");
temp = temp.next;
}
}
sb.setCharAt(sb.length()-1, '}');
return sb.toString();
}
public static void main(String[] args) {
SxtHashMap04<Integer,String> m = new SxtHashMap04<>();
m.put(10, "aa");
m.put(20, "bb");
System.out.println(m.get(85));
}
public static int myHash(int v, int length){
// System.out.println("hash in myHash:"+(v&(length-1))); //直接位运算,效率高
// System.out.println("hash in myHash:"+(v%(length-1))); //取模运算,效率低
return v&(length-1);
}
}
定义节点:
public class Node3<K,V> {
int hash;
K key;
V value;
Node3 next;
}
-
LinkedHashMap:
有序的HashMap,速度快 -
TreeMap:
有序、速度没有hash快
public class TestTreeMap {
public static void main(String[] args) {
Map<Integer,String> treemap1 = new TreeMap<>();
treemap1.put(20, "aa");
treemap1.put(3, "bb");
treemap1.put(6, "cc");
//按照key递增的方式排序
for(Integer key:treemap1.keySet()){
System.out.println(key+"---"+treemap1.get(key));
}
Map<Emp,String> treemap2 = new TreeMap<>();
treemap2.put(new Emp(100,"张三",50000), "张三是一个好小伙");
treemap2.put(new Emp(200,"李四",5000), "李四工作不积极");
treemap2.put(new Emp(150,"王五",6000), "王五工作还不错");
treemap2.put(new Emp(50,"赵六",6000), "赵六是个开心果");
//按照key递增的方式排序
for(Emp key:treemap2.keySet()){
System.out.println(key+"---"+treemap2.get(key));
}
}
}
class Emp implements Comparable<Emp> {
int id;
String name;
double salary;
public Emp(int id, String name, double salary) {
super();
this.id = id;
this.name = name;
this.salary = salary;
}
@Override
public String toString() {
return "id:"+id+",name:"+name+",salary:"+salary;
}
@Override
public int compareTo(Emp o) { //负数:小于,0:等于,正数:大于
if(this.salary>o.salary){
return 1;
}else if(this.salary<o.salary){
return -1;
}else{
if(this.id>o.id){
return 1;
}else if(this.id<o.id){
return -1;
}else{
return 0;
}
}
}
}
set和map的关系:采用了相同的数据结构、只用于map的key,存储数据为set。
- Iterator:
-
产生的原因:集合类均未提供相应的遍历方法,将遍历交给迭代器
-
方法:
- boolean hasNext():判断是否存在另一个可访问的元素
- Object next(): 返回要访问的下一个元素
- void remove(): 删除上次访问返回的对象
-
For-each循环
- 增强的for循环,遍历array 或 Collection的时候相当简便。
- 无需获得集合和数组长度,无需使用索引访问元素,无需循环条件。
- 遍历集合时底层调用Iterator完成操作。
- For-each缺陷:
- 数组:不能方便的访问下标值,不要在for-each中尝试对变量赋值,只是一个临时变量。
- 集合:与使用Iterator相比,不能方便的删除集合中的内容。
-
ListIterator和Iterator的关系:
public interface ListIterator extends Iterator,都可以遍历List。 -
ListIterator和Iterator的区别:
- 使用范围不同:Iterator可以应用于更多的集合,Set、List和这些集合的子类型。而ListIterator只能用于List及其子类型。
- 遍历顺序不同:Iterator只能顺序向后遍历; ListIterator还可以逆序向前遍历。Iterator可以在遍历的过程中remove();ListIterator可以在遍历的过程中remove()、add()、set()。
- ListIterator可以定位当前的索引位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。
-
public class TestIterator {
public static void main(String[] args) {
// testIteratorList();
// testIteratorSet();
// testIteratorMap();
testRemove();
}
public static void testIteratorList(){
List<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
//使用iterator遍历List
for(Iterator<String> iter=list.iterator();iter.hasNext();){
String temp = iter.next();
System.out.println(temp);
}
}
public static void testIteratorSet(){
Set<String> set = new HashSet<>();
set.add("aa");
set.add("bb");
set.add("cc");
//使用iterator遍历Set
for(Iterator<String> iter=set.iterator();iter.hasNext();){
String temp = iter.next();
System.out.println(temp);
}
}
public static void testIteratorMap(){
Map<Integer,String> map1 = new HashMap<>();
map1.put(100, "aa");
map1.put(200, "bb");
map1.put(300, "cc");
//第一种遍历Map的方式
Set<Entry<Integer,String>> ss = map1.entrySet();
for(Iterator<Entry<Integer,String>> iter=ss.iterator();iter.hasNext();){
Entry<Integer,String> temp = iter.next();
System.out.println(temp.getKey()+"--"+temp.getValue());
}
System.out.println("++++++++++++++++++++++++");
//第二种遍历Map的方式
Set<Integer> keySet = map1.keySet();
for(Iterator<Integer> iter=keySet.iterator();iter.hasNext(); ){
Integer key = iter.next();
System.out.println(key+"----"+map1.get(key));
}
}
//测试边遍历,边删除
public static void testRemove(){
List<String> list = new ArrayList<>();
for(int i=0;i<20;i++){
list.add("gao"+i);
}
for(int i=0;i<list.size();i++){
String temp = list.get(i);
if(temp.endsWith("2")){
list.remove(i);
}
System.out.println(list.size());
System.out.println(list.get(i));
}
}
}
- Collections:
- 专门用来操作集合的工具类
- 构造方法私有,禁止创建对象
- 提供一系列静态方法实现对各种集合的操作
- 具体操作:搜索、复制、排序、线程安全化等
- 常用方法:
- Collections.addAll(list, “aaa”,“bbb”,“ccc”,“ccc”);
- int index = Collections.binarySearch(list, “ccc”);
- Collections.copy(list2, list);
- Collections.fill(list3, “888”);
- String max = Collections.max(list4);
- String min = Collections.min(list4); • Collections.reverse(list4); • List list5 = Collections.synchronizedList(list4);
- Collection和Collections的区别:
- Collection是Java提供的集合接口,存储一组不唯一,无序的对象。它有两个子接口 List和Set。
- Java中还有一个Collections类,专门用来操作集合类 ,它提供一系列静态方法实现对 各种集合的搜索、排序、线程安全化等操作。
public class TestCollections {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for(int i=0;i<10;i++){
list.add("gao:"+i);
}
System.out.println(list);
Collections.shuffle(list); //随机排列list中的元素
System.out.println(list);
Collections.reverse(list); //逆序排列
System.out.println(list);
Collections.sort(list); //按照递增的方式排序。自定义的类使用:Comparable接口。
System.out.println(list);
System.out.println(Collections.binarySearch(list, "gao:1")); //二分法查找,或者:折半查找
}
}
- vector:
- 实现原理和ArrayList相同,功能相同,长度可变的数组结构。
- 两者的主要区别如下:
- Vector是早期JDK接口,ArrayList是替代Vector的新接口。
- Vector线程安全,效率低下;ArrayList重速度轻安全,线程非安全。
- 长度需增长时,Vector默认增长一倍,ArrayList增长50%。
public class TestVector {
public static void main(String[] args) {
List<String> a = new Vector();
}
}
- Hashtable类:
- 实现原理和HashMap相同,功能相同,底层都是哈希表结构,查询速度快,很多情况下可互用。
- 两者的主要区别如下:
- Hashtable是早期JDK提供的接口,HashMap是新版JDK提供的接口。
- Hashtable继承Dictionary类,HashMap实现Map接口。
- Hashtable线程安全,HashMap线程非安全。
- Hashtable不允许null值,HashMap允许null值。
- 集合和数组的比较:
- 数组不是面向对象的,存在明显的缺陷,集合完全弥补了数组的一些缺点,比数组更灵活更实 用,可大大提高软件的开发效率而且不同的集合框架类可适用于不同场合。
- 数组容量固定且无法动态改变,集合类容量动态改变。
- 数组能存放基本数据类型和引用数据类型的数据,而集合类中只能放引用数据类型的数据。
- 数组无法判断其中实际存有多少元素,length只告诉了array容量;集合可以判断实际存有多 少元素,而对总的容量不关心。
- 集合有多种数据结构(顺序表、链表、哈希表、树等)、多种特征(是否有序,是否唯一)、 不同适用场合(查询快,便于删除、有序),不像数组仅采用顺序表方式。
- 集合以类的形式存在,具有封装、继承、多态等类的特性,通过简单的方法和属性调用即可 实现各种复杂操作,大大提高软件的开发效率。
- 集合总结