黑马程序员——集合框架

来源:互联网 发布:河北大学网络教育招生 编辑:程序博客网 时间:2024/05/21 09:53

------- android培训、java培训、期待与您交流! ----------

集合框架


一、概述

集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。

  • 接口:是代表集合的抽象数据类型。接口允许集合独立操纵其代表的细节。在面向对象的语言,接口通常形成一个层次。
  • 实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构。
  • 算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。

Java集合框架:

1. 什么是框架:类库的集合

2. 集合框架:用来表示和操作的统一的框架,包含了实现集合的接口与类

3. 集合:存放数据的容器。集合框架包含了两部分:一部分是接口,一部分是类

4. 为什么会出现接口:因为集合框架中的很多类,功能是相似的,所以用接口来规范类。


主要结构图:



注:1. 在集合框架中,接口Map和Collection在层次结构上没有任何亲缘关系,它们是截然不同的。

        2. 不要简单的认为集合类就这些,jdk中集合类有很多这些是我们经常用到的而已,Collection、List、Set、Queue和Map都是接口(Interface),不是具体的类实现。


为什么出现集合类?

面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。

 

数组和集合类同是容器,有何不同?

数组虽然也可以存储对象,但长度是固定的;集合长度是可变的。

数组中可以存储基本数据类型,集合只能存储对象。

 

集合类的特点:

集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。

 

为什么会出现这么多的容器呢?

因为每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。



二、共性方法

1,add方法的参数类型是Object。以便于接收任意类型对象。

2,集合中存储的都是对象的引用(地址)。



三、迭代器

什么是迭代器呢?

其实就是集合的取出元素的方式。

  就把取出方式定义在集合的内部。这样取出方式就可以直接访问集合内部的元素。那么取出方式就被定义成了内部类。

而每一个容器的数据结构不同,所以取出的动作细节也不一样。但是都有共性内容:判断和取出。那么可以将这些共性抽取。

那么这些内部类都符合一个规则,该规则是Iterator。


如何获取集合的取出对象呢?

通过一个对外提供的方法。iterator();

格式:

                ArrayList al = new ArrayList();//1.添加元素。al.add("java01");al.add("java02");                Iterator it = al.iterator(); //获取迭代器,用于取出集合中的元素。while (it.hasNext()){System.out.println(it.next());}


例如:

import java.util.*;class CollectionDemo {public static void main(String[] args) {//method_2();method_get();}public static void method_get(){ArrayList al = new ArrayList();//1.添加元素。al.add("java01");al.add("java02");al.add("java03");al.add("java04");/*Iterator it = al.iterator(); //获取迭代器,用于取出集合中的元素。while (it.hasNext()){sop(it.next());}*/for (Iterator it=al.iterator(); it.hasNext(); ){sop(it.next());}}public static void method_2(){ArrayList al1 = new ArrayList();al1.add("java01");al1.add("java02");al1.add("java03");al1.add("java04");ArrayList al2 = new ArrayList();al2.add("java03");al2.add("java04");al2.add("java05");al2.add("java06");//al1.retainAll(al2);//取交集。al1中只会保留和al2中相同的元素。al1.removeAll(al2);sop("al1:"+al1);sop("al2:"+al2);}public static void base_method(){//创建一个集合容器,使用collection接口的子类。ArrayListArrayList al = new ArrayList();//1.添加元素。al.add("java01");  //add(Object obj);al.add("java02");al.add("java03");al.add("java04");//打印原集合sop("原集合:"+al); //结果:[java01, java02, java03, java04]//3.删除元素。//al.remove("java02"); //结果:[java01, java03, java04]//al.clear();  //清空集合。结果为:[]//4.判断元素。sop("java03是否存在:"+al.contains("java03"));sop("集合是否为空?"+al.isEmpty());//2.获取个数,集合长度。sop("size:"+al.size());//打印改变后的集合。sop(al);}public static void sop(Object obj){System.out.println(obj);}}



四、List集合共性方法

1、ListIterator

List集合特有的迭代器:ListIterator是Iterator的子接口。在迭代时,不可以通过集合对象的方法操作集合中的元素。

因为会发生ConcurrentModificationException异常。所以,在迭代时,只能用迭代器的方法操作元素。可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作。如果想要其他的操作,如添加、修改等。就需要使用其子接口,ListIterator。

该接口只能通过List集合的ListIterator方法获取。



2、Collection

|--List:元素是有序的;元素可以重复。因为该集合体系有索引。

|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快,但是增删稍慢。线程不同步。

|--LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。

|--Vector:底层是数组数据结构。线程同步。被ArrayList替代了。

|--Set:元素是无序的;元素不可以重复。

 

List:

特有方法,凡是可以操作角标的方法都是该体系特有的方法。

 

add(index,element);

addAll(index,Collection);

remove(index);

set(index,element);

get(index);

subList(from,to);

listIterator();

int indexOf(obj):获取指定元素的位置。

ListIterator listIterator();

 例如:

import java.util.*;class ListDemo {public static void sop(Object obj){System.out.println(obj);}public static void method(){ArrayList al = new ArrayList();//添加元素。al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);//在指定位置添加元素。al.add(1,"java09");//删除指定位置的元素//al.remove(2);//修改元素。//al.set(2,"java07");//通过角标获取元素。sop("get(1):"+al.get(1));sop("改变后是:"+al);//获取所有元素。for (int x=0; x<al.size(); x++){System.out.println("al("+x+")="+al.get(x));}//用迭代器获取所有元素。Iterator it=al.iterator();while (it.hasNext()){sop("next:"+it.next());}//通过indexOf获取对象的位置。sop("index="+al.indexOf("java02"));List sub=al.subList(1,3);sop("sub="+sub);}public static void main(String[] args) {//演示列表迭代器。ArrayList al = new ArrayList();//添加元素。al.add("java01");al.add("java02");al.add("java03");sop("原集合是:"+al);ListIterator li=al.listIterator();//sop("hasPrevious():"+li.hasPrevious());while (li.hasNext()){Object obj=li.next();if(obj.equals("java02"))li.set("java06");//li.add("java009");}while (li.hasPrevious()){sop("previous::"+li.previous());}//sop("hasNext():"+li.hasNext());//sop("hasPrevious():"+li.hasPrevious());sop("改变后的集合:"+al);/*//在迭代过程中,准备添加或者删除元素。Iterator it=al.iterator();while (it.hasNext()){Object obj=it.next();if(obj.equals("java02"))it.remove();  //将java02的引用从集合中删除了。//al.add("java008");sop("obj="+obj);}sop("改变后的集合:"+al);*/}}

3、Vector中的枚举

枚举就是Vector特有的取出方式。发现枚举和迭代器很像,其实枚举和迭代是一样的。

因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。枚举郁郁而终了。

例如:

import java.util.*;class VectorDemo {public static void main(String[] args) {Vector v=new Vector();v.add("java01");v.add("java02");v.add("java03");v.add("java04");Enumeration en=v.elements();while (en.hasMoreElements()){System.out.println(en.nextElement());}}}


4、LinkedList

LinkedList:特有方法:

addFirst();

addLast();

getFirst();

getLast();

获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException。

 

removeFirst();

removeLast();

获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException。

 

在JDK1.6出现了替代方法。

offerFirst();

offerLast();

peekFirst();

peekLast();

获取元素,但不删除元素。如果集合中没有元素,会返回null。

 

pollFirst();

pollLast();

获取元素,但是元素被删除。如果集合中没有元素,会返回null。

例如:

import java.util.*;class LinkedListDemo {public static void main(String[] args) {LinkedList link=new LinkedList();link.addLast("java01");link.addLast("java02");link.addLast("java03");link.addLast("java04");while (!link.isEmpty()){System.out.println(link.removeFirst());}}public static void sop(Object obj){System.out.println(obj);}}


5、ArrayList

/*例如:去除ArrayList集合中的重复元素。*/import java.util.*;class ArrayListTest {public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {ArrayList al=new ArrayList();al.add("java01");al.add("java02");al.add("java01");al.add("java02");al.add("java01");al.add("java03");/*在迭代时循环中next调用一次,就要hasNext判断一次。Iterator it=al.iterator();while (it.hasNext()){sop(it.next()+"......"+it.next());}*/sop(al);al=singleElement(al);sop(al);}public static ArrayList singleElement(ArrayList al){//定义一个临时容器。ArrayList newAl=new ArrayList();Iterator it=al.iterator();while (it.hasNext()){Object obj=it.next();if(!newAl.contains(obj))newAl.add(obj);}return newAl;}}



五、Set

Set集合的功能和Collection是一致的。

|--Set:元素是无序(存入和取出的顺序不一定一致);元素不可以重复。

|--HashSet:底层数据结构是哈希表。线程是非同步的。

HashSet是如何保证元素唯一性的呢?

是通过元素的两个方法,hashCode和equals来完成。

如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals。

注意:对于判断元素是否存在,以及删除等操作,依赖的方法时元素的hashCode和equals方法。

|--TreeSet:可以对Set集合中的元素进行排序。

底层数据结构是二叉树。

保证元素唯一性的依据:compareTo方法return 0;

 

TreeSet排序的第一种方式:让元素自身具备比较性。

元素需要实现Comparable接口,覆盖compareTo方法。这种方式也称为元素的自然顺序,或者叫做默认顺序。

 

TreeSet的第二种排序方式:

当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。在集合初始化时,就有了比较方式。

 

记住:排序时,当主要条件相同时,一定要判断一下次要条件。


1、HashSet

例如:

import java.util.*;class HashSetTest {public static void sop(Object obj){System.out.println(obj);}public static void main(String[] args) {HashSet hs=new HashSet();hs.add(new Person("a1",11));hs.add(new Person("a2",12));hs.add(new Person("a3",13));hs.add(new Person("a2",12));//sop("a1:"+hs.contains(new Person("a2",12)));hs.remove(new Person("a3",13));Iterator it=hs.iterator();while (it.hasNext()){Person p=(Person)it.next();sop(p.getName()+"::"+p.getAge());}}}class Person{private String name;private int age;Person(String name,int age){this.name=name;this.age=age;}public int hashCode(){System.out.println(this.name+"...hashCode");return name.hashCode()+age*39;//return 60;}public boolean equals(Object obj){if(!(obj instanceof Person))return false;Person p=(Person)obj;System.out.println(this.name+"...equals..."+p.name);return this.name.equals(p.name) && this.age==p.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;}}


2、TreeSet

                TreeSet ts=new TreeSet();ts.add("cba");ts.add("abcd");ts.add("aaa");ts.add("bca");Iterator it=ts.iterator();while (it.hasNext()){System.out.println(it.next());}


3、实现Comparator方式排序

当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较性。

那么定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。

当两种排序都存在时,以比较器为主。

怎样定义一个比较器呢?

定义一个类,实现Comparator接口,覆盖compare方法。

例如:

import java.util.*;class Student implements Comparable //该接口强制让学生具备比较性。{private String name;private int age;Student(String name,int age){this.name=name;this.age=age;}//覆盖compareTo方法,按年龄排序public int compareTo(Object obj){if(!(obj instanceof Student))throw new RuntimeException("不是学生对象!");Student s=(Student)obj;//System.out.println(this.name+"...compareto..."+s.name);if(this.age>s.age)return 1;if(this.age==s.age){return this.name.compareTo(s.name);}return -1;}public String getName(){return name;}public int getAge(){return age;}}class TreeSetDemo2 {public static void main(String[] args) {                //TreeSet ts=new TreeSet();TreeSet ts=new TreeSet(new MyCompare());ts.add(new Student("lisi02",22));ts.add(new Student("lisi02",21));ts.add(new Student("lisi007",20));ts.add(new Student("lisi09",19));ts.add(new Student("lisi06",18));ts.add(new Student("lisi007",29));Iterator it=ts.iterator();while (it.hasNext()){Student stu=(Student)it.next();System.out.println(stu.getName()+"......"+stu.getAge());}}}//实现Comparator接口,覆盖compare方法。按姓名排序。class MyCompare implements Comparator{public int compare(Object o1,Object o2){Student s1=(Student)o1;Student s2=(Student)o2;//return s1.getName().compareTo(s2.getName());int num=s1.getName().compareTo(s2.getName());if (num==0){return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));}return num;}}



六、泛型

泛型:JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。

 

好处:

1,将运行时期出现的问题ClassCastException,转移到了编译时期。方便于程序员解决问题。让运行时期问题减少,安全。

2,避免了强制转换的麻烦。

 

泛型格式:通过<>来定义要操作的引用数据类型。

在使用java提供的对象时,什么时候写泛型呢?

  通常在集合框架中很常见,只要见到<>就要定义泛型。其实<>就是用来接收类型的。

当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可。

例如:

import java.util.*;class GenericDemo {public static void main(String[] args) {ArrayList<String> al=new ArrayList<String>(); //泛型al.add("abc01");al.add("abc0991");al.add("abc014");Iterator<String> it=al.iterator();while (it.hasNext()){String s=it.next();System.out.println(s+":"+s.length());}}}


1、泛型类

什么时候定义泛型类?

当类中要操作的引用数据类型不确定的时候。早期定义Object来完成扩展。现在定义泛型来完成扩展。

例如:

class Worker{}class Student{}//泛型前做法class Tool{private Object obj;public void setObject(Object obj){this.obj=obj;}public Object getObject(){return obj;}}//泛型类class Utils<QQ>{private QQ q;public void setObject(QQ q){this.q=q;}public QQ getObject(){return q;}}class GenericDemo3 {public static void main(String[] args) {Utils<Worker> u=new Utils<Worker>();u.setObject(new Worker());//Worker w=(Worker)u.getObject();Worker w=u.getObject(); //不用强转}}


2、泛型方法

泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

  为了让不同方法可以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。


3、静态方法泛型

特殊之处:

静态方法不可以访问类上定义的泛型。如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。


泛型定义在方法上,放在哪?

<>放在返回值类型前面,修饰符的后面。

例如:

class Demo<T>//泛型类{public void show(T t){System.out.println("show:"+t);}public <Q> void print(Q q)//泛型方法{System.out.println("print:"+q);}public static <W> void method(W w)//静态方法泛型{System.out.println("method:"+w);}}class GenericDemo4 {public static void main(String[] args) {Demo<String> d=new Demo<String>();d.show("haha");//d.show(4); //错误;泛型的类型已经固定。d.print(5);d.print("hehe");Demo.method("hahahaha"); //静态方法,类名调用}}


4、泛型接口

//泛型定义在接口上。interface Inter<T>{void show(T t);}/*//第一种方式:class InterImpl implements Inter<String>{public void show(String t){System.out.println("show:"+t);}}*///第二种方式:class InterImpl<T> implements Inter<T>{public void show(T t){System.out.println("show:"+t);}}class GenericDemo5 {public static void main(String[] args) {/*InterImpl i=new InterImpl();i.show("haha");*/InterImpl<Integer> i=new InterImpl<Integer>();i.show(4);}}



七、泛型限定

? 通配符。也可以理解为占位符。

泛型的限定:

? extends E:可以接收E类型或者E的子类型。上限。

? super E:可以接收E类型或者E的父类型。下限。

例如:


import java.util.*;class GenericDemo6 {public static void main(String[] args) {ArrayList<Person> al=new ArrayList<Person>();al.add(new Person("abc1"));al.add(new Person("abc2"));al.add(new Person("abc3"));ArrayList<Student> al1=new ArrayList<Student>();al1.add(new Student("abc--1"));al1.add(new Student("abc--2"));al1.add(new Student("abc--3"));printColl(al1); //ArrayList<Person> al=new ArrayList<Student>(); Error}public static void printColl(ArrayList<? extends Person> al) //泛型限定{Iterator<? extends Person> it=al.iterator();while (it.hasNext()){System.out.println(it.next().getName());}}}class Person{private String name;Person(String name){this.name=name;}public String getName(){return name;}}class Student extends Person{Student(String name){super(name);}}




------- android培训、java培训、期待与您交流! ----------


0 0
原创粉丝点击