黑马程序员——第五章 JavaAPI之集合框架

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


对象数组

  数组中存储的是引用类型,弊端是长度固定。

例:Student[]stu = {new Student("a",90),new Student("b",88),new Student("c",10)};

              //遍历对象数组

              for(int i = 0; i < stu.length ; i++){

                     System.out.println(stu[i]);

}

 

  为了解决对象数组长度固定的问题,JavaJDK1.2版本开始,开发出来集合框架,处理掉对象数组的问题。集合长度是可变的。

   

数组和集合的区别

  数组:长度固定,存储基本数据类型或对象,存储同一类型元素。

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

数组和集合都是容器,基本数据多就存数组,对象多就存集合。

 

学习集合框架

  学习的集合中每一个容器的特点,怎么存储对象,怎么取出来

 

顶层接口Collection

 java.util.Collection,集合中的顶层接口,下面的子类或者子接口都具备它所有的抽象方法。

找实现类ArrayList,是接口指向实现类,运行的方法都是实现类重写后的方法。

 

Coollection方法

1add(Objecto)将元素存储到集合中。

   例:Collection con = new ArrayList();

               con.add("abc");

               con.add(123);

               con.add(true);//con=[abc,123,true]

 

2Iteratoriterator()获取迭代器对象。

 

3intsize()返回集合中存储元素的个数。

   例:Collection con = new ArrayList();

              con.add(123);

              con.add("abc");

              int size = con.size();//size=2

 

4booleancontains(Object o)判断集合中是不是包含这个对象,如果包含返回true

   例:Collection con = new ArrayList();

              con.add(123);

              con.add(456);

              con.add("abc");

              boolean b = con.contains(456);//b=true

 

5,void clear()清除集合中的所有对象,但是集合容器还在。

   例:Collection con = new ArrayList();

              con.add(123);

              con.add("abc");//con=[123,abc]

              con.clear();//con=[]

 

6,addAll(Collection c)把一个集合存储到另一个集合。

       例:Collection co1 = new ArrayList();

              Collection co2 = new ArrayList();

              co1.add(123);

              co1.add(456);

              co2.add("abc");

              co2.add(123);     

              co1.addAll(co2);//co1=[123,456,abc,123]

 

7,boolean containsAll(Collection c)一个集合是否完全包含另一个集合中存储的对象,如果完全包含,返回true。

   例:Collection co1 = new ArrayList();

              Collection co2 = new ArrayList();

              co1.add(123);

              co1.add(789);

              co2.add(123);

              co2.add(123);

              boolean b = co1.containsAll(co2);//b=true

 

8,boolean isEmpty()如果集合中元素个数是0,返回true。等价于判断size()==0。

9,toArray()集合转成数组。

10,boolean remove(Object o)移除集合中的元素,移除成功返回true,相同元素只移除第一个。

   例:Collection con = new ArrayList();

              con.add("abc1");

              con.add("abc2");

              con.add("abc3");

              boolean b = con.remove("abc2");//b=true

 

11,boolean removeAll(Collection c)移除两个集合中相同的元素。

       例:Collection co1 = new ArrayList();

              Collection co2 = new ArrayList();

              co1.add(123);

              co1.add(456);

              co1.add(789);

              co2.add(123);

              co2.add(789);

              boolean b = co1.removeAll(co2);//b=true,co1=[789],co2=[123,789]

 

12,boolean retainAll(Collection c)获取两个集合的交集。

   例:Collection co1 = new ArrayList();

              Collection co2 = new ArrayList();

              co1.add(123);

              co1.add(456);

              co1.add(789);            

              co2.add(123);

              co2.add(789);

              boolean b = co1.retainAll(co2);//b=true,co1=[123,789],co2=[123,789]

//若co1变了则为true,不变则为false

 

迭代器

 java.util,迭代器就是从集合中取出元素的方式,理解为遍历数组。

  但是每种集合子类存储对象的方式不同,造成获取对象的方式也不同,因此规定了一个接口(Iterator),所有子类的迭代器必须满足接口的规则。

 Iterator iterator() 方法是获取迭代器对象的方法,返回值是一个接口,返回的是这个接口的实现类的对象,这个实现类是被私有修饰的内部类。

 

Iterator接口中的方法

1,boolean hasNext(),判断集合中有没有下一个被取出的元素,有返回true。

2,Object next(),获取集合中的下一个元素。

3,void remove(),移除元素,是迭代过程中移除。

  Iterator it = ArrayList对象.iterator();

 

使用迭代器取出集合中存储元素的三个步骤:

1,调用集合方法iterator()获取迭代器接口的实现类对象。

2,调用接口Iterator方法hasNext()判断集合中有没有下一个元素。

3,调用接口Iterator方法next()获取集合中的元素。

   例:Collection con = newArrayList();

              con.add("abc3");

              con.add("abc1");

              con.add("abc2");

              Iterator it = con.iterator();

              while(it.hasNext()){

              System.out.println(it.next());

}

 

for循环完成集合遍历

     for(Iterator it2 = con.iterator(); it2.hasNext();){

                 System.out.println(it2.next());

           }

 

迭代器获取集合元素的注意事项

1,如果hasNext()判断为false,还用next()获取,出现没有元素被取出异常NoSuchElementException。

2,在迭代过程中,不允许使用集合的方法改变集合长度,出现并发修改异常。

3,迭代器创建好以后,只能迭代一次。

4,一次迭代中,不允许出现多次next方法。

 

迭代器方法remove

  迭代过程中,删除元素方法是迭代器方法,不是集合方法,因此不会出现并发修改异常。

 next()方法获取到的是谁,voidremove()删除的就是谁。

   例:Collection con = new ArrayList();

              con.add("abc1");

              con.add("abc2");

              con.add("abc3");

              Iterator it = con.iterator();

              while(it.hasNext()){

                     Objecto = it.next();

                     if("abc2".equals(o))

                            it.remove();//删除abc2

                     System.out.println(o);//abc1,abc2,abc3

              }

              System.out.println(con);//[abc1,abc3]

 

List接口派系

 List接口继承Collection接口,自己成立一个派系。

  List可存放重复元素,元素的存取是有序的,元素有下标。

List接口特有方法

1,void add(int index,Object o)在列表的指定位置上插入元素。

   例:List list = new ArrayList();

              list.add("abc1");

              list.add("abc2");

              list.add("abc3");

              list.add(2,"www");//list=[abc1,abc2,abc3,]

 

2,boolean addAll(int index,Collection c)在列表的指定位置上插入另一个集合。

   例:List list = new ArrayList();

              List list2 = new ArrayList();   

              list.add("abc1");

              list.add("abc2");

              list2.add(1231);

              boolean b = list.addAll(1,list2);//b=true,两个有一个为null,b=false

//list=[abc1,1231,abc2],list2=[1231]

 

3,Object get(int index)返回指定索引上的元素。

   例:List list = new ArrayList();

              list.add("abc1");

              list.add("abc2");

              list.add("abc3");

              Object o = list.get(2);//o=abc3

4,Object remove(int index)移除指定下标上的元素,返回移除前的对象。

       例:List list = new ArrayList();

              list.add("abc1");

              list.add("abc2");

              list.add("abc3");

              Object o = list.remove(1);//o=abc2,list=[abc1,abc3]

 

5,Object set(int index,Object o)修改指定下标上的元素,返回修改前的元素。

   例:List list = new ArrayList();

              list.add("abc1");

              list.add("abc2");

              list.add("abc3");

              Object o = list.set(2,"QQ");//;o=abc3,list=[abc1,abc2,QQ]

 

6,List subList(int start,int end)获取集合中的一部分,包含头,不包含尾,返回新集合。

       例:List list = new ArrayList();

              list.add("abc1");

              list.add("abc2");

              list.add("abc3"); 

              list = list.subList(1,2);//list=[abc2,abc3]

 

List派系特有迭代器

 List特有迭代器接口ListIterator,这个接口是Iterator的子接口,只能应用于List集合。

 List的派系的每一个子类,都有一个方法listIterator,返回ListIterator接口的实现类对象,这个实现类,就是集合的内部类。

  特点:迭代中,可以使用迭代器方法,进行添加,修改,删除集合中的元素,正向、逆向遍历。

ListIterator接口方法

1,add(Object)添加,迭代到哪个对象,添加到这个对象的后面

2,set(Object)修改,迭代到哪个对象,修改的就是哪个对象

       例:List list = new ArrayList();

              list.add("abc1");

              list.add("abc2");

              ListIterator lit = list.listIterator();

              while(lit.hasNext()){

                     Objecto = lit.next();

                     if("abc2".equals(o))

                            lit.set("abc22");

              }

              System.out.println(list);//list=[abc1,abc22]

3,remove()删除。

4,逆向遍历,用法:hasPrevious() 类似 hasNext(), previous() 类似 next() 。逆向前要先正向遍历一次。推荐使用for循环逆向遍历。

   例:List list = new ArrayList();

              list.add("abc1");

              list.add("abc2");

              list.add("abc3");

              for(int i = list.size()-1 ; i >= 0;i--){

                     System.out.println(list.get(i));

              }

 

ArrayList类

  容器的底层实现方式,可变长度数组(扩容,自动复制数组),数组默认大小10个长度,每次增长50%,查询速度快,增删慢,线程不安全,运行速度快。

 

练习:去掉ArrayList中的重复对象

例:import java.util.ArrayList;

import java.util.Iterator;

public class ArrayListDemo {

       public static voidmain(String[] args) {

              ArrayList Array = new ArrayList();

              Array.add("abc");

              Array.add(123);

              Array.add(123);

              Array.add("abc");

              Array.add("双11");

              Array = method(Array);

              System.out.println(Array);//[abc,123,双11]

       }

       //定义一个方法去掉Array里面的重复对象

       public static ArrayListmethod(ArrayList Array){

              ArrayList temp = new ArrayList();

              //迭代array集合

              Iterator lit = Array.iterator();

              while (lit.hasNext()) {

                     Object o =lit.next();

                     //判断是否有重复对象,没有则加入temp

                     if(!temp.contains(o))

                            temp.add(o);

              }

              return temp;

       }

}

 

Vector类

  开始版本JDK1.0 , 升级到JDK1.2的时候,才出现了集合框架的概念。类Vector在JDK1.2版本后,改为实现List接口。 类名不该呢 VectorList,版本的兼容性。

 Vector类底层实现,也是可变数组,数组默认大小10个长度,增长率100%,线程安全,运行速度慢。

  从JDK1.2版本开始,Vector被ArrayList取代。

 

LinkedList类

  特点和List接口,一致,重复,有序,下标

 LinkedList底层实现原理:链表结构,查询慢,增删快,线程不安全,运行速度快

  存储和取出,实现代码,和ArrayList完全一致

 

LinkedList特有方法

在列表的开头或者结尾添加元素addFirst(Object o )  addLast(Object o)

获取列表的开头或者结尾Object getFirst()  Object getLast()

移除列表的开头或者结尾Object removeFirst()  Object removeLast()

以上的获取和移除,若列表中是空的,会出现没有元素被取出异常。

 

    在LinkedList中,1.6版本开始,添加了几个新的方法,来操作集合

offerFirst()  offerLast() 替换的了addFirst() addLast()

Object peekFirst()  Object peekLast() 替换了 getFirst() getLast().如果集合中是空的,获取后返回null不会出现异常。

Object pollFirst()  Object pollLast() 替换了 removeFirst() removeLast().如果集是空的返回null,不会出现异常。

 

数据的存储结构队列和堆栈

   堆栈:内存中的数据,先进去的,后出来。

   队列:内存中的数据,先进去的,先出来。

   特点:符合LinkedList类的特点,存储对象的时候,开头结尾,获取对象的时候,可以在开头和结尾获取。

   使用LinkedListd的方法removeFirst( )和removeFirst( ),模拟数据的先进后出,先进先出。

 

泛型

泛型是JDK1.5出现的安全机制。泛型的出现,强制集合存储指定的数据类型,如果数据类型不符号要求,编译失败。

JDK1.7新特性,泛型前后自动匹配,后面的可以不写,空菱形语法。

写泛型的时候,前后的类型一致。存储基本数据类型时,泛型写包装类。

 

格式:集合类<数据类型>  变量 = new 集合类<数据类型>( );

 

泛型的好处

  1,保证安全:将问题,由运行时期,提前到了编译时期。

2,使用泛型,避免了类型的强制转换。

  3,简化书写,代码量减少。

 

自定义泛型

  可以保证程序的安全性 <>自定义泛型

定义泛型类,泛型方法,泛型接口

  泛型类:将泛型,定义在类上,如果类中的任何位置出现了个泛型,和类上的泛型是相同的。

  泛型方法:跟随类的泛型走的。定义泛型不跟着类的走的.在方法的声明上,在返回值类型之前,定义泛型,这个泛型属于方法自己,不属于类上的泛型。

  静态泛型方法:不可以和类上的泛型相同,如果相同,出现静态不能访问非静态,自定义一个泛型,这个泛型只属于这个静态方法。静态方法的泛型,写在返回值类型前

 泛型接口:接口上定义泛型,实现类实现接口不指定泛型,实现类实现接口的同时,就实现了泛型。

 

Java泛型是假泛型

编写程序时明确了泛型,编译后生成.class字节码文件无泛型。

理解为:编译时有泛型,运行时无泛型。

 

泛型的通配符

文件系统中,通配符 * 匹配任意的文件名,或者是后缀名。例: del*.* 

泛型中,有一个通配符号?,匹配所有的泛型类型,好处是方便遍历集合,弊端在于不能进行强转。

 

泛型的限定

  泛型上限限定 ? extends E  传递E类型 和E的子类

  泛型下限限定 ? super E    传递E类型 和E的父类

 

Set接口派系

  Set不能存放重复元素,元素的存取是无序的,元素无下标。

  Set接口方法,和父接口Collection的方法,完全一致。

 

HashSet类

HashSet哈希表,允许存null,线程不安全,查询速度快。

HashSet底层实现原理,哈希表,存储的是对象的哈希值,成为哈希表,是一个巨大的容器,会为每一个哈希值开辟独立存储空间。

HashSet集合add( )方法存储对象过程:存储对象的时候,调用该对象的hashCode方法,取得哈希值,查看自己的容器中是否有了这个哈希值。没有就直接存入集合;有就和就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存。

   结论:HashSet集合保证对象的唯一性,依据对象的hashCode和equals方法,要求存储到哈希表中的对象,必须重写hashCode( )equals( )方法。

 

对象的哈希值

  对象的哈希值,输出语句中,直接打印对象,看到的是XXX@34Ed2,十六进制数叫做哈希值。

  1,对象内存中确实有个真实地址值,我们看不到。

  2,我们看到十六进制数,其实是个十进制数,是JVM通过hashCode( )方法计算出来的虚拟地址。

 

注意:

  两个对象,如果对象的哈希值相同,equals方法不一定返回真。

  两个对象,如果equals方法返回真,一定具有相同的哈希值。

 

LinkedHashSet类

 HashSet的子类,具有迭代顺序的Set集合,是基于链表的哈希表,开始版本是JDK1.4,线程不安全,效率快。

 

TreeSet类

TreeSet(二叉树)用来排序, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列。

  存储对象到TreeSet集合中,出现了类型转换异常,不能被转成java.lang.Comparable类型,Comparable是一个接口,如果类实现了此接口,定义的类具有了自然顺序。TreeSet排序必须按照对象的自然顺序。

 

Person类存储到TreeSet集合中,需要Person具备自然顺序,实现Comparable接口,重写compareTo方法。

 

使用方式

1,自然顺序(Comparable)排序

存储对象到TreeSet集合中,需要对象具备自然顺序,实现Comparable接口,重写compareTo方法。

2,比较器顺序(Comparator)排序

创建TreeSet的时候可以制定 一个Comparator

如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序

add()方法内部会自动调用Comparator接口中compare()方法排序

注意:

TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序排序(没有就报错ClassCastException)。

TreeSet如果传入Comparator, 就优先按照Comparator排序。

 

Map接口

  Map集合存储映射键值对,存储两个对象,一个作为键,一个作为值。

  Map集合不能存储重复键,每一个键最多只能映射一个值。

 

Map接口中的方法

put(键对象,值对象), 将键值对存储到集合,存储重复键时,覆盖原值,并返回覆盖之前的值。

V get(Key) 通过键获取值,若集合中没有这个键,返回null。

booleancontainsKey(Key)判断集合中有没有这键,有返回真,没有返回假。

booleancontainsValue(Value)判断集合中有无这个值,有返回真,没有返回假。

booleanisEmpty()如果集合中,没有键值对返回真,否则返回假。

V remove(Key)根据键移除这个键值对,返回移除之前的值,没有移除成功返回null。

Collection<V>values()将Map中的所有值,存储到Collection集合

 

迭代Map集合

1,keySet()方法——代码少,简单易懂。

先调用keySet()方法从Map集合中获取所有Key组成的一个Set集合

迭代Set集合可以得到每一个Key

然后再调用get()方法通过Key获取每一个Value

 

2,entrySet()方法——代码多,不好理解,开发不常用,面试常用。

先调用entrySet()方法从Map集合中获取所有Entry(键值对)组成的一个Set集合

迭代Set集合可以得到每一个Entry

然后再调用getKey()和getValue()方法得到每一个Key和每一个Value

 

增强for循环不能直接遍历Map集合,但是可以通过遍历Set集合间接遍历Map集合。

 

HashMap类

  映射哈希表,无序集合,可以存储null值、null键,线程不同步、不安全,效率高。

  为保证唯一性,对象必须重写hashCode( )和equals( )方法。

 

LinkedHashMap类

  是HashMap的子类,基于链表的映射哈希表,有序的Map集合,线程不安全,开始于版本JDK1.4

 

Hashtable类

  映射哈希表,不能存储null值、null键,线程同步、安全,效率低。开始版本JDK1.0,现被HashMap取代。

 

Properties类

  是Hashtable的子类,不能存储null,也是一个线程安全的键值对的集合,可以和IO流结合使用,实现数据的永久性存储,键值对的数据类型都是字符串。

特有方法

setProperty(Stringkey,String value)等同于就是Map中的put

getProperty(Stringvalue)传递键,返回对应的值,等同于Map中的get方法

结合IO可以用于配置文件。

 

TreeMap类

 TreeMap(红黑树)对存储的键进行排序,底层是二叉树,线程不同步、不安全,效率高,需要对象的自然顺序或者比较器,用法和实现代码,直接参考TreeSet集合。

 

集合的嵌套演示

 

集合工具类Collections

  专门操作集合的工具类,方法全部静态。

Collections类中的方法

1staticvoid sort(List list)根据存储在集合的对象的自然顺序,对List集合排序。

2staticvoid sort(List list,Comparator com)根据比较器对List集合排序。

3staticComparator reverseOrder()返回比较器,逆转对象的自然顺序。

4staticComparator reverseOrder(Comparator c)传递比较器,返回比较器,返回的比较器逆转了传递的比较器。

5staticint binarySearch(List list, Object key)集合的折半查找,传递List集合必须有序,找到返回下标,找不到返回-插入点-1

6,static void fill(List list,Object obj)填充集合。

7,static void swap(List list ,int x,int y)指定下标,对List集合中的对象换位置。

8,static void shuffle(List list)对List集合中的对象,随机换位置。

将线程不安全集合变成线程安全集合 synchronized开头的方法

 

集合和数组的互转

数组转成集合:Arrays类方法isList , 传递数组,返回集合。

数组转成集合后,不能改变集合长度。

例:String[] str = {"abc","bbc","ddc"};

              List <String>list = Arrays.asList(str);//str数组转成List集合

集合转数组:Collection方法 toArray() 将集合转成数组,传递数组,返回数组。

例:List<String> list = new ArrayList<String>();

              String[] str = list.toArray(newString[list.size()]);//list集合转成数组

 

静态导入

 JDK1.5的新特性,简化书写。

 import static ...静态成员或者是静态方法。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值