一、集合概述
集合類的特點
集合是用來封裝對象的。
數組雖然也可以存儲對象,但長度是固定的;集合長度是可變的。數組中可以存儲基本數據類型,集合只能存儲對象。
二、Collection
常用的兩個子接口:
List:元素有序,可重複,因爲其中元素有索引。
set: 無序(無下標),不可重複。
(1)add方法的參數類型是Object。以便於接收任意類型對象。
(2)集合中存儲的都是對象的引用(地址)
示例:
Person p = new Person();
ArrayList l = new ArrayList();
l.add(p);
數組轉化成集合
ArrayList aList = new ArrayList(Arrays.asList(str));
將集合轉化成數組
toArray():返回包含此 collection 中所有元素的數組。
1、Collection的子接口List和Set
(1).List
List:元素是有序的,元素可以重複。因爲該集合體繫有索引。
|–ArrayList:底層的數據結構使用的是數組結構。特點:查詢速度很快。但是增刪稍慢。線程不同步(線程無聯繫),不安全。
|–LinkedList:底層使用的鏈表數據結構。特點:增刪速度很快,查詢稍慢。線程不同步。
|–Vector:底層是數組數據結構。線程同步。被ArrayList替代了。因爲效率低,但是安全。
(List集合判斷元素是否相同,依據是元素的equals方法。當存儲時會自動調用。)
List的特有方法:凡是可以操作角標的方法都是該體系特有的方法。
增
add(index,element);
addAll(index,Collection);
刪
remove(index);
改
set(index,element);
查
get(index):獲取角標
subList(from,to):截取
ListIterator():獲取迭代器
int indexOf(obj):獲取指定元素的位置。
List集合特有的迭代器。ListIterator是Iterator的子接口。
在迭代時,不可以通過集合對象的方法操作集合中的元素。
因爲會發生ConcurrentModificationException異常。
所以,在迭代器時,只能用迭代器的放過操作元素,可是Iterator方法是有限的,
只能對元素進行判斷,取出,刪除的操作,
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。
該接口只能通過List集合的listIterator方法獲取。
(1)LinkeList
底層使用的鏈表數據結構。特點:增刪速度很快,查詢稍慢。線程不同步。
特有方法:
addFirst(); addLast();
getFirst(); getLast();
獲取元素,但不刪除元素。如果集合中沒有元素,會出現NoSuchElementException
removeFirst(); removeLast();
LinkedList的部分方法已經升級。JDK1.6以後。
removeLast(); 獲取元素,但是元素被刪除。如果集合中沒有元素,會出現NoSuchElementException
pollLast();獲取元素,但是元素被刪除。如果集合中沒有元素,會返回null。
(2)ArrayList
底層的數據結構使用的是數組結構。特點:查詢速度很快。但是增刪稍慢。線程不同步(線程無聯繫),不安全。
練習:
刪除list集合中的重複元素
package CollectionDemo;
import java.util.*;
public class DeleOver {
public static void main(String[] args) {
ArrayList<String> l1 = new ArrayList<String>();
l1.add("PHP1");
l1.add("PHP2");
l1.add("PHP3");
l1.add("PHP4");
l1.add("PHP1");
l1.add("PHP2");
l1.add("PHP3");
l1.add("PHP2");
l1.add("PHP2");
for(int i = 0;i<l1.size();i++){
for(int j =i+1;j<l1.size();j++){
if(l1.get(i).equals(l1.get(j))){
l1.remove(j);
j--;
}
}
}
/* ArrayList<String> l2 = new ArrayList<String>();
Iterator it = l1.iterator();
while(it.hasNext()){
String strValue = it.next().toString();
if(!l2.contains(strValue)){
l2.add(strValue);
}
}*/
//遍歷l2
Iterator it = l1.iterator();
while(it.hasNext()){
System.out.print(it.next().toString());
}
}
}
(3)Vector
底層是數組數據結構。線程同步。被ArrayList替代了。因爲效率低,但是安全。
枚舉是Vector特有的取出方式。
Vector v = new Vector();
v.add("Ruby01");
v.add("Ruby02");
v.add("Ruby03");
//枚舉方式取出
Enumeration en = v.elements();
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
需求:使用LinkedList模擬堆棧和隊列的數據結構
隊列:先進先出
class Queue{
private LinkedList link;
Queue(){
link = new LinkedList();
}
public void add(Object o){
link.addFirst(o);
}
public Object remove(){
return link.removeLast();
}
public boolean isEmpty(){
return link.isEmpty();
}
}
棧:先進後出
稍微修改下
class Stack{
private LinkedList link;
Queue(){
link = new LinkedList();
}
public void add(Object o){
link.addFirst(o);
}
public Object remove(){
return link.removeFirst();
}
public boolean isEmpty(){
return link.isEmpty();
}
}
注意list集合保證對象的唯一性是用equals方法,若對象類沒有重寫equals方法,則默認調用Object的equals方法。
2、Set集合
Set集合元素無序且不可以重複。
(1)HashSet如何保證元素唯一性?
當哈希表中出現兩個相同的對象時:要先判斷hashCode值是否相同,若相同,再使用equals判斷對象是否相同。若不是一個對象,那麼這個會對象存儲順延,還在原位置。其中涉及兩個方法:hashCode和equals來完成。
如果元素的HashCode值相同,纔會判斷equals是否爲true。
如果元素的hashcode值不同,不會調用equals。
注意,對於判斷元素是否存在,以及刪除等操作,依賴的方法是元素的hashcode和equals方法。
那麼當hashSet中不允許存入相同的對象時必須複寫hashcode方法和equals方法。
判斷刪除:先判斷hashCode值,然後判斷內容。
class Person{
private String name;
private int 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;
}
Person(String name ,int age){
this.name = name ;
this.age = age ;
}
//重寫equals方法
public boolean equals(Object obj){
if(!(obj instanceof Person)){
return false;
}
Person p = (Person)obj;
System.out.println("equals has been called");
return this.name.equals(p.getName())&&this.age ==p.getAge();
}
//重寫hashCode方法
public int hashCode(){
System.out.println("hashCode has been called");
return this.name.hashCode()+age;
}
}
(2)TreeSet:可以對set集合中的元素進行自動排序
需求:TreeSet中存儲自定義對象,按照某種規則排序
package CollectionDemo;
import java.util.*;
class Person implements Comparable{
private String name;
private int 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;
}
Person(String name ,int age){
this.name = name ;
this.age = age ;
}
//繼承Comparable,重寫compareTo方法
public int compareTo(Object obj){
if(!(obj instanceof Person)){
throw new RuntimeException("不是Person對象");
}
Person p = (Person)obj;
if(this.age>p.getAge()){
return 1;
}else if(this.age ==p.getAge()){
return this.name.compareTo(p.getName());//調用String的compareTo方法
}
return -1;
}
}
public class Demo1 {
public static void main(String[] args) {
TreeSet hs = new TreeSet();
hs.add(new Person("zhangsaa",19));
hs.add(new Person("zhangsac",19));
hs.add(new Person("zhangsab",19));
hs.add(new Person("lisi",22));
hs.add(new Person("xiaoliu",20));
for(Iterator it1 = hs.iterator();it1.hasNext();){
Person p = (Person)it1.next();
System.out.println(p.getName()+" "+p.getAge());
}
}
}
TreeSet底層數據結構是二叉樹,保證元素的唯一性的依據:compareTo方法return 0。只要return 0,該對象不會存入TreeSet容器。
TreeSet會進行自動排序,方式有兩種。
(1)讓對象自身具備可比性,需實現Comparable接口,重寫 compareTo方法。
(2)當對象不具備比較性時,讓集合自身具備比較功能。
//TreeSet定義方式。
TreeSet hs = new TreeSet(new Comparator() {
public int compare(Object o1, Object o2){
Person p1 = (Person)o1;
Person p2 = (Person)o2;
int i = p1.getAge()-p2.getAge();
if(i==0){
i = p1.getName().compareTo(p2.getName());
}
return i;
}
});
練習:TreeSet容器實現字符串長度排序
package CollectionDemo;
import java.util.*;
public class Demo2 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new Comparator(){
public int compare(Object o1,Object o2){
int i = o1.toString().length() - o2.toString().length();
if(i==0) {
//如果長度一致就錯啦。。。還需繼續判斷!!!return爲0絕對會剔除。
i = o1.toString().compareTo(o2.toString());
}
return i;
}
});
ts.add("aaaa");
ts.add("aa");
ts.add("aab");
ts.add("aaa");
Iterator it = ts.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
}
練習
“adasdweasdfgagfaga”獲取該字符串中的字母出現的次數。
* 希望打印結果:a(1)c(2)…..
import java.util.*;
import java.util.Map.Entry;
public class TestDemo {
/**
* 需求:"adasdweasdfgagfaga"獲取該字符串中的字母出現的次數。
* 希望打印結果:a(1)c(2).....
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Map<Character, Integer> map = new TreeMap<Character, Integer>();
String str = "adasdweasdfgagfaga";
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
// 判斷是否在其中
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
map.put(c, 1);
}
}
// 遍歷map集合
for (Entry<Character, Integer> entry : map.entrySet()) {
System.out.print(entry.getKey() + "(" + entry.getValue() + ")");
}
}
}
輸出結果
a(6)d(3)e(1)f(2)g(3)s(2)w(1)
“`