思维导图
Collection接口
容器:顾名思义,从字面上的理解就是能够容纳很多东西的器皿;
- 我们已经有各种各样的变量了,难道那个就不是容器了吗?
- 及时变量不够,我们还有数组呢?
- 解答:一个人事管理系统,我们可以通过new很多个name变量来解决,但是如果这个系统有成千上万个人呢?那我们是不是需要new成千上万个name呢?当然不是,这样也太可怕了。那有人会说,我们可以定义一个数组呢,但问题是你知道这个数组需要多大吗?太大浪费内存空间,太小不够装怎么办?所有就有了容器这个概念的产生。
- 容器就是一个你需要多大就给你多大
数组与容器的区别:
数组元素既可以是基本类型的值,也可以是对象,而集合里面只能保存对象(实际上保存的是引用类型的变量——。
本章重点(2136):二张图,一个类,三个知识点,六个接口
一张图:
- JDK所提供的容器API位于java.util包中;
- java的集合主要由两个接口派生而成:Collection和Map,Collection和Map是java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
容器API的类图结构如下:Collection体系集合:Set(无序集合)、List(有序集合)、Queue(队列实现)
Map体系集合:用于保存具有映射关系的数据(共同的特征是:都是键值对形式,通常键不可重复,值可以重复)
小结:可以将java中的集合分成三大类
一、Set(罐子):无顺序不可重复——根据元素本身访问
二、List(数组):有顺序可变长度——根据元素索引访问
三、Map(罐子):每项数据两个值——根据元素Key访问
Collection接口定义了存取一组对象的方法,其子接口set和list分别定义了存储的方式:
- set中的数据对象没有顺序且可以重复;
- list中的数据对象有顺序且可以重复;
- map接口定义了存储键值映射对的方法。
Collection接口中所定义的方法:(容器跟生活生活中的容器无异,无非都是添加、删除、清空、判断容器是否为空)
Boolean add(Object o) |
向集合里添加一个元素,改变则返回true |
Boolean addAll(Object c) |
向集合c里的所有元素添加到指定集合,指定集合改变返回true |
Void clear() |
清除集合里所有元素,集合长度变为0 |
Boolean contains(Object o) |
返回集合里是否包含指定元素 |
Boolean containsAll(Object 哦) |
返回集合里是否包含集合c里的所有元素 |
Boolean isEmpty() |
返回集合是否为空,集合长度为0时返回true,否则返回false |
Boolean remove(Object o) |
删除集合里指定元素o,有多个o时只删除一个符合条件的,返回true |
Iterator iterator() |
返回一个iterator对象,用于遍历集合里的元素 |
Boolean removeAll(Collection c) |
从集合中删除集合c包含的所有元素,如果删除一个或一个以上返回true |
Boolean retainAll(Collection c) |
从集合中删除集合c里面不包含的元素,如该操作改变了调用该方法的集合,则该方法返回true |
Int size() |
该方法返回集合元素的个数 |
Object[] toArray() |
该方法把集合转换成一个数组,所有集合元素都变成了对应的数组元素 |
实例代码:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new ArrayList();
c.add("Hello");
c.add(new Name("f1","11"));
c.add(new Integer(100));
System.out.println(c.size());
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
}
输出结果:
异常解决:
原因:这个是1.5以后的版本才会有这个警告提示,主要是警告用户没有使用泛型来限制集合里的元素类型
解决:可以在class类里面加上这句代码就可以了或者不用管他。
@SuppressWarnings("unchecked")
Collection方法举例:
- 容器类对象再调用remove、contains等方法时需要比较对象是否相等,这个会涉及到对象类类型的equals方法和hashCode方法;对于自定义的类型需要重写equals和hashCode方法实现自定义的对象相等规则。
- 注意:相等的对象应该具有相等hash codes。
- 增加Name类的equals和hashCode方法如下:
实例代码:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new HashSet();
c.add("Hello");
c.add(new Name("f1","11"));
c.add(new Integer(100));
c.remove("Hello");
c.remove(new Integer(100));
System.out.println(c.remove(new Name("f1","11")));
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
输出结果:如果没有添加equals和hashCode方法时无法移除f1和11的
添加这两个方法后的结果如下:
Iterator接口
- Iterator接口是Collection接口的父接口,因此Collection集合也可以直接调用该方法;
- Collection系列集合、Map系列集合主要用于盛装其他对象,而Iterator主要用于遍历Collection集合中的元素;
- 所有实现Collection接口的容器类都有一个Iterator方法用以返回一个实现了Iterator接口的对象;
- Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作;
- Iterator接口定义了如下方法:
- Boolean hasNext();//判断游标右边是否有元素
- Object next();//返回游标右边的元素并将游标移动到下一个位置
- Void remove();//删除游标左面的元素,在执行完next之后该操作只执行一次。
- Void forEachRemaining(Consumer action)java8新增
实例代码:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new HashSet();
c.add(new Name("f1","11"));
c.add(new Name("f2","12"));
c.add(new Name("f3","13"));
Iterator i = c.iterator();
while(i.hasNext()){
Name n = (Name)i.next();
System.out.println(n.getFirstName()+" ");
}
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
输出结果:
Iterator对象的remove方法时在迭代过程中删除元素的唯一的安全方法
实例代码:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Collection c = new HashSet();
c.add(new Name("f111","1111"));
c.add(new Name("f2222","12"));
c.add(new Name("f3","11113"));
for(Iterator i = c.iterator();i.hasNext();){
Name n = (Name)i.next();
if(name.getFirstName().length()<3){
i.remove();
}
}
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
Set接口
- set接口是collection的子接口,set接口没有提供额外的方法,但实现set接口的容器类中的元素是没有顺序的,而且不可用重复;
- set容器可以与数学中的集合的概念相对应;
- Jdk API中的所提供的set容器类有HashSet,TreeSet等。
实例代码:
import java.util.*;
public class TestCollection{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Set c = new HashSet();
c.add("hello");
c.add("world");
c.add(new Name("f1","f2"));
c.add(new Integer(100));
c.add(new Name("f1",",f2"));
c.add("hello");
System.out.println(c);
}
}
class Name{
private String firstName,lastName;
public Name(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName(){
return firstName;
}
public String getLastName(){
return lastName;
}
public String toString(){
return firstName + "" + lastName;
}
public boolean equals(Object obj){
if(obj instanceof Name){
Name name = (Name)obj;
return(firstName.equals(name.firstName)) && (lastName.equals(name.lastName));
}
return super.equals(obj);
}
public int hashCode(){
return firstName.hashCode();
}
}
输出结果:
List接口
- list接口是collection的子接口,实现list接口的容器类中的元素是有顺序的,而且可以重复;
- list容器中的元素都对应一个整数型的序列号记载其在容器中的位置,可以根据序号存取容器中的元素;
- jdk所提供的list容器类有ArrayList(数组),linkedlist(链表)等
实例代码:
import java.util.*;
public class TestList{
@SuppressWarnings("unchecked")
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)+"");
System.out.println(l1.indexOf("a3"));
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容器,采用折半查找的方法查找特定的对象
Comparable 接口
- 问题:上面的算法根据什么确定容器中对象的大小顺序?
- 所有可以排序的类都实现了java.lang.Comparable接口,Comparable接口中只有一个方法:public int compareTo(Object obj);该方法:返回0表示this==obj;返回正数表示this>obj;返回负数表示this<obj
- 实现了comparable接口的类通过实现comparaTo方法从而确定该类对象的排序方式。
如何选择数据结构:
衡量标准:读的效率和改的效率
- Array读快改慢
- Linked改快读慢
- Hash两者之间
Map接口
- 实现Map接口的类用来存储键值对;
- Map 接口的实现有HashMap和TreeMap等;
- Map类中存储的键值对通过建来表示,所以键值不能重复(说的是equals)。
1 |
void clear( ) 从此映射中移除所有映射关系(可选操作)。 |
2 |
boolean containsKey(Object k) 如果此映射包含指定键的映射关系,则返回 true。 |
3 |
boolean containsValue(Object v) 如果此映射将一个或多个键映射到指定值,则返回 true。 |
4 |
Set entrySet( ) 返回此映射中包含的映射关系的 Set 视图。 |
5 |
boolean equals(Object obj) 比较指定的对象与此映射是否相等。 |
6 |
Object get(Object k) 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 |
7 |
int hashCode( ) 返回此映射的哈希码值。 |
8 |
boolean isEmpty( ) 如果此映射未包含键-值映射关系,则返回 true。 |
9 |
Set keySet( ) 返回此映射中包含的键的 Set 视图。 |
10 |
Object put(Object k, Object v) 将指定的值与此映射中的指定键关联(可选操作)。 |
11 |
void putAll(Map m) 从指定映射中将所有映射关系复制到此映射中(可选操作)。 |
12 |
Object remove(Object k) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 |
13 |
int size( ) 返回此映射中的键-值映射关系数。 |
14 |
Collection values( ) 返回此映射中包含的值的 Collection 视图。 |
实例代码:(含自动打包和解包)
import java.util.*;
public class TestMap{
@SuppressWarnings("unchecked")
public static void main(String[] args){
Map m1 = new HashMap();
Map m2 = new HashMap();
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 = (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 TestArgsWords{
private static final Integer ONE = new Integer(1);
@SuppressWarnings("unchecked")
public static void main(String[] args){
Map m = new HashMap();
for(int i=0;i<args.length;i++){
Integer freq = (Integer)m.get(args[i]);
m.put(args[i],(freq==null ? ONE : new Integer(freq.intValue()+1)));
}
System.out.println(m.size()+"distinct words detected:");
System.out.println(m);
}
}
输出结果:
实例代码:(采用打包解包的形式写)
import java.util.*;
public class TestArgsWords{
private static final Integer ONE = new Integer(1);
@SuppressWarnings("unchecked")
public static void main(String[] args){
Map m = new HashMap();
for(int i=0;i<args.length;i++){
//Integer freq = (Integer)m.get(args[i]);
int freq = (Integer)m.get(args[i])==null ? 0 : (Integer)m.get(args[i]);
//m.put(args[i],(freq==null ? ONE : new Integer(freq.intValue()+1)));
m.put(args[i],freq == 0 ? ONE : freq + 1);
}
System.out.println(m.size()+"distinct words detected:");
System.out.println(m);
}
}
输出结果:
泛型
java集合的缺点是——把一个对象丢进集合里面之后,集合就会忘记这个对象的数据类型,当再次取出该对象时,该对象的编译类型就变成了Object类型(运行时类型没有变)。
java集合被设计成这样主要是因为设计者不知道我们会用集合来装什么类型的对象,所以设计成了可以装任何类型的对象。
因此存在两个问题:
一、集合对元素的类型没有任何的限制,如果我只想装Dog对象,程序可以轻易的将Cat对象丢进去;
二、将对象丢进集合时,集合丢失了对象的状态信息,集合只知道他装的是Object,因此取来的时候需要强制转换。
所谓泛型:就是允许在定义类、接口、方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方法时动态的指定。
实例代码:
import java.util.*;
public class BasicGeneric{
@SuppressWarnings("unchecked")
public static void main(String[] args){
List<String> c = new ArrayList<String>();
c.add("aaa");
c.add("bbb");
c.add("ccc");
for(int i=0;i<c.size();i++){
String s = c.get(i);
System.out.println(s);
}
Collection<String> c2 = new HashSet<String>();
c2.add("aaa");
c2.add("bbb");
c2.add("ccc");
for(Iterator<String> it = c2.iterator();it.hasNext();){
String s = it.next();
System.out.println(s);
}
}
}
class MyName implements Comparable<MyName>{
int age;
public int compareTo(MyName mn){
if(this.age > mn.age)return 1;
else if(this.age < mn.age)return -1;
else return 0;
}
}
输出结果: