9.集合List

 

一.集合

a)        集合是一种长度可变的容器,可以存储任意类型的对象

b)       为什么出现集合?

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

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

数组容器长度固定,一个数组存储一种数据类型;

集合长度是可变的,能存储不同类型的对象;

c)        集合的分类:

i.         Collection接口下常用类型分为两种:List,Set

List: 有存储顺序的,可以存储重复的对象;

Set:  没有存储顺序的,不可重复的

3. List集合   

i.         ArrayList:数组结构,查找快,增删慢;

查找的时候直接获取数组中的元素,直接操作内存地址,速度较快

增删的时候,由于创建数组或者拷贝数组,所以速度较慢

ii.  LinkedList: 链表结构,增删快,查找慢

LinkedList:特有方法:                                     jdk1.6出现的替代方法:

添加到集合的首位置:addFirst();    ----->       offerFirst();

添加到集合的首位置:addLast();    ----->    offerLast();

获取集合中0号索引的对象:getFirst();----->  peekFirst();

获取集合中最后一个对象:getLast();   ----->  peekLast();

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

removeFirst();  ----->   pollFirst();

removeLast();

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

 

JDK1.6出现了替代方法。

offerFirst();

offerLast();

peekFirst();

peekLast();

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

pollFirst();

pollLast();

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

 

***4.List类常用方法: (,, ,)

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

boolean add(Objectobj)-----

向集合中添加一个对象,如果改变了集合的结构,返回true,集合可以添加任意类型的对象

Object remove(intindex)----

删除指定索引上的元素,并且返回这个元素

Object set(intindex,Object object)---

将集合中指定位置的元素替换为指定对象;

Object get(int index)----

从集合中获取指定索引上的对象;

练习:

package cn.itcast;

 

import java.util.LinkedList;

 

 

publicclass ListMethodDemo {

   publicstaticvoid main(String[] args) {

      // TODO Auto-generated method stub

      //add();

      //addAll();

      //clear();

      //contains();

      //containsAll();

      //equals();

      //indexOf();

      //remove();

      //removeAll();

      //set();

      //subList();

      //print1();

      print2();

   }

 

   publicstaticvoid print2() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bb");

      list1.add("cc");

      list1.add("dd");

      String[]str = (String[]) list1.toArray(new String[list1.size()]);

      for(int x =0;x<str.length; x++)

         System.out.println(str[x]);

   }

 

   publicstaticvoid print1() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bb");

      list1.add("cc");

      list1.add("dd");

      Object[]arr = list1.toArray();

      for(int x =0; x<arr.length; x++)

         System.out.println(arr[x]);

   }

 

   publicstaticvoid subList() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bb");

      list1.add("cc");

      list1.add("dd");

      //从1号索引截取到3号索引之间的元素,生成新的数组

      Listlist2 = list1.subList(1,3);

      System.out.println(list2);

   }

 

   publicstaticvoid set() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bb");

      list1.add("cc");

      list1.add("dd");

      //将list1中1号索引的元素改成xx

      System.out.println(list1.set(1,"xx"));

      System.out.println(list1);

   }

 

   publicstaticvoid removeAll() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bb");

      list1.add("cc");

      list1.add("dd");

      Listlist2= newLinkedList();

      list2.add("aaa");

      list2.add("bb");

      list2.add("xx");

      //从list1中删除和list2重复的元素,只要删了,就返回true

      System.out.println(list1.removeAll(list2));

      System.out.println(list1);

      // 在list1中保留和list2重复的元素, list1中没有的全部删除

      list1.retainAll(list2);

      System.out.println(list1);

   }

 

   publicstaticvoid remove() {

      Listlist = newLinkedList();

      list.add("aa");

      list.add("bb");

      list.add("cc");

      list.add("dd");

      list.add("aa");

      list.add("aa");

      //删除1号索引上的元素,并将元素返回;删除的是bb

      System.out.println(list.remove(1));

      System.out.println(list.remove(1));

      //删除list中的aa,如果删掉了就返回true,如果存在多个,只删除第一次出现的

      System.out.println(list.remove("aa"));

      System.out.println(list);

   }

 

   publicstaticvoid indexOf() {

      Listlist1 = newLinkedList();

      list1.add("aa");

      list1.add("bb");

      list1.add("cc");

      list1.add("aa");

      list1.add("aa");

      //查找aa在数组中第一次出现的位置

      System.out.println(list1.indexOf("aa"));

      //最后一次出现的位置

      System.out.println(list1.lastIndexOf("aa"));

   }

 

   publicstaticvoid equals() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bb");

      Listlist2= newLinkedList();

      list2.add("aaa");

      list2.add("bb");

      //判断list1和list2中的元素是否都相同,

      System.out.println(list1.equals(list2));

   }

 

   publicstaticvoid containsAll() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bb");

      list1.add("cc");

      Listlist2= newLinkedList();

      list2.add("aaa");

      list2.add("bb");

      list2.add("xx");

      //判断list2中的元素是否在list1中全部存在,用equals判断;

      System.out.println(list1.containsAll(list2));

   }

 

   publicstaticvoid contains() {

      Listlist = newLinkedList();

      list.add(new String("aaa"));

      list.add("bbb");

      //判断list数组中是否包含"aaa" ,使用equals方法判断

      System.out.println(list.contains("aaa"));

      System.out.println(list.contains("bb"));

   }

 

   publicstaticvoid clear() {

      Listlist = newLinkedList();

      list.add("aaa");

      list.add("bbb");

      list.add("ccc");

      //清空集合,删除数组中所有元素

      list.clear();

      System.out.println(list);

      //打印数组长度

      System.out.println(list.size());

      //判断集合是否为空,如果是结果为true

      System.out.println(list.isEmpty());

   }

 

   publicstaticvoid addAll() {

      Listlist1 = newLinkedList();

      list1.add("aaa");

      list1.add("bbb");

      list1.add("vvv");

      Listlist2 = newLinkedList();

      list2.add("ccc");

      list2.add("ddd");

      //和下面有个区别,打印结果把中括号也插入到了list1中

      list1.add(1,list2);

      //将list2数组所有元素插入到list1数组中的1号索引处,list1中的原有元素向后顺延;

      list1.addAll(1,list2);

      System.out.println(list1);

   }

 

   publicstaticvoid add() {

      Listlist = newLinkedList();

      list.add("aaa");

      list.add("bbb");

      //将"vvv"添加到数组中1号索引

      list.add(1,"vvv");

      System.out.println(list);

//结果为boolean返回true;添加成功,

System.out.println(list.add(123));

System.out.println(list);

   }

 

}

5.集合的遍历:

For循环:循环size(),每次调用get(int)方法获取一个元素

迭代器:使用iterator方法获取一个iterator对象,调用hasNext()方法判断是否包含下一个元素,调用next()获取下一个元素;

迭代器就是集合取出元素的方式;迭代器是取出方式,会直接访问集合中的元素。所以将迭代器通过内部类的形式来进行描述。

通过容器的iterator()方法获取该内部类的对象。

增强for循环:for(类型变量名 :容器){循环体}容器长度是多少就执行多少次循环体,变量每次饮用容器中的一个元素;

package cn.itcast;

 

import java.util.Iterator;

import java.util.LinkedList;

import java.util.List;

 

publicclass ListIteratorDemo {

 

   /**

    * @param args

    */

   publicstaticvoid main(String[] args) {

      // TODO Auto-generated method stub

      Listlist = newLinkedList();

      list.add("aa");

      list.add("bb");

      list.add("ccc");

      //itertator1(list);

      //itertator2(list);

      //iterator3(list);

      forIterator(list);

   }

 

   privatestaticvoid forIterator(List list) {

//iterator3的改写;

      for(Iterator iter = list.iterator();iter.hasNext();)

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

   }

 

   //

   privatestaticvoiditerator3(List list) {

      // 获取list对象的迭代器(iterator接口的子类)内部有一个指针,默认指向第一个元素之前的位置

      Iteratoriter = list.iterator();

      // 判断是否包含下一个元素,返回boolean类型

      while (iter.hasNext())

         // 如果有,就打印下一个元素;

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

   }

 

   privatestaticvoiditertator2(List list) {

      // 普通for循环,只能List用,Set不能用

      for (int i = 0; i < list.size(); i++)

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

   }

 

   privatestaticvoiditertator1(List list) {

      // 遍历集合,List和Set通用;

      // 增强for循环格式;for(类型 变量名: 容器) {循环体}

      for (Object obj : list)

         System.out.println(obj);

   }

 

}

List集合特有的迭代器:ListInteratorIterator的子接口;

在迭代时,不可以通过集合对象的方法操作集合中的元素;因为会发生ConcurrentModificationException异常(事件并发异常);所以,在迭代器时,只能用迭代器的方法操作元素,可是iterator方法时有限的,如果想要其他的操作如添加,修改等,就需要使用其子接口ListIterator;

该接口只能通过List集合的listIterator方法获取;

:

import java.util.List;

import java.util.ListIterator;

 

publicclass ListDemo {

 

   publicstaticvoid main(String[] args) {

      // TODO Auto-generated method stub

      ArrayListal = newArrayList();

      al.add("java");

      al.add("javase");

      al.add("javaee");

      al.add("javaweb");

      //创建列表迭代器;

      ListIteratorit = al.listIterator();

      //判断是否有下一个元素;

      while(it.hasNext())

         //如果有,就打印出来

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

      //判断是否有上一个元素;

      while(it.hasPrevious())

         //如果有则打印;

         System.out.println("previous>>"+it.previous());

               

}

}   输出结果是java

javase

javaee

javaweb

previous>>javaweb

previous>>javaee

previous>>javase

previous>>java

 

 

6.遍历时删除元素:

for循环由于在list集合中删除元素之后,后面的元素会向前移动,所以每次删除之后将遍历循环-1;

迭代器:   迭代器在使用过程中不允许修改集合,如果要修改,必须使用迭代器中的remove方法;

增起for循环:无法在循环过程中修改集合;

7.泛型:用于解决安全问题,是一个类型安全机制;

      JDK1.5之后支持带有泛型的类, 集合上如果加了泛型, 只能存储同一类型的数据, 获取数据时的类型也被指定了

*泛型的优点:

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

2,避免了强制转换麻烦

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

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

通常在集合框架中常见,只要见到<>就要定义泛型,其实<>就是要接受类型的,当使用集合时,将集合中要存储的数据类型作为参数传递到<>中即可;

//练习:删除年龄为19的对象;

   packagecn.itcast.day16.list;

 

import java.util.ArrayList;

 

publicclass GenericDemo {

 

   publicstaticvoid main(String[] args) {

      List<Person>list = new ArrayList<Person>();  // 集合一旦指定泛型,只能存储同一类型数据, 获取时的类型也不再是Object了

      list.add(new Person("张三", 19));

      list.add(new Person("李四", 20));

      list.add(new Person("王五", 19));

      list.add(new Person("赵六", 19));

     

//    demo1(list);

//    demo2(list);

//    demo3(list);

   }

 

   privatestaticvoiddemo3(List<Person>list) {

      for (Person p : list)

         if (p.getAge() == 19)

            System.out.println(p.getName());

   }

 

   privatestaticvoiddemo2(List<Person>list) {

      for (Iterator<Person> iter = list.iterator(); iter.hasNext();){

         Personp = iter.next();

         if (p.getAge() == 19)

            System.out.println(p.getName());

      }

   }

 

   privatestaticvoiddemo1(List<Person>list) {

      for (int i = 0; i < list.size(); i++)

         if (list.get(i).getAge() == 19)

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

   }

 

}

泛型类和泛型方法:

泛型类:

什么时候定义泛型类?

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

现在定义泛型来完成扩展。

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

泛型的限定;用来支持泛型的扩展;

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

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

   :

packageGeneriDemo;

 

publicclass GeneriDemo {

publicstaticvoid main(String[] args) {

      /*泛型前的作法;

      Tool t = new Tool();

      t.setObject(new Worker());

      Worker w = (Worker)t.getObject();

      */

      Util<Worker> u = new Util<Worker>();

      u.setObject(new Worker());

      Worker w = u.getObject();

   }

 

}

class Util<T>{      //将泛型定义在类上;

   private Tt;

   publicvoid setObject(T t) {

      this.t = t;

   }

   public T getObject() {

      returnt;

   }

}

/*//泛型前的作法;

classTool {

   private Object obj;

   public void setObject(Objectobj) {

      this.obj = obj;

   }

   public Object getObject() {

      return obj;

   }

}

*/

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

注意:泛型定义在方法上的位置,一定是在返回值类型前,方法修饰符后;其他位置报错;

publicclass GenericDemo {

   publicstaticvoid main(String[] args) {

      Demo d = newDemo();

      d.show(new Integer(3));//调用方法打印不同数据类型的对象;

      d.show("abc");

      d.print('a');

      d.fun("good good study");

   }

 

}

/*

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

 */

class Demo<T>{

   //静态方法上定义泛型;

   publicstatic <Q>void fun(Q q) {

      System.out.println("fun="+q);

   }

  

   public void show(T t) {

      System.out.println("show="+t);

   }

   public <T>void print(T t) {     //将泛型定义在方法上;

      System.out.println("print="+t);

   }

  

}

 

练习:模拟Java提供的ArrayList结构;

package List;

 

publicclass MyArrayList {

  

   private Object[]arr = new Object[10]; //用来装载元素的数组;

   privateintsize;    //集合的大小;

   /**自定义ArrayList,内部就是将元素添加到数组中

    * @param obj   要添加的对象;

    * @param return 添加成功

    */

   publicboolean add(Object obj) {

      if(size ==arr.length) {   //如果数组满了

         Object[] newArr = new Object[arr.length * 3/2 +1];//创建一个新数组,重新定义数组长度

         System.arraycopy(arr,0,newArr,0,size);     //将原数组中的元素拷贝到新数组中

         arr = newArr;        //原数组记住新数组;

      }

      arr[size++] = obj;

      returntrue;

   }

   /**

    * 删除指定索引上的元素

    * @param index要删除的索引

    * @return     被删除的元素

    */

   public Object remove(int index) {

      checkRange(index);

      Object oldobj = arr[index];       //定义变量,记住原对象;

      System.arraycopy(arr,index+1,arr,index,size-index-1);//将要删除位置的后面元素向前移动一位;覆盖要删除的元素;

      arr[--size] =null;              //将最后一个元素删除(将要删除的元素指定为null,并将size--.)

      return oldobj;                //将删除的元素返回;

   }

   /**

    * 将集合中指定位置上的元素替换为指定元素

    * @param index要替换的位置

    * @param obj  要替换成哪个对象

    * @return     被替换掉的对象

    */

   public Object set(int index ,Object obj) {

      checkRange(index);

      Object oldobj = arr[index];       //记住原对象;

      arr[index] = obj;             //将原对象替换为新对象;

      return oldobj;                //将原对象返回;

   }

   /**

    * 检查索引是否越界

    * @param index要检查的索引

    */

   privatevoid checkRange(int index) {

   if(index >=size)        //如果索引越界,抛出异常;

         thrownew IndexOutOfBoundsException("index="+index+",size="+size);

   }

   /**

    * 获取集合中指定索引上的元素

    * @param index指定索引

    * @return     索引上的元素

    */

   public Object get(int index) {

      checkRange(index);

      returnarr[index];

   }

   /**

    * 获取集合的大小

    * @return  集合的大小

    */

   publicint size() {

      returnsize;

   }

   /**

    * 重写Object类的toString,返回集合中每个元素的toString

    * @return  每个元素的toString

    */

   public String toString() {

      //将集合中每个元素添加到StringBuilder

      StringBuilder sb = new StringBuilder();

      sb.append("[");

      for(int i = 0; i <size; i++)

         sb.append(arr[i]+(i <size -1 ? ", " :""));// 如果不是最后一个,加上逗号和空格

      sb.append("]");

      return sb.toString();

   }

}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值