Java集合

集合与数组的区别,缓存的管理,Collection 、List、Set 接 口的作用及相关的子类

类集设置的目的

在这里插入图片描述

Collection 接口

在这里插入图片描述

List 接口

ArrayList

ArrayList 是 List 接口的子类,此类的定义如下:
public class ArrayList extends AbstractList implements List, RandomAccess, Cloneable, Serializable 此类继承了 AbstractList 类。
AbstractList 是 List 接口的子类。AbstractList 是个抽象类,适配器设计模式。
范例:增加及取得元素

package org.listdemo.arraylistdemo; 
import java.util.ArrayList; 
import java.util.List; 
public class ArrayListDemo01 { 
public static void main(String[] args) { 
	List<String> all = new ArrayList<String>(); 
	// 实例化List对象,并指定泛型类型 all.add("hello "); 
	// 增加内容,此方法从Collection接口继承而来 all.add(0, "LAMP ");
	// 增加内容,此方法是List接口单独定义的 all.add("world");
	// 增加内容,此方法从Collection接口继承而来 System.out.println(all); 
	// 打印all对象调用toString()方法 
	}
}

以上的操作向集合中增加了三个元素,其中在指定位置增加的操作是 List 接口单独定义的。随后进行输出的时候, 实际上调用的是 toString()方法完成输出的。
可以发现,此时的对象数组并没有长度的限制,长度可以任意长,只要是内存够大就行。
范例:进一步操作

  • 使用 remove()方法删除若干个元素,并且使用循环的方式输出。
  • 根据指定位置取的内容的方法,只有 List 接口才有定义,其他的任何接口都没有任何的定义。
package org.listdemo.arraylistdemo; 
import java.util.ArrayList; 
import java.util.List; 
public class ArrayListDemo02 { 
	public static void main(String[] args) { 
		List<String> all = new ArrayList<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的 
		all.remove("world");// 删除指定的对象 
		System.out.print("集合中的内容是:"); 
		for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 
			System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的 
		} 
	} 
} 

但是,这里需要注意的是,对于删除元素的操作,后面还会有更加清楚的讲解,此处只是简单的理解一下元素删除 的基本操作即可。具体的原理可以暂时不进行深入掌握。

Vector

与 ArrayList 一样,Vector 本身也属于 List 接口的子类,此类的定义如下:

public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable
package org.listdemo.vectordemo; 
import java.util.List; 
import java.util.Vector; 
public class VectorDemo01 { 
	public static void main(String[] args) { 
		List<String> all = new Vector<String>(); // 实例化List对象,并指定泛型类型 
		all.add("hello "); // 增加内容,此方法从Collection接口继承而来 
		all.add(0, "LAMP ");// 增加内容,此方法是List接口单独定义的 
		all.add("world"); // 增加内容,此方法从Collection接口继承而来 
		all.remove(1); // 根据索引删除内容,此方法是List接口单独定义的 
		all.remove("world");// 删除指定的对象 
		System.out.print("集合中的内容是:"); 
		for (int x = 0; x < all.size(); x++) { // size()方法从Collection接口继承而来 
			System.out.print(all.get(x) + "、"); // 此方法是List接口单独定义的 
		} 
	} 
}

在这里插入图片描述

链表操作类:LinkedList

public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, Serializable

此类继承了 AbstractList,所以是 List 的子类。但是此类也是 Queue 接口的子类,Queue 接口定义了如下的方法:
在这里插入图片描述

import java.util.LinkedList; 
import java.util.Queue; 
public class TestDemo { 
public static void main(String[] args) { 
	Queue<String> queue = new LinkedList<String>(); 
	queue.add("A"); 
	queue.add("B"); 
	queue.add("C"); 
	int len=queue.size();//把queue的大小先取出来,否则每循环一次,移除一个元素,就少 一个元素,那么queue.size()在变小,就不能循环queue.size()次了。 
	for (int x = 0; x <len; x++) { 
		System.out.println(queue.poll()); 
	}
	System.out.println(queue); 
	} 
}

结果输出为:ABC

Set 接口

Set 接口也是 Collection 的子接口,与 List 接口最大的不同在于,Set 接口里面的内容是不允许重复的。
Set 接口并没有对 Collection 接口进行扩充,基本上还是与 Collection 接口保持一致。因为此接口没有 List 接口中定义 的 get(int index)方法,所以无法使用循环进行输出。
那么在此接口中有两个常用的子类:HashSet、TreeSet

散列存放:HashSet

package org.listdemo.hashsetdemo; 
import java.util.HashSet; 
import java.util.Set; 
public class HashSetDemo03 { 
	public static void main(String[] args) { 
		Set<String> all = new HashSet<String>(); // 实例化Set接口对象 
		all.add("A");
		all.add("B"); 
		all.add("C"); 
		all.add("D"); 
		all.add("E"); 
		String[] str = all.toArray(new String[] {});// 变为指定的泛型类型数组 
		for (int x = 0; x < str.length; x++) { 
			System.out.print(str[x] + "、"); 
		} 
	} 
}

排序的子类:TreeSet

与 HashSet 不同的是,TreeSet 本身属于排序的子类,此类的定义如下:

public class TreeSet<E> extends AbstractSet<E> implements NavigableSet<E>, Cloneable, Serializable
package org.listdemo.treesetdemo01; 
import java.util.Set; 
import java.util.TreeSet; 
public class TreeSetDemo01 { 
	public static void main(String[] args) { 
		Set<String> all = new TreeSet<String>(); // 实例化Set接口对象
		all.add("D"); 
		all.add("X");
		all.add("A"); 
		System.out.println(all); 
	} 
}

虽然在增加元素的时候属于无序的操作,但是增加之后却可以为用户进行排序功能的实现。

排序的说明

package org.listdemo.treesetdemo03; 
public class Person implements Comparable<Person> { 
	private String name; 
	private int age; 
	public int compareTo(Person per) { 
		if (this.age > per.age) { 
			return 1; 
		} else if (this.age < per.age) { 
			return -1; 
		} else { 
			return this.name.compareTo(per.name);
		} 
	}
	public Person() { }
	public Person(String name, int age) { 
		this.name = name; 
		this.age = age; 
	}
	public String getName() { 
		return name; 
	}
	public void setName(String name) { 
		this.name = name; 
	}
	public int getAge() { 
		return age; 
	}
	public void setAge(int age) { 
		this.age = age; 
	}
	public String toString() { 
		return "姓名:" + this.name + ",年龄:" + this.age; 
	} 
}
package org.listdemo.treesetdemo02; 
import java.util.Set; 
import java.util.TreeSet; 
public class TreeSetPersonDemo01 { 
public static void main(String[] args) { 
	Set<Person> all = new TreeSet<Person>(); 
	all.add(new Person("张三", 10)); 
	all.add(new Person("李四", 10));
	all.add(new Person("王五", 11)); 
	all.add(new Person("赵六", 12)); 
	all.add(new Person("孙七", 13)); 
	System.out.println(all); 
} 
}

Person 类如果假设年龄相等的话,按字符串进行排序。

关于重复元素的说明

如果要想判断两个对象是否相等,则必须使用 Object 类中的 equals()方法。 从最正规的来讲,如果要想判断两个对象是否相等,则有两种方法可以完成:

  • 第一种判断两个对象的编码是否一致,这个方法需要通过 hashCode()完成,即:每个对象有唯一的编码
  • 还需要进一步验证对象中的每个属性是否相等,需要通过 equals()完成。 所以此时需要覆写 Object 类中的 hashCode()方法,此方法表示一个唯一的编码,一般是通过公式计算出来的。
public boolean equals(Object obj) { 
	if (this == obj) { 
		return true; 
	}
	if (!(obj instanceof Person)) { 
		return false; 
	}
	Person per = (Person) obj; 
	if (per.name.equals(this.name) && per.age == this.age) { 
		return true; 
	} else { 
		return false; 
	}
}
public int hashCode() { 
	return this.name.hashCode() * this.age; 
}

小结:

       关于 TreeSet 的排序实现,如果是集合中对象是自定义的或者说其他系统定义的类没有实现 Comparable 接口,则不能实现TreeSet 的排序,会报类型转换(转向 Comparable 接口)错误。
       换句话说要添加到 TreeSet集合中的对象的类型必须实现了 Comparable 接口。 不过 TreeSet 的集合因为借用了 Comparable接口,同时可以去除重复值,而 HashSet 虽然是 Set 接口子类,但是对于没有复写 Object 的 equals 和hashCode 方法的对象,加入了 HashSet 集合中也是不能去掉重复值的。

集合输出

只要是碰到了集合,则输出的时候想都不想就使用 Iterator 进行输出。

Iterator

Iterator 属于迭代输出,基本的操作原理:是不断的判断是否有下一个元素,有的话,则直接输出。

public interface Iterator<E>

在这里插入图片描述

package org.listdemo.iteratordemo; 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.Iterator; 
public class IteratorDemo01 { 
	public static void main(String[] args) { 
		Collection<String> all = new ArrayList<String>(); 
		all.add("A"); 
		all.add("B"); 
		all.add("C"); 
		all.add("D"); 
		all.add("E"); 
		Iterator<String> iter = all.iterator(); 
		while (iter.hasNext()) {// 判断是否有下一个元素 
			String str = iter.next(); // 取出当前元素 
			System.out.print(str + "、"); 
		} 
	} 
}

以上的操作是 Iterator 接口使用最多的形式,也是一个标准的输出形式。 但是在使用 Iterator 输出的时候有一点必须注意,在进行迭代输出的时候如果要想删除当前元素,则只能使用 Iterator 接口中的 remove()方法,而不能使用集合中的 remove()方法。否则将出现未知的错误。

Collection<String> all = new ArrayList<String>();
 all.add("A");
 all.add("B");
 all.add("C");
 all.add("D");
 all.add("E");
 Iterator<String> iter = all.iterator();
 while (iter.hasNext()) {
     // 判断是否有下一个元素
     String str = iter.next();
     // 取出当前元素
     if (str.equals("C")) {
         iter.remove();
         // 错误的,调用了集合中的删除
     } else {
         System.out.print(str + "、");
     }
 }

ListIterator

ListIterator 是可以进行双向输出的迭代接口,此接口定义如下:

public interface ListIterator<E> extends Iterator<E>

此接口是 Iterator 的子接口,此接口中定义了以下的操作方法:
在这里插入图片描述

package org.listdemo.listiteratordemo; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.ListIterator; 
public class ListIteratorDemo01 { 
	public static void main(String[] args) { 
		List<String> all = new ArrayList<String>(); 
		all.add("A"); 
		all.add("B"); 
		all.add("C"); 
		all.add("D"); 
		all.add("E"); 
		ListIterator<String> iter = all.listIterator(); 
		System.out.print("从前向后输出:"); 
		while (iter.hasNext()) { 
			System.out.print(iter.next() + "、"); 
		}
		System.out.print("\n从后向前输出:"); 
		while (iter.hasPrevious()) { 
			System.out.print(iter.previous() + "、"); 
		} 
	} 
}

新的支持:foreach

foreach 可以用来输出数组的内容,那么也可以输出集合中的内容。

package org.lamp.listdemo.foreachdemo; 
import java.util.ArrayList; 
import java.util.Collection; 
public class ForeachDemo01 { 
public static void main(String[] args) { 
		Collection<String> all = new ArrayList<String>(); 
		all.add("A"); 
		all.add("B"); 
		all.add("C"); 
		all.add("D"); 
		all.add("E"); 
		for (String str : all) { 
			System.out.println(str) ; 
		} 
	} 
}

Map 接口

在这里插入图片描述

新的子类:HashMap(重点)

HashMap 是 Map 的子类,此类的定义如下:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

此类继承了 AbstractMap 类,同时可以被克隆,可以被序列化下来。

import java.util.Collection; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.Set; 
public class HashMapDemo02 { 
	public static void main(String[] args) { 
		Map<Integer, String> map = new HashMap<Integer, String>(); 
		map.put(1, "张三A"); 
		map.put(2, "李四"); 
		map.put(3, "王五"); 
		Set<Integer> set = map.keySet(); // 得到全部的key 
		Collection<String> value = map.values(); // 得到全部的value 
		Iterator<Integer> iter1 = set.iterator(); 
		Iterator<String> iter2 = value.iterator(); 
		System.out.print("全部的key:"); 
		while (iter1.hasNext()) { 
			System.out.print(iter1.next() + "、"); 
		}
		System.out.print("\n全部的value:"); 
		while (iter2.hasNext()) { 
			System.out.print(iter2.next() + "、"); 
		} 
	} 
}

旧的子类:Hashtable

操作的时候,可以发现与 HashMap 基本上没有什么区别,而且本身都是以 Map 为操作标准的,所以操作的结果形式 都一样。但是 Hashtable 中是不能向集合中插入 null 值的。
在这里插入图片描述

排序的子类:TreeMap

TreeMap 子类是允许 key 进行排序的操作子类,其本身在操作的时候将按照 key 进行排序,另外,key 中的内容可以 为任意的对象,但是要求对象所在的类必须实现 Comparable 接口。

public static void main(String[] args) { 
	Map<String, String> map = new TreeMap<String, String>(); 
	map.put("ZS", "张三"); 
	map.put("LS", "李四"); 
	map.put("WW", "王五"); 
	map.put("ZL", "赵六"); 
	map.put("SQ", "孙七"); 
	Set<String> set = map.keySet(); // 得到全部的key 
	Iterator<String> iter = set.iterator(); 
	while (iter.hasNext()) { 
		String i = iter.next(); // 得到key 
		System.out.println(i + " --:> " + map.get(i)); 
	} 
}

关于 Map 集合的输出

Map.Entry 本身是一个接口。此接口是定义在 Map 接口内部的,是 Map 的内部接口。此内部接口使用 static 进行定义,所以此接口将成为外部接口。
实际上来讲,对于每一个存放到 Map 集合中的 key 和 value 都是将其变为了 Map.Entry并且将 Map.Entry 保存在了 Map 集合之中。

在这里插入图片描述
范例:使用 Iterator 输出 Map 接口

package org.listdemo.mapoutdemo; 
import java.util.HashMap; 
import java.util.Iterator; 
import java.util.Map; 
import java.util.Set; 
public class MapOutDemo01 { 
	public static void main(String[] args) { 
		Map<String, String> map = new HashMap<String, String>(); 
		map.put("ZS", "张三"); 
		map.put("LS", "李四"); 
		map.put("WW", "王五"); 
		map.put("ZL", "赵六"); 
		map.put("SQ", "孙七"); 
		Set<Map.Entry<String, String>> set = map.entrySet();// 变为Set实例 
		Iterator<Map.Entry<String, String>> iter = set.iterator(); 
		while (iter.hasNext()) { 
			Map.Entry<String, String> me = iter.next(); 
			System.out.println(me.getKey() + " --> " + me.getValue()); 
		} 
	} 
}

也可以使用 foreach 完成同样的输出

package org.listdemo.mapoutdemo; 
import java.util.HashMap; 
import java.util.Map; 
public class MapOutDemo02 { 
	public static void main(String[] args) { 
		Map<String, String> map = new HashMap<String, String>(); 
		map.put("ZS", "张三"); 
		map.put("LS", "李四"); 
		map.put("WW", "王五"); 
		map.put("ZL", "赵六"); 
		map.put("SQ", "孙七"); 
		for (Map.Entry<String, String> me : map.entrySet()) { 
			System.out.println(me.getKey() + " --> " + me.getValue()); 
		} 
	} 
}

Collections 类

Collections 实际上是一个集合的操作类,此类的定义如下:

public class Collections extends Object

这个类与 Collection 接口没有任何的关系。是一个单独存在的类。

package org.listdemo.collectionsdemo; 
import java.util.Collections; 
import java.util.List; 
public class CollectionsDemo01 { 
	public static void main(String[] args) { 
		List<String> all = Collections.emptyList() ;// 空的集合 
		all.add("A") ; 
	}
}

使用 Collections 进行增加元素的操作

package org.listdemo.collectionsdemo; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.List; 
public class CollectionsDemo02 { 
	public static void main(String[] args) { 
		List<String> all = new ArrayList<String>(); 
		Collections.addAll(all, "A", "B", "C");// 向集合增加元素 
		System.out.println(all); 
	} 
}

分析 equals、hashCode 与内存泄露

  • equals 的作用:比较两个对象的地址值是否相等
    • 但是我们必需清楚,当 String 、Math、还有 Integer、Double。等这些封装类在使用 equals()方法时,已经覆盖了 object 类的 equals()方法,不再是地址的比较而是内容的比较。
  • hashcode() 方法,在 object 类中定义如下:

public native int hashCode();

- 说明是一个本地方法,它的实现是根据本地机器相关的。
- 当然我们可以在自己写的类中覆盖 hashcode()方法,比如 String、 Integer、Double。等等这些类都是覆盖了 hashcode()方法的。
  • java.lnag.Object 中对 hashCode 的约定
  1. 在一个应用程序执行期间,如果一个对象的 equals 方法做比较所用到的信息没有被修改的话,则对该对象调用 hashCode 方法多次,它必须始终如一地返回同一个整数。
  2. 如果两个对象根据 equals(Object o)方法是相等的,则调用这两个对象中任一对象的 hashCode 方法必须产生相同的整数结果。
  3. 如果两个对象根据 equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的 hashCode 方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
  • 在 java 的集合中,判断两个对象是否相等的规则是:
    (1)判断两个对象的 hashCode 是否相等。如果不相等,认为两个对象也不相等,完毕。如果相等,转入 2 (这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低,所以我们 这里将其做为必需的)
    (2)判断两个对象用 equals 运算是否相等 如果不相等,认为两个对象也不相等 如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)

TIPS:当一个对象被存进 HashSet 集合后,就不能修改这个对象中的那些参与计算的哈希值的字段了,否则,对象被修改后的哈 希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为 的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中删除当前对象,从而造成内存泄露

总结

1、 类集就是一个动态的对象数组,可以向集合中加入任意多的内容。
2、 List 接口中是允许有重复元素的,Set 接口中是不允许有重复元素。
3、 所有的重复元素依靠 hashCode()和 equals 进行区分
4、 List 接口的常用子类:ArrayList、Vector
5、 Set 接口的常用子类:HashSet、TreeSet
6、 TreeSet 是可以排序,一个类的对象依靠 Comparable 接口排序
7、 Map 接口中允许存放一对内容,key ,value
8、 Map 接口的子类:HashMap、Hashtable、TreeMap
9、 Map 使用 Iterator 输出的详细步骤

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值