黑马程序员——Java高新技术——集合

来源:互联网 发布:马踏棋盘贪心算法c 编辑:程序博客网 时间:2024/05/19 18:16


点击打开链点击打开链接 点击打开链接 android培训、<a">点击打开链接 点击打开链接 java培训、期待与您交流!">点击打开链接 点击打开链接

集合类

集合类是存储对象最常用的的一种方式

为什么出现集合类?

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

 

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

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

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

 

集合类的特点:

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

 

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

collection方法:

1.存储

 boolean  add(E e):参数类型是Object,以便于接受任意类型的对象。

 boolean  addAll(Collection c):添加容器里所有元素

2.删除

 void   clear():删除所有元素

 boolean  remove(Object o):移除单个元素

 boolean  removeAll(Collection c):移除集合中包含c集合中的所有元素

3.判断

 boolean  contains(Object o):集合是否存在某个对象

 boolean  containsAll(Collection c):集合是否包含c集合中的所有元素。

 boolean  isEmpty():是否包含元素

 boolean  equals(Object o):返回此Collection与指定对象是否相等。

4.获取

 int         hashCode():获取集合的哈希码值

 int         size():元素数,长度

 Iterator     iterator():返回此collection的元素上进行迭代的迭代器。集合取出元素的方法

 boolean     retainAll(Collection c):取交集。

 Objcet[]     toArray():返回包含所有元素的数组

 

例:

import java.util.*;class Test15 {public static void main(String[] args) {//创建一个ArrayList集合对象alArrayList al=new ArrayList();//添加元素al.add("java01");al.add("java02");al.add("java03");al.add("java04");//创建另一个arrayList集合对象a.        ArrayList a=new ArrayList();//添加元素a.add("java01");a.add("java02");a.add("java06");a.add("java07");sop("原"+al);al.addAll(a);   //把a集合中的元素都添加到al集合中去sop("添加a"+al);al.remove("java01");  //删除java01这个元素,al中有2个java01元素,运行结果发现,只删除了第一个。sop("删除java01"+al);al.removeAll(a);      //删除a集合中包含的所有元素,运行后会发现前面的java02也被删除了sop("删除a集合里包含的元素"+al);al.clear();           //清除集合中所有元素,此时集合为空sop("清除元素"+al);al.addAll(a);             //添加a中所有元素       sop(al.contains("java01")); //判断al集合是否包含java01这个元素sop(al.containsAll(a));     //判断al集合是否包含a集合中的所有元素sop(al.isEmpty());          //判断集合是否为空al.add("java04");sop(al.equals(a));              //判断两集合是否相等sop("size"+al.size());al.add("java03");sop("交集"+al.retainAll(a));    //取两集合的交集}public static void sop(Object obj){System.out.println(obj);}}

运行结果:


 

集合中存储的都是对象的引用。

 

Iterator接口:

方法: E        next():返回迭代器的下一个元素

       boololean  hasNext(): 如果仍有元素可以迭代,返回true

       void       remove():将对象引用从集合中删除

 

Collection:常见子接口

List特点:元素是有序的,元素可以重复,因为该集合体系有索引

Set特点:元素是无序的,元素不可以重复。

 

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

void      add(index,element)

boolean   addAll(index,Collection)

E    remove(index)

E   set(index,element)

E     get(index)

int    indexOf(object)

List   subList(int fromIndex,int toIndex)

ListIterator listIterator()

 

ListIterator:列表迭代器,List集合特有的迭代器

    在迭代时。不可以通过集合对象的方法操作集合中的元素,因为会发生concurrentModificationException异常。

   所以,在迭代时只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断、取出、删除的操作。

  如果想要其他的操作如添加、修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取。

 

ListIterator的操作方法:

void     add(E   e):将指定元素插入列表

void     remove():从列表中移除由nextprevious返回的最后一个元素

void     set(E  e):用指定元素替换由nextprevious返回的最后一个元素

boolean  hasNext():以正向遍历列表时,如果列表迭代器还有元素,则返回true

boolean  hasPrevious():如果逆向遍历列表,列表迭代器有多个元素,则返回true

E       next():返回列表中的下一个元素

E       previous():返回列表的前一个元素

int      nextIndex():返回对next的后续调用所返回元素的索引。

int      previousIndex():返回对previous的后续调用所返回元素的索引。

 

List三个子类的异同:

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

LinkList:底层的数据结构是链表结构,特点:增删速度快,但是查询稍慢。

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

Vector特点

Enumeration elements():枚举

 hasMoreElements()

 nextElements()

 

Linkedlist:特有方法

JDK1.5版本特性:删除、添加如果没有找到,则抛出异常。

 Void   addFirst(E  e):将元素添加到列表的开头

 Void   addLast(E  e):将元素添加到列表的结尾

E     getFirst():获取列表的第一个元素

E     getLast():获取列表的最后一个元素

E     removeFirst():移除并返回此列表的第一个元素

E     removeLast():  移除并返回此列表的最后一个元素

E     poll()::移除并获取此列表第一个元素。

E     peek():获取但并不移除此列表的头

JDK 1.6版本新特性

E    pollFirst():获取并移除此列表第一个元素,如果集合没有,则返回null.

E    pollLast():获取并移除此列表第一个元素,如果集合没有,则返回null.

Boolean offerFirst(E   e):在此列表的开头插入指定元素

Boolean offerLast(E    e):在此列表的结尾插入指定元素

peekFirst():获取但不移除此列表的第一个元素,如果此列表为空,则返回null

peekLast():获取但不移除此列表的最后个元素,如果此列表为空,则返回null

 

/*请模仿堆栈:先进后出和队列:先进先出的模式为LinkedList存取数据  */import java.util.*;class Test16   //堆栈练习题{public static void main(String[] args) {DuiZhan d=new DuiZhan();d.myAdd("java01");        d.myAdd("java02");        d.myAdd("java03");        d.myAdd("java04");while(!d.isNull()){           sop(d.myGet());}}public static void sop(Object obj){System.out.println(obj);}}//队列:先进先出,用addLast每次都把数据往结尾处存,用removeFirst从前头取,//取一个删除一个,这样就能保证元素先进先出,还能用isEmpty判断一下元素是否取完。class Duilie{private LinkedList link;Duilie(){link=new LinkedList();}//存入数据的方法public void myAdd(Object obj){link.addLast(obj);}//取出数据的方法    public Object myGet(){return link.removeFirst();}//判断数据是否取完的方法public boolean isNull(){return link.isEmpty();}}//堆栈:先进后出,用addLast把数据每次都往结尾处存,用removeLast从最后头取,//这样先取出的就是后存进去的数据。class DuiZhan{private LinkedList link;DuiZhan(){link=new LinkedList();}public void myAdd(Object obj){link.addLast(obj);}    public Object myGet(){return link.removeLast();}public boolean isNull(){return link.isEmpty();}}
<pre class="java" name="code">//做一个去除ArrayList里面重复元素的函数import java.util.*;class Test17 {public static void main(String[] args) {ArrayList al=new ArrayList();al.add("java01");        al.add("java02");        al.add("java03");        al.add("java01");System.out.println(myRemove(al));}      //去除ArrayList重复元素的函数myRemove,传入一个ArrayList集合,返回一个ArrayList集合。public static ArrayList myRemove(ArrayList al){//建立一个新的ArrayList集合ArrayList newal=new ArrayList();Iterator it=al.iterator();//遍历传入al集合的所有元素for(Object obj;it.hasNext();){obj=it.next();//判断如果新集合里面没有包含旧集合里面的元素,才把元素存入新集合if(!newal.contains(obj))  //利用contains()判断newal.add(obj);}return newal;}}

 

对与以上例子,如果ArrayList里面存储的不是字符串,而是自定义Person类,这时判断两个Person对象是否一样,比较的是地址值,如果我们需要将两个名字、年龄一样的Person对象看做同一个Person,我们就需要复写equals方法,示例如下:

import java.util.*;class Test18 //ArrayList练习2{public static void main(String[] args) {ArrayList al=new ArrayList();al.add(new Person("张三",12));al.add(new Person("李四",15));al.add(new Person("王五",17));al.add(new Person("张三",12));        //调用去重函数al=QC(al);            //利用迭代器将去除重复元素以后的集合元素打印出来Iterator it =al.iterator();for(Person p;it.hasNext();){p=(Person)it.next();System.out.println(p.getName()+"....."+p.getAge());}}//这是一个去除ArrayList里面重复元素的函数public static ArrayList QC(ArrayList al){ArrayList newal=new ArrayList();Iterator it=al.iterator();for(Object obj;it.hasNext();){obj=it.next();if(!newal.contains(obj))newal.add(obj);}return newal;}}//建立person类class Person{private String name;private int age;//一初始化就有姓名和年龄Person(String name,int age){this.name=name;this.age=age;}//复写了equals方法public boolean equals(Object obj){if(!(obj instanceof Person))return false;Person p=(Person)obj;//当姓名和年龄都一样就返回true,否则返回falsereturn  name.equals(p.name) && age==p.age;}    public String getName(){return name;}public int getAge(){return age;}}

 

注意:

l 在迭代时循环中next调用一次,hasNext就要判断一次。

l List集合判断元素是否相同,调用的是equals

 

Set是无序的(存入和取出的顺序不一定一致),元素不可以一致

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

常见子类:HashSet:底层数据结构是哈希表,线程是非同步的

          TreeSet:可以对Set集合中的元素进行排序。底层数据结构:二叉树。保证元素唯一性的依据:compareTo方法return 0

 

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

是通过元素的两个方法HashCodeequals来完成

如果元素的HashCode值相同,才会判断equals是否为true

如果元素的HashCode值不同,不会调用equals

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

 

排序时,当主体条件相同,一定要判断次要条件。

 

TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现comparable接口,覆盖compareTo方法。这种方式也称为元素的自然排序或者叫默认排序。

 

TreeSet排序的第二种排序方式:当元素自身不具备比较性或者具备的比较性不是需要的,这时就需要让集合自身具备比较性。在集合初始化时就有了比较方式。定义比较器,将比较器最为参数传递给TreeSet集合的构造函数。

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

比较器:定义一个类,实现Comparator接口,覆盖compare覆盖。

import java.util.*;class Test19 {public static void main(String[] args) {TreeSet ts=new TreeSet(new myComparator());ts.add("lisi01");ts.add("aisi00001");ts.add("cisi01");ts.add("misi01");Iterator it=ts.iterator();for(Object obj;it.hasNext();){System.out.println(it.next());}}}//自定义的比较器,①继承Comparator接口class myComparator implements Comparator{//②复写里面的compare方法public int compare(Object o1,Object o2){//这个类是用来比较字符串长短的,所以先要判断传入参数是否为字符串if(!(o1 instanceof String)|| !(o2 instanceof String))throw new RuntimeException();//进行强制转换String s1=(String)o1;String s2=(String)o2;// 当两字符串长度一样时,比较字母自然顺序if(s1.length()==s2.length())return s1.compareTo(s2);//否则比较两字符串的长度return new Integer(s1.length()).compareTo(new Integer(s2.length()));}}

 

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

好处:1.将运行期间出现问题转移到编译时期,方便程序员解决问题。

      2.避免了强制转换麻烦。

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

例:ArrayList<String>  al=new ArrayList<String>;

 

什么时候使用?

通常在集合框架中很常见,只要见到<>就要定义泛型。

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

 

泛型类

什么时候定义泛型类?

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

class Demo<T>

{

Public void show<T t>

{

}

}

 

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

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

Public <Q> void print(Q q)

{}

特殊之处:静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以定义在方法上。

 

泛型定义在接口上

import java.util.*;class Test20   //泛型定义在接口上的两种方法 {public static void main(String[] args) {InterImpl i=new InterImpl();i.show("hello java!");InterImple<Integer> in=new InterImple<Integer>();in.show(2);}}interface Inter<T>{void show(T t);}class InterImpl implements Inter<String>  //第一种,子类时确定好类型{public void show(String str){System.out.println(str);}}class  InterImple<T> implements Inter<T>  //第二种 子类时不确定类型,调用再确认{public void show(T t){System.out.println(t);}}

 

泛型的高级应用

泛型限定:如ArrayList<? Extends Person>  ?是不明确类型,是一个占位符,也可以叫通配符

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

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

 

Map集合

特点:该集合存储键值对,一对一对往里存,而且要保证键的唯一性。

 

重要方法:

1.增加

  V   put(K key,V  value):如果出现添加相同的键,那么添加的值会覆盖原有的键对应值,并返回原有键对应的值。如果没有相同的键,返回null.

  void  putAll(Map<? extends K,? extends V>  m):

2.删除

  void  clear():移除所有映射关系

  V    remove(Object  key):移除会返回键对应的值。没有回返回null

3.判断

 boolean  containsKey(Object K):是否包含某个键

 boolean  containsValue(Object v):是否包含某个值

 boolean  isEmpty():是否包含键值对

4.获取

  V   get(object key):没有回返回null。可以通过get方法的返回值来判断一个键是否存在

  int   size():返回键值映射关系数

  Collection<V>   values():获取map集合中所有的值.

  Set<Map.Entry<K,V>>   entrySet():返回映射关系的Set视图

  Set<k>   KeySet():返回此映射中的包含的所有键存入到set集合,因为set具备迭代器。所以可以根据跌倒取出所有的键,再根据get方法,获取每一个键对应的值。

 

Map的子类

  --HashTable:底层是哈希表数据结构,不可以存入nullnull值,该集合是线程同步的。

  --HashMap:底层是哈希表数据结构,允许使用nullnull值,该集合是不同步的。

  --TreeMap:底层是二叉树数据结构的,线程不同步,可以用于给map集合中的键进行排序。

 

Map的两种取出方式

1.KeySet

  Set<String>  keySet=map.keySet();

  Iterator<String> it=keySet.iterator();

while(it.hasNext())

{

  String key=it.next();

  String name=map.get(key);

}

Map的取出原理:将Map集合转成Set集合,再通过迭代器取出

 

2.entrySet():将map集合的映射关系存入到set集合中,而这个关系的数据类型是Map.Entry

 Set<Map.Entry<String,String>>  entrySet=map.entrySet();

 Iterator<map.Entry<String,String>> it=entrySet.iterator();

While(it.hasNext())

{

Map.Entry<String,String> me=it.next();

String key=me.getKey();

String value=me.getvalue();

  map.Entry 其实Entry也是一个接口,他是Map接口中的一个内部接口。

Map拓展练习

 

import java.util.*;class Test24  //map扩展练习 {public static void main(String[] args) {HashMap<String,List<Student>> yz=new HashMap<String,List<Student>>();List<Student>  ptb=new ArrayList<Student>();List<Student>  jyb=new ArrayList<Student>();yz.put("普通班",ptb);yz.put("精英班",jyb);ptb.add(new Student("zhangsan",15));        ptb.add(new Student("lisi",17));        jyb.add(new Student("wangwu",16));        jyb.add(new Student("zhaoliu",14));Iterator<String> it=yz.keySet().iterator();for(String str;it.hasNext();){str=it.next();System.out.println(str);getInfo(yz.get(str));}}public static void getInfo(List<Student> b){Iterator<Student> it=b.iterator();for(Student stu;it.hasNext();){stu=it.next();System.out.println(stu);}}}

 

集合工具类:Collections与Arrays

Collections:对集合进行操作的工具类

 

重要方法:

①排序

static <T extends Comparable<? Super T>> void  /   sort(List<T> list):根据元素的自然顺序升序排列

Static <T> void /  sort(List<T> list,Comparator<? super T> c):根据比较器产生的顺序对指定列表进行排列

②返回最值

static <T extends Object & Comaparable<? super T> >  T /max(Collection<? Extends T> coll):根据元素的自然顺序返回给定collection的最大值

static <T> T   / max(Collection<? extends T> coll,Comparator<? super T> comp):根据指定比较器产生的顺序,返回给定collection的最大元素。

static <T extends Object & Comaparable<? super T> >  T /min(Collection<? Extends T> coll):根据元素的自然顺序返回给定collection的最小值

static <T> T   / min(Collection<? extends T> coll,Comparator<? super T> comp):根据指定比较器产生的顺序,返回给定collection的最小值。

③根据二分法查找:

static <T> int /binarySearch(List<? extends Comparable<? super T>> list,T key):根据二分法查找元素,如果搜索键包含在指定列表中,则返回搜索键的索引,否则返回(-插入点-1

Static <T> int / binarySearch(List<? extends T>list,T key,Comparator<? super T> c):根据二分法查找元素

④替换

static <T> void /fill(List<? super T> list,T obj):将集合中所有元素替换成指定元素

Static <T> boolean / replaceAll(List<T> list,T oldVal ,T newVal):使用另一个值替换列表中所有指定值。

⑤反转

static void /  reverse(List<?> list):反转指定列表中所有元素的顺序。

static <T> Comparator<T>  / reverseOrder():返回一个比较器,它强行逆转实现了Comparable接口的对象collection的自然顺序

static <T> Comparator<T>  / reverseOrder(comparator<T> cmp):返回一个比较器,它强行逆转了指定比较器的顺序。

⑥得到同步的列表或映射

Static <T> List<T> /synchronizedList(List<T> list):返回列表支持的同步列表

Static <T> Set<T> /synchronizedSet(Set<T> s):返回指定Set支持的同步Set

Static <K,V> Map<K,V> /synchronizedMap<Map<K,V> m>:返回指定映射支持的同步映射

⑦其余方法

Static void / swap(List<?> list,int i,int j):在指定列表的指定位置处交换元素

Static void / shuffle(List<?> list):使用默认随机源对指定列表进行置换

 

练习:将List集合中的部分元素替换成指定元素。CollectionsDemo

import static java.util.Collections.*; //静态导入import java.util.*;class CollectionsDemo {public static void main(String[] args) {List<String> list=new ArrayList<String>();list.add("java01");list.add("java02");list.add("java03");list.add("java04");System.out.println(list);myFill(list,"java",1,3);System.out.println(list);}//将集合中的指定部分(包含头不包含尾)元素替换成指定元素public static <T> List<T> myFill(List<T> list,T t,int start,int end){for(int i=start;i<end;i++)        {list.set(i,t);}return list;}}


 

Arrays:用于操作数组的工具类,大部分方法已经在学习数组的时候介绍过。

static boolean  / deepEquals(Object[]  a1,Object[]  a2):如果两个指定数组是彼此深层相等的,则返回true

Static <T> List <T>  /asList(T...a):将数组变成List集合。

1.数组变成集合的好处:可以使用集合的思想和方法来操作数组中的元素

2.注意:将数组转成集合,不可以使用集合的增删方法,如果使用增删方法,会发生UnsupportedOperationException.

    如果数组中的元素都是对象,那么变成集合时,数组中的元素就会转成集合中的元素。

如果数组中的元素都是基本类型,那么将数组作为集合中的元素存在。

 

集合变数组:<T> T[]  /  toArray(T[] a):

1.指定类型数组到底要定义多长?

 当指定类型数组长度小于集合的size,那么该方法内部会创建一个新的数组,长度为集合的size。

  当指定类型数组长度大于集合的size,那么该方法内部不会创建新数组,而是使用传递进来的数组,所有创建一个刚好等于集合size的数组最优。

2.为什么要将集合变数组?

  为了限定对元素的操作。

 

高级for循环:

格式:  for(数据类型 变量名:被遍历的集合或者数组)

        {}

 

高级for循环和迭代器的区别?

高级for循环只能获取集合元素,但是不能对集合进行操作。

迭代器除了遍历外,还可以进行remove集合中元素的动作,如果使用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。

 

传统for循环和高级for循环的区别?

高级for循环有一个局限性,必须要被遍历的目标,建议在遍历数组时,使用传统for。

 

JDK1.5版本出现的新特性

Public static void show(int...arr)

{

}

可变参数列表:其实就是数组参数的简写形式,不用每一次都手动建立数组对象,只有将要操作的元素作为参数传递即可,隐式将这些参数封装成了数组。

方法的可变参数使用时注意:可变参数一定要定义在参数列表的最后面。

 

静态导入:

例:import static java.util.Arrays.*;  //导入的是Arrays这个类中的所有静态成员。

当类名重名时,需要指定具体的包名

当方法重名时,指定具备所属的对象或者类

例:import static java.lang.System.*;导入System类中所有的静态成员。

那么我们用输出语句时可以直接用:out.println();

0 0