能够封装其他类对象的一个类,叫容器。容器中放入的是一些对象。
集合类型分三种:
Set,List,Map
Set:不区分元素顺序,不允许出现重复元素
List:区分元素顺序,允许包含重复元素
Map:映射中保存成对的“键-值”,映射中不能包含重复的键,每个键只能映射一个值。(哈希表)
实现类:HashSet, LinkList,ArrayList,HashMap
1、Collection接口—定义了存储一组对象的方法。其子接口Set和List分别定义了存储的方式
Collection接口中的方法:
(1)Object [] toArray()
容器不是数组,不能通过下标访问;若想当做数组用,利用Object[] bb=aa.toArray()转换为数组,调用bb[index]
(2)add,remove,addAll,removeAll,clear,boolean equals(Object o),int hashCode(),
2、Collection接口实现类的实例
所有添加到Collection容器中的对象都应该重写父类Object的toString方法。
将自己定义的类对象放入容器中,需要自己重写toString()方法。
import java.util.*;
public class TestCollection{
public static void main(String[] args){
Collection c = new LinkedList();
c.add(new Student("zhangsan", 80));
c.add(66.6);
System.out.println(c);
}
}
class Student
{
private String name;
private int age;
public Student(String name, int age){
this.name = name;
this.age = age;
}
//如果把toString方法注释掉了,则程序输出结果会有乱码
public String toString() {
return name + " " + age;
}
}
3、List接口中的ArrayList,LinkedList
两者的区别:LinkedList双向链表实现。
4、Collections类,Collection接口
对于Collection接口实现的类,ArrayList、LinkedList本身并没有提供排序,倒置查找等方法,这方法是由Collections类实现,该类有很多public static 方法,可以直接对Collection接口的实现类进行操作。
Collections类常用方法
排序中的问题
import java.util.*;
class Student implements Comparable
{ private int id;
private String name;
public Student(int id, String name)
{
this.id = id;
this.name = name;
}
@Override //伪代码表示重写
public String toString()
{
return id + " " + name; //1000张三
//System.out.println();
}
@Override
public int compareTo(Object o) //父类的引用,比较标准的方法
{
Student st = (Student)o;
if (this.id == st.id)
return 0;
else if (this.id > st.id)
return 1;
else
return -1;
}
}
public class TestList
{
public static void main(String[] args)
{
List L = new ArrayList(); .//多态。当然将L转化数组 ,利用数组进行排序
L.add(new Student(1000, "张三"));
L.add(new Student(1003, "小娟"));
L.add(new Student(1002, "王五"));
L.add(new Student(1001, "李四"));
Collections.sort(L); //若没有compareTo(),比较标准不知道。默认将调用L中的compareTo方法。
System.out.println(L);
}
}
//排序需要比较,利用到Comparabe接口
Comparable接口
compareTo方法的重写
Set接口
Set容器类中有HashSet,TreeSet(类)
问题:无序不重复,不需要实现Comparable接口,进行排序比较。输出的顺序跟添加顺序都不一样,且不允许容器中出现重复元素,对于Set中equals重写。比较对象中的内容,若相等返回true。不同内存,相同内容需要重写,实现true。
为了保证在HashSet容器中添加没重复,必须重写上述两种方法。
(1)重写的原因:
hashCode:两个对象不同,返回的hashCode不同。基本类型类的同样参数new出的对象的hashCode一样,默认都对hashCode进行了重写。
是否重写hashCode值。
将对象aa放入容器S中。
aa对象会根据aa对象里面的hashCode方法(返回某个值)找到对象存放的位置。再通过equals方法比较后面存放的元素是否有相同的元素。
TreeSet放入将自动排序。类实现Comparable接口,并重写compareTo方法。
(2)什么类必须向重写?
3、怎样重写?
equals重写注意将Object类对象ob强制转换为子类对象B bb=(B) ob,进行比较this.id==bb.i
hashCode中,内容一样哈希码一样,基本类型的,通过new Integer(i).hashCode()转换为相同。
返回当前基本类型数据对象的hashCode()方法
/*
Student类必须同时实现equals方法 和 hashCode方法 才可以保证在装入HashSet类时不会出现“重复”装入的情况
重新实现了equals方法 和 hashCode 方法 的正确的程序
*/
import java.util.*;
public class TestHashSet
{
public static void main(String[] args)
{
Collection c = new HashSet();
c.add(new Student(1001, “张三”));
c.add(new Student(1002, “李四”));
c.add(new Student(1003, “王五”)); //10行
c.add(new Student(1003, “王五”));
c.add(new Student(1003, “王五”));
c.add(new Student(1003, “王五”));
c.add(new Student(1003, “王五”)); //14行
Iterator i = c.iterator();
while (i.hasNext())
{
System.out.println(i.next());
}
}
}
class Student
{
private int num;
private String name;
public Student()
{
}
public Student(int num, String name)
{
this.num = num;
this.name = name;
}
public String toString()
{
return "学号: " + this.num + ", 姓名: " + name;
}
public boolean equals(Object o)
{
Student s = (Student)o;
return this.num==s.num && this.name.equals(s.name);
}
public int hashCode()
{
//return num; //如果你设定的学生信息中学号是唯一的,则可以直接用num来作为哈希码
return num * this.name.hashCode();
}
}
Iterator 接口
由于数据的存储方式不同,遍历元素较为麻烦。数组,链表,树。。访问不同
如何忽略存储数据的差别,进行遍历。按照同一方式访问他们的元素
方法
boolean hasNext():游标不动,用来判断当前游标后面是否存在元素,若存在,返回为真,否则为假、初始为值为第一个元素的前面位置。
object next():先返回当前游标右边的元素,然后游标后移一个位置
void remove();
import java.util.*;
public class TestIterator_1
{
//可以遍历所有Collection接口的实现类
public static void showCollection(Collection c)
{
Iterator it = c.iterator(); //Collecion中有Iterator()方法,it就是指针,通过指针调用hasNext方法,it指向第一
//个元素的指针。it.next---it++; it指针可以指向c容器中的元素
while (it.hasNext())
{
System.out.println(it.next());
}
}
public static void main(String[] args)
{
ArrayList al = new ArrayList();
al.add("one");
al.add(22);
al.add(new Point(1,1));
System.out.println("a1 容器的内容是:");
showCollection(al);
HashSet hs = new HashSet();
hs.add("one");
hs.add(22);
hs.add(new Point(1,1));
System.out.println("hs容器的内容是:");
showCollection(hs);
}
}
class Point
{
private int i, j;
public Point(int i, int j)
{
this.i = i;
this.j = j;
}
public String toString()
{
return "[" + i + ", " + j + "]";
}
}
3、Map
为了更加方便的查找某个元素,给出关键字,一次性找出
内部实现:根据每个元素的关键字存放位置,放置元素。给出关键字,计算元素存放的地址。
每个元素映射地址不同,最后映射完,每个元素的地址是连续的。完美情况是这样,设计出来很困难。实际中每个元素之间的地址相差较大,浪费空间。
存在的问题:
关键字出现映射地址一样,hash冲突。
关键字对应的映射地址超出了元素存放的内存区间,没有其地址。
map映射地址数据存放的空间浪费
避免冲突;存储空间内存大小设计与 存放数据大小匹配
哈希因子不能过高,为了避免冲突,但检测到快满时,就会扩充内存。
为了避免哈希冲突,存放方式Hash表。根据关键字找位置,即使两个关键字映射为同样的hashCode,但是仍然比较看看后面是否f,将再继续放入。
Map的实现类HashMap,遍历所有元素利用方法keySet()方法,
import java.util.*;
class Student
{
private int id;
private String name;
private int age;
public Student()
{
}
public Student(int id, String name, int age)
{
this.id = id;
this.name = name;
this.age = age;
}
public int hashCode()
{
return this.name.hashCode()*id*age;
}
public boolean equals(Object o)
{
Student s = (Student)o;
return this.name.equals(s.name) && this.id==s.id && this.age==s.age;
}
public String toString()
{
return id + " " + name + " " + age;
}
}
public class TestHashMap_2
{
public static void main(String[] args){
HashMap hm = new HashMap();
hm.put(1001, new Student(1001, "zhangsan", 20)); //自动封装new integer(1001),1001为将值转换为自动转为integer对象,容器中必须存的是对象
hm.put(1003, new Student(1003, "lisi", 30)); //自动封装
hm.put(new Integer(1004), new Student(1004, "wangwu", 10));
hm.put(1002, new Student(1002, "baichi", 20)); //自动封装
//遍历所有的元素
System.out.println("hm容器中所有的元素是:");
Set s = hm.keySet(); //获取到当前容器键的集合,实际就是Integer对象的集合
Iterator it = s.iterator();
while (it.hasNext()){
//int Key = (Integer)it.next(); // (Integer) 不能省,这里key,定义方法it.next()返回object类型转换为子类, 利用了自动拆分技术
Integer kk = (Integer)it.next(); //kk变量就可以,不是关键字
System.out.println(hm.get(kk));
}
System.out.println("直接查找某一元素");
System.out.println( hm.get(1003) );
System.out.println( hm.get(1005) ); //如果找不到 则直接返回null,而不是抛出异常
}
}
泛型:限制指定某一时刻,某一个容器放置的元素类型。
对于Iterator,说明内部数据可以是任意的,但是对于具体某一次运行,可以设定对象类型
对于接口以及实现接口的类都需要指定。