容器
容器
1、J2SDK所提供的容器API位于java.util包内
2、容器API的类图结构如下图所示:
Collection 接口
定义了存取一组对象的方法,其子接口Set和List分别定义了存储方式
Set中的数据对象没有顺序且不可以重复
List中的数据对象有顺序且可以重复。(对象的equals方法比较相同)
Map接口
定义了存储“键(key)-值(value)映射对”的方法。
import java.util.*;
public class Test{
public static void main(String []args){
Collection c=new ArrayList(); //父类引用指向子类对象时,只能用父类的方法
c.add("hello");
c.add(new Name("l1","f1"));
c.add(new Integer(100)); //容器中只能添加对象,不能添加基本数据类型元素
System.out.println(c.size());
System.out.println(c); //其实是调用了c.toString()方法,继而调用了c中每个元素的toString方法。可以修改Name类中的toString方法来试验下
}
}
class Name{
private String l;
private String f;
Name(String l1,String f1){
this.l=l1;
this.f=f1;
}
public String toString(){
return l+" "+f;
}
}
注意:
重写对象的equals方法,则必须重写对象的hashcode方法
两个对象互相的eqauls,则两个对象具备相同的hashcode
容器类对象在调用remove、contains等方法时需要比较对象是否相等,这会涉及到对象类型的equals方法和hashCode方法;对于自定义的类型,需要重写equals和hashCode方法以实现自定义的对象相等规则。
注意: 相等的对象应该具有相等的hash codes。
下例中Name 类没有重写equals方法,所以其equals方法还是继承自Object的equa方法,所以删除不了容器中最后一个元素。
import java.util.*;
public class Test2{
public static void main(String []args){
Collection c=new ArrayList(); //父类引用指向子类对象时,只能用父类的方法
c.add("hello");
c.add(new Name("l1","f1"));
c.add(new Integer(100)); //容器中只能添加对象,不能添加基本数据类型元素
//查看API的Object的equals方法
c.remove("hello"); //查看API String的equals方法
c.remove(new Integer(100)); //查看API Integer的equals方法
System.out.println(c.remove(new Name("l1","f1")));
System.out.println(c);
}
}
class Name{
private String l;
private String f;
Name(String l1,String f1){
this.l=l1;
this.f=f1;
}
public String toString(){
return l+" "+f;
}
/*
public boolean equals(Object o){
if(o instanceof Name){
Name name=(Name)o;
return (l.equals(name.l))&&(f.equals(name.f));
}
return super.equals(o);
}
public int hashCode(){
return l.hashCode();
}
*/
}
下例中Name类重写了equals方法,所以可以remove
import java.util.*;
public class Test3{
public static void main(String []args){
Collection c=new ArrayList(); //父类引用指向子类对象时,只能用父类的方法
c.add("hello");
c.add(new Name("l1","f1"));
c.add(new Integer(100)); //容器中只能添加对象,不能添加基本数据类型元素
//查看API的Object的equals方法
c.remove("hello"); //查看API String的equals方法
c.remove(new Integer(100)); //查看API Integer的equals方法
System.out.println(c.remove(new Name("l1","f1")));
System.out.println(c);
}
}
class Name{
private String l;
private String f;
Name(String l1,String f1){
this.l=l1;
this.f=f1;
}
public String toString(){
return l+" "+f;
}
public boolean equals(Object o){
if(o instanceof Name){
Name name=(Name)o;
return (l.equals(name.l))&&(f.equals(name.f));
}
return super.equals(o);
}
public int hashCode(){
return l.hashCode();
}
}
Iterator接口
所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象。
Iterator<E> | iterator()
Returns an iterator over the elements in this collection.
|
Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。
Iterator接口定义了如下方法:
//判断游标右边是否有元素
boolean hasNext()
Returns true if the iteration has more elements.
//返回游标游标的元素并将游标移动到下一个位置
(Object)E next()
Returns the next element in the iteration.
//删除游标左边的元素,在执行完next之后该操作只能执行一次
void remove()
Removes from the underlying collection the last element returned by this iterator (optional operation).
import java.util.*;
public class Test4{
public static void main(String[] args){
Collection c=new HashSet();
c.add(new Name("f1","l1"));
c.add(new Name("f2","l2"));
c.add(new Name("f3","l3"));
Iterator i=c.iterator(); //所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象。
while(i.hasNext()){
Name n=(Name)i.next(); //next()的返回值是Object类型,需要转换为相应类型
System.out.println(n.getName());
}
}
}
class Name{
private String l;
private String f;
Name(String l1,String f1){
this.l=l1;
this.f=f1;
}
public String getName(){
return l+" "+f;
}
}
Iterator对象的remove方法是在迭代过程中删除元素的唯一的安全方法。
JDK1.5增强的for循环
增强的for循环低于遍历array或Collection的时候相当简便
缺陷:
数组:不能方便的访问下标值
集合:与使用Iterator相比,不能方便的删除集合中的内容
在内部也是调用Iterator
总结:除了简单遍历并读出其中的内容外,不建议使用增强for。
import java.util.*;
public class EnhancedFor{
public static void main(String[] args){
int []a={1,2,3,4};
for(int i:a){
System.out.println(i);
}
Collection c=new ArrayList();
c.add("hello");
c.add("world");
c.add("people");
for(Object o:c){
System.out.println(o);
}
}
}
Set接口
Set接口是Collection的子接口,Set接口没有提供额外的方法,但实现Set接口的容器类中的元素师没有顺序的,而且不可以重复。
Set接口可以与数学中“集合”的概念相对应。
J2SDK API中所提供的Set容器类有HashSet,TreeSet等。
import java.util.*;
public class Test6{
public static void main(String[] args){
Set s=new HashSet();
s.add("hello");
s.add(new Integer(100));
s.add(new Name("f1","l1"));
s.add("hello"); //相同元素不会被加入!
s.add(new Name("f1","l1")); //如果Name重写了如下的equals方法,则 相同元素不会被加入!如果没有重写equals方法,则是继承Object的equals方法,则不是相同元素,可以加入!
System.out.println(s);
}
}
class Name{
private String l;
private String f;
Name(String l1,String f1){
this.l=l1;
this.f=f1;
}
public String toString(){
return l+" "+f;
}
public boolean equals(Object o){
if(o instanceof Name){
Name name=(Name)o;
return (l.equals(name.l))&&(f.equals(name.f));
}
return super.equals(o);
}
public int hashCode(){
return l.hashCode();
}
}
List接口
List接口是Collection的子接口,实现List接口的容器类中的元素是有顺序的,二期可以重复。
List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。
J2SDK所提供的List容器类有ArrayList,LinkedList等
List方法举例
import java.util.*;
public class Test8{
public static void main(String[] args){
List l1=new LinkedList();
for(int i=0;i<=5;i++){
l1.add("a"+i);
}
System.out.println(l1);
l1.add(3,"a100");
System.out.println(l1);
l1.set(6,"a200");
System.out.println(l1);
System.out.println((String)l1.get(2));
l1.remove(1);
System.out.println(l1);
}
}
List常用算法
类java.util.Collections提供了一些静态方法实现了基于List容器的一些常用算法!
void sort(List)对List容器内的元素排序
void shuffle(List)对List容器内的对象进行随机排列
void reverse(List)对List容器内的对象进行逆序排列
void fill(List,object)用一个特定的对象重写整个List容器
void copy(List dest,List src)将src List容器内容拷贝到dest List容器
int binarySearch(List,Object) 对于顺序的List容器,采用折半查找的方法查找特定对象
import java.util.*;
public class Test9{
public static void main(String[] args){
List l1=new LinkedList();
List l2=new LinkedList();
for(int i=0;i<=9;i++){
l1.add("a"+i);
}
System.out.println(l1);
Collections.shuffle(l1); //随机排列
System.out.println(l1);
Collections.reverse(l1); //逆序
System.out.println(l1);
Collections.sort(l1); //排序
System.out.println(l1);
System.out.println(Collections.binarySearch(l1,"a5"));
}
}
Comparable接口
问题:上面的算法根据什么确定容器中对象的“大小”顺序?
所有可以“排序”的类都实现了java.lang.Comparable接口,Comparable接口中只有一个方法:
public int compareTo(object obj);//返回0表示this==obj;返回正数表示this>obj;返回负数表示this<obj
实现了Comparable接口的类 通过实现compareTo方法从而确定该类对象的排序方式
public class Name implements Comparable{
private String f;
private String l;
public int compareTo(Object o){
Name n=(Name)o;
int x=f.compareTo(n.f);
return x!=0? x:l.compareTo(n.l);
}
}
如何选择数据结构
衡量标准:读的效率和改的效率
Array读快改慢
Linked改快读慢
Hash两者之间
Map接口
实现Map接口的类用来存储 键——值 对。
Map接口的实现类有HashMap和TreeMap等
Map类中存储的键——值对通过键来标识,所以键值不能重复。 (键就是索引,比较索引是否重复就是用equals方法,但为了效率更高,用hashCode方法!因为equals方法相等则hashcode也相等)
object put(object key,object vaue);
object get(object key); //返回的是value对象
object remove(object key);
boolean containsKey(object key);
boolean containsValue(object value);
int size();
boolean isEmpty();
void putAll(Map t);
void clear();
import java.util.*;
public class Test11{
public static void main(String[] args){
Map m1=new HashMap();
Map m2=new TreeMap();
m1.put("one",new Integer(1));
m1.put("two",new Integer(2));
m1.put("three",new Integer(3));
m2.put("A",new Integer(1));
m2.put("B",new Integer(2));
System.out.println(m1.size());
System.out.println(m1.containsKey("One"));
System.out.println(m2.containsValue(new Integer(1)));
if(m1.containsKey("two")){
int i=((Integer)m1.get("two")).intValue();
System.out.println(i);
}
Map m3=new HashMap(m1);
m3.putAll(m2);
System.out.println(m3);
}
}
Auto-boxing/unboxing
在合适的时机自动打包、解包
自动将基础类型转换为对象
自动将对象转换为基础类型
import java.util.*;
public class Test11AutoboxingUnboxing{
public static void main(String[] args){
Map m1=new HashMap();
Map m2=new TreeMap();
//m1.put("one",new Integer(1));
m1.put("one",1);
//m1.put("two",new Integer(2));
m1.put("two",2);
//m1.put("three",new Integer(3));
m1.put("three",3);
//m2.put("A",new Integer(1));
m2.put("A",1);
//m2.put("B",new Integer(2));
m2.put("B",2);
System.out.println(m1.size());
System.out.println(m1.containsKey("One"));
System.out.println(m2.containsValue(new Integer(1)));
if(m1.containsKey("two")){
//int i=((Integer)m1.get("two")).intValue();
int i=(Integer)m1.get("two");
System.out.println(i);
}
Map m3=new HashMap(m1);
m3.putAll(m2);
System.out.println(m3);
}
}
泛型
import java.util.*;
public class BasicGeneric{
public static void main(String[] args){
List<String> s=new ArrayList<String>();
s.add("aa");
s.add("bb");
s.add("cc");
for(int i=0;i<s.size();i++){
String ss=s.get(i);
System.out.println(ss);
}
Collection <String> c1=new HashSet();
c1.add("aa");
c1.add("bb");
c1.add("cc");
for(Iterator<String> i=c1.iterator();i.hasNext();){
String si=i.next();
System.out.println(si);
}
}
}
class MyName implements Comparable<MyName>{
int age;
public int compareTo(MyName mn){
if(this.age>mn.age)return 1;
if(this.age<mn.age)return -1;
else
return 0;
}
}
import java.util.*;
public class BasicGeneric2{
public static void main(String[] args){
Map<String,Integer> m1=new HashMap<String,Integer>();
Map<String,Integer> m2=new TreeMap<String,Integer>();
m1.put("one",1);
m1.put("two",2);
m1.put("three",3);
m2.put("A",1);
m2.put("B",2);
System.out.println(m1.size());
System.out.println(m1.containsKey("One"));
System.out.println(m2.containsValue(1));
if(m1.containsKey("two")){
int i=(m1.get("two"));
System.out.println(i);
}
Map m3=new HashMap(m1);
m3.putAll(m2);
System.out.println(m3);
}
}
import java.util.*;
public class BasicGeneric3{
private static final int ONE=1;
public static void main(String[] args){
Map<String,Integer> m=new HashMap<String,Integer>();
for(int i=0;i<args.length;i++){
if(!m.containsKey(args[i])){
m.put(args[i],1);
}
else{
int freq=m.get(args[i]);
m.put(args[i],freq+1);
}
}
System.out.println(m.size()+" distinct words!");
System.out.println(m);
}
}