集合部分的继承关系要把常用的类(接口)搞清楚。这一章笔记只包括常用的类。
Collection
集合只能存储引用类型。
- List:有序,可重复
- Set:无序,不重复
- Map:无序键值对,键不可重复,值可重复。
List和Set继承自Collection接口
java.util.Collection<E>接口
单个存储!!!!!!
<>
是泛型。
java.util.Iterator
接口主要有hasNext(),next(),remove()
,1.8又加了forEachRemaining()
。
重点实现类:
ArrayList, LinkedList
HashSet, TreeSet.
SortedSet
:无序,不重复,但取出时可按元素大小排序。
常用集合类底层数据结构
ArrayList
:数组,适合查询,不适合频繁增删元素。常用。LinkedList
:双向链表。Vector
:数组,但是线程安全。但效率低,很少使用。采用其它方式实现线程安全。
重要方法:
add, clear, contains, isEmpty, iterator, remove, size, toArray.
注意Collection没有get()
方法。
import java.util.*;
public class CollectionTest01{
public static void main(String[] args){
Collection c = new ArrayList();
c.add(1);
c.add("a");
Person p1 = new Person("Tom",12);
c.add(p1);
System.out.println("c.size(): "+c.size());
System.out.println("c.isEmpty(): "+c.isEmpty());
//c.remove(p1);
System.out.println("c.contains(p1): "+c.contains(p1));
Object[] objs = c.toArray();
for(int i=0;i<objs.length;i++){
System.out.println(objs[i]);
}
c.clear();
System.out.println("after c.clear()... ");
objs = c.toArray();
for(int i=0;i<objs.length;i++){
System.out.println(objs[i]);
}
}
}
class Person{
String name;
int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return "Person[name="+name+",age="+age+"]";
}
}
迭代
iterator()
来自于Iterable
接口,用于获取集合所依赖的迭代器对象(ListItr,AbstractListItr,并包含内部类),是所有集合通用的遍历方式。
详细继承关系查询api
contains()
和remove()
底层调用了equals()
.
所以存储在集合中的元素应该重写equals()
方法。
删除要使用迭代器的remove()
,因为使用集合的remove()
会改变集合c进而导致迭代器error.
import java.util.*;
public class CollectionTest02{
public static void main(String[] args){
Collection c = new ArrayList();
c.add(1);
c.add("a");
Iterator itr = c.iterator();
System.out.println(itr); //java.util.ArrayList$Itr@15db9742
System.out.println(c);
}
}
import java.util.*;
public class CollectionTest03{
public static void main(String[] args){
Collection c = new ArrayList();
Integer i1 = new Integer(1);
c.add(i1);
Integer i2 = new Integer(1);
System.out.println(c.contains(i2)); //true
c.remove(i2);
System.out.println(c.size()); //0
Person p1 = new Person("Tom",12);
c.add(p1);
Person p2 = new Person("Tom",12);
System.out.println(c.contains(p2)); //true
c.remove(p2);
System.out.println(c.size()); //0
}
}
class Person{
String name;
int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public boolean equals(Object o){
if(this==o) return true;
if(o instanceof Person){
Person p = (Person)o;
if(p.name==this.name && p.age==this.age){
return true;
}
}
return false;
}
}
List
import java.util.*;
public class ListText01{
@SuppressWarnings("unchecked")
public static void main(String[] args){
//List l = new ArrayList();
//ArrayList<Integer> l = new ArrayList<Integer>();
//List<Integer> l = new ArrayList<Integer>();
List<Integer> l = new LinkedList<Integer>();
l.add(1);
l.add(2);
l.add(3);
l.add(3);
Iterator itr = l.iterator();
while(itr.hasNext()){
//Object o = itr.next();
System.out.println(itr.next());
}
for(int i=0;i<l.size();i++){
System.out.println(l.get(i));
}
System.out.println(l);
}
}
ArrayList
默认容量是10,扩容后是原来的1.5倍。
LinkedList
没有容量。
Vector
默认容量是10,扩容后是原来的1.5倍。
注意add()
是插入,不是替换。
优化ArrayList
和Vector
,可以通过预测并指定初始化容量,减少扩容(数组拷贝)。
##Set
###HashSet
HashSet
其实就是HashMap
的key部分。
两类初始容量都是16.
HashMap
类中有static final float DEFAULT_LOAD_FACTOR = 0.75;
扩容因子,意思是数组装满75%则扩容。
import java.util.*;
public class SetTest01{
public static void main(String[] args){
Set<Integer> s = new HashSet<Integer>();
s.add(1);
s.add(2);
s.add(3);
s.add(3);
Iterator itr = s.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
}
}
java.lang.Object.hashCode()
总之Object的方法都是用来重写的。
存储在HashSet
或HashMap
中的元素需要同时重写HashCode()
和equals()
.
import java.util.*;
public class SetTest02{
public static void main(String[] args){
Set<Employee> s = new HashSet<Employee>();
Employee e1 = new Employee("1000","Tom");
Employee e2 = new Employee("1000","Tom");
Employee e3 = new Employee("2000","Jerry");
Employee e4 = new Employee("3000","John");
s.add(e1);
s.add(e2);
s.add(e3);
s.add(e4);
Iterator itr = s.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
/*
Employee@17005f
Employee@1774be
Employee@17e91d
*/
}
System.out.println(e1.hashCode());
System.out.println(e2.hashCode());
System.out.println(s.size());
/*
1507423
1507423
3
*/
}
}
class Employee{
//1000-9999
String no;
String name;
Employee(String no,String name){
this.no = no;
this.name = name;
}
public boolean equals(Object o){
if(this == o) return true;
if(o instanceof Employee){
Employee e = (Employee)o;
if(e.no.equals(this.no) && e.name.equals(this.name)){
return true;
}
}
return false;
}
public int hashCode(){
//String.hashCode()
return no.hashCode();
}
}
SortedSet
实现类有TreeSet
Integer,String,Date
都实现了接口java.lang.Comparable的compareTo()
,所以可比较。
o1.compareTo(o2)
import java.util.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class SortedSetTest{
public static void main(String[] args) throws ParseException{
SortedSet<Integer> ss = new TreeSet<Integer>();
ss.add(3);
ss.add(2);
ss.add(5);
ss.add(1);
Iterator itr1 = ss.iterator();
while(itr1.hasNext()){
Object o = itr1.next();
System.out.println(o);
}
SortedSet<String> ss2 = new TreeSet<String>();
ss2.add("John");
ss2.add("Jerry");
ss2.add("Tom");
ss2.add("Cris");
Iterator itr2 = ss2.iterator();
while(itr2.hasNext()){
Object o = itr2.next();
System.out.println(o);
}
SortedSet<Date> ss3 = new TreeSet<Date>();
String st1 = "2012-01-03";
String st2 = "2010-07-01";
String st3 = "2008-08-08";
String st4 = "2012-12-12";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date d1 = sdf.parse(st1);
Date d2 = sdf.parse(st2);
Date d3 = sdf.parse(st3);
Date d4 = sdf.parse(st4);
ss3.add(d1);
ss3.add(d2);
ss3.add(d3);
ss3.add(d4);
Iterator itr3 = ss3.iterator();
while(itr3.hasNext()){
Object o = itr3.next();
System.out.println(o);
}
}
}
import java.util.*;
public class CompTest{
public static void main(String[] args){
SortedSet<Person> ss = new TreeSet<Person>();
Person p1 = new Person("Tom",12);
Person p2 = new Person("Jack",10);
Person p3 = new Person("Ann",14);
Person p4 = new Person("Cris",11);
Person p5 = new Person("Conner",13);
ss.add(p1);
ss.add(p2);
ss.add(p3);
ss.add(p4);
ss.add(p5);
Iterator itr = ss.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
}
}
class Person implements Comparable{
String name;
int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return "Person[name="+name+",age="+age+"]";
}
public int compareTo(Object o){
/*
int age1 = this.age;
int age2 = ((Person)o).age;
return age1-age2;
*/
String s1 = this.name;
String s2 = ((Person)o).name;
return s1.compareTo(s2);
}
}
注意Comparable<T>
,显示支持泛型。
实现java.lang.Comparable<T>.compareTo()
是第一种方式,另一种方式是java.util.Comparator
比较器接口,需要重写compare()
方法。
import java.util.*;
public class ComparatorTest{
public static void main(String[] args){
SortedSet<Product> products = new TreeSet<Product>(new ProductComparator());
/*
//anonymous inner class
SortedSet<Product> products = new TreeSet<Product>(new ProductComparator(){
public int compare(Object o1,Object o2){
double price1 = ((Product)o1).price;
double price2 = ((Product)o2).price;
if(price1==price2){
return 0;
}else if(price1>price2){
return 1;
}else{
return -1;
}
}
});
*/
Product p1 = new Product(12);
Product p2 = new Product(10);
Product p3 = new Product(14);
Product p4 = new Product(11);
Product p5 = new Product(13);
products.add(p1);
products.add(p2);
products.add(p3);
products.add(p4);
products.add(p5);
Iterator itr = products.iterator();
while(itr.hasNext()){
System.out.println(itr.next());
}
}
}
class Product{
double price;
Product(double price){
this.price = price;
}
public String toString(){
return price+"";
}
}
class ProductComparator implements Comparator{
public int compare(Object o1,Object o2){
double price1 = ((Product)o1).price;
double price2 = ((Product)o2).price;
if(price1==price2){
return 0;
}else if(price1>price2){
return 1;
}else{
return -1;
}
}
}
TreeSet
有这样一种构造方法:TreeSet(Comparator<? super E> comparator)
采用了匿名内部类,不推荐,因为这种比较器无法重复利用。
优先选耦合度低的比较器方式。
Map
Map接口实现类:
HashMap, Hashtable,SortedMap.
HashMap
的Key
等同于一个Set
集合
Hashtable
线程安全。但效率低,很少使用。但它有一个重要的类Properties
,该类的key
和value
只能是字符串类型。
SortedMap
的Key
也等同于一个Set
集合
单向链表:节点Entry entry
;
双向链表:java.util.LinkedList
存储在Map集合key部分的元素需要重写hashCode()
和equals()
方法。
如果key重复,则value会覆盖。
HashMap
java.util.HashSet
,底层是HashMap
.
HashMap
底层是Entry
类型数组,即哈希表。
哈希表:单向链表的数组。
类似于字典。增删查询效率都很高。
Entry
是链表类(api),每个节点都有一个final int hash
.
单向链表中每一个节点的hash值是相同的,是Object key经过hashCode()得到的,代表数组下标。
Object get(Object key)
import java.util.*;
public class MapTest01{
public static void main(String[] args){
Map<String,String> persons = new HashMap<String,String>();
persons.put("1000","Tom");
persons.put("1000","Jack");
persons.put("1001","Tom");
persons.put("2000","Jerry");
persons.put("3000","John");
Collection values = persons.values();
Iterator itr1 = values.iterator();
while(itr1.hasNext()){
System.out.println(itr1.next());
}
Set keys = persons.keySet();
Iterator itr2 = keys.iterator();
while(itr2.hasNext()){
Object key = itr2.next();
Object value = persons.get(key);
System.out.println(key+"-->"+value);
}
Set entrySets = persons.entrySet();
Iterator itr3 = entrySets.iterator();
while(itr3.hasNext()){
System.out.println(itr3.next());
}
}
}
向hash表中添加元素:
V put(Object key,Object value)
先hashCode(key)
得到hash值,
若hash表不存在该hash值,则直接加入元素到数组中。
若hash表存在该hash值,则用equals()
遍历链表key,false则添加,true则放弃添加。
Hashtable
默认初始容量(11),负载因子(0.75)。
Properties的key和value都是String类型。
SortedMap
实现类有TreeMap
import java.util.*;
public class SortedMapTest{
public static void main(String[] args){
Map<Product,Double> products = new TreeMap<Product,Double>();
Product p1 = new Product("apple",2.0);
Product p2 = new Product("banana",1.0);
Product p3 = new Product("orange",5.0);
Product p4 = new Product("pear",4.0);
Product p5 = new Product("peach",3.0);
//value:kg
products.put(p1,3.0);
products.put(p2,4.0);
products.put(p3,1.0);
products.put(p4,2.0);
products.put(p5,7.0);
Set entrySets = products.entrySet();
Iterator itr = entrySets.iterator();
while(itr.hasNext()){
System.out.println(itr.next()+"kg");
}
Set keys = products.keySet();
Iterator itr2 = keys.iterator();
while(itr2.hasNext()){
Object k = itr2.next();
Object v = products.get(k);
System.out.println(k+"---"+v+"kg");
}
}
}
class Product implements Comparable{
String name;
double price;
Product(String name,double price){
this.name = name;
this.price = price;
}
public String toString(){
return "["+name+"---"+price+"]";
}
public int compareTo(Object o){
double price1 = this.price;
double price2 = ((Product)o).price;
if(price1==price2){
return 0;
}else if(price1>price2){
return -1;
}else{
return 1;
}
/*
String s1 = this.name;
String s2 = ((Product)o).name;
return s1.compareTo(s2);
*/
}
}
SortedMap的key可以自动排序,需要实现Comparable接口,并单独写一个比较器。
Collections
Collections
是一个类,而Collection
是一个接口。
import java.util.*;
public class CollectionsTest{
public static void main(String[] args){
List c = new ArrayList();
c.add(9);
c.add(6);
c.add(8);
c.add(3);
c.add(5);
for(Iterator itr=c.iterator();itr.hasNext();){
System.out.println(itr.next());
}
Collections.sort(c);
System.out.println("---------------------------");
for(Iterator itr=c.iterator();itr.hasNext();){
System.out.println(itr.next());
}
Set s = new HashSet();
s.add(9);
s.add(6);
s.add(8);
s.add(3);
s.add(5);
System.out.println("---------------------------");
List sl = new ArrayList(s);
Collections.sort(sl);
for(int i=0;i<sl.size();i++){
System.out.println(sl.get(i));
}
c.clear();
Person p1 = new Person("Tom",12);
Person p2 = new Person("Jack",10);
Person p3 = new Person("Ann",14);
Person p4 = new Person("Cris",11);
Person p5 = new Person("Conner",13);
c.add(p1);
c.add(p2);
c.add(p3);
c.add(p4);
c.add(p5);
System.out.println("---------------------------");
for(Iterator itr=c.iterator();itr.hasNext();){
System.out.println(itr.next());
}
Collections.sort(c);
System.out.println("---------------------------");
for(Iterator itr=c.iterator();itr.hasNext();){
System.out.println(itr.next());
}
//secure threads
//Collections.synchronizedList(c);
}
}
class Person implements Comparable{
String name;
int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return "["+name+"---"+age+"]";
}
public int compareTo(Object o){
double age1 = this.age;
double age2 = ((Person)o).age;
if(age1==age2){
return 0;
}else if(age1>age2){
return -1;
}else{
return 1;
}
/*
String s1 = this.name;
String s2 = ((Person)o).name;
return s1.compareTo(s2);
*/
}
}
泛型
这是JDK5.0加入的特性,和自动拆装箱一样是编译器的特点。
为什么引入?
- 统一集合中的数据类型
- 减少强制类型转换(Object->其他类)
优点:同一类型,减少强制转换。
缺点:只能存储一种类型。
<E>指Element
<K,V>指键值对
List<String> strs = new ArrayList<Stirng>();
Iterator<String> it = strs.iterator();
while(it.hasNext()){
String s = it.next;
}
//下面是不用泛型的情况
while(it.hasNext()){
Object o = it.next();
if(o instanceof String){
String s = (String)o;
}
}
注意实现Comparable接口的区别
自定义泛型
class MyClass<T>{}
__foreach__
也是JDK5.0加入的特性
for(类型 变量:数组名/集合名)
集合需要用泛型
否则类型应该为Object
缺点:没有下标