黑马程序员--Java基础学习笔记【集合-List、泛型】

 

 ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------   

 

集合框架 Collection  java.util(interface)

集合 只能存储引用类型,存储对象,不存储基本类型,长度可变

数组 存储基本类型,存储对象,长度固定

 

    集合中存储的都是引用类型的元素,那么引用类型变量实际上存储的是对象的“地址”,所以实际上集合只存储了元素对象在堆中的地址,而并不是将对象本身存入了集合中。

 

Collection 接口

是层次结构中的根接口,定义了集合相关的操作方法。

其有两个子接口:List(可重复集)和Set(不可重复集)

元素是否重复,取决于元素的equals() 比较的结果

 

成员方法:

boolean add(E e) // 添加元素

boolean remove(E e) // 移除第一次出现的指定元素

void clear() // 清空集合

boolean contains(Object o) // 判断是否包含指定对象

boolean isEmpty() // 判断集合是否为空

int size() // 返回集合的大小(容量),即集合中存储元素的个数

boolean addAll(Collection c) // 添加指定集合中的所有元素

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

boolean containsAll(Collection c) // 判断是否包含指定集合的所有元素

boolean retainAll(Collection c) // 保留与指定集合中相同的元素(获取交集)

Object[] toArray() // 集合 --> 数组,可以实现集合的遍历

Iterator<E> iterator() // 获取迭代器,集合专用的遍历方式

*  迭代器迭代结合,泛型跟随集合

Iterator 迭代器

    集合专用遍历方式,做集合中元素的获取

    集合顶层接口Collection中,定义了一个抽象方法Iterator<E> iterator(),返回值是接口类型,返回的是该接口的实现类对象。

    迭代器接口的实现类是集合容器的内部类,Collection下面所有的实现类,都会重写该方法。比如 ArrayList 实现 List 接口,而 List 继承自Collection。

    迭代器类的成员方法:

    boolean hasNext() // 判断集合中是否还有下一个元素

    <E> next() // 获取迭代的下一个元素

    void remove() // 移除本次迭代后迭代器返回的最后一个元素

    迭代器的删除方法是在原集合中删除元素

  • ConcurrentModificationException

在使用迭代器遍历集合时,不能通过集合的remove() 方法删除集合元素,否则会抛出并发更改异常,可以通过迭代器自身提供的remove() 方法删除通过next() 迭代出的元素。

在调用remove() 方法前必须通过迭代器的next() 方法迭代过元素,那么删除的就是这个元素。并且不能再次调用remove() 方法,除非再次调用next() 后方可再次调用。

 

  • 使用迭代器接口的两种方式,一般使用 while 循环

Iterator iterator = collection.iterator();

// 调用迭代器接口方法判断集合中有没有下一个元素

while (iterator.hasNext()) {

    // 调用迭代器接口方法获取出集合中的元素

    Object object = iterator.next();

    System.out.println(object);

}

for (Iteratoriterator = collection.iterator(); iterator.hasNext();){

    Object object = iterator.next();

    System.out.println(object);

}

 

增强型for循环

since JDK1.5,只用于遍历集合或数组,也称新循环

格式:

    for(元素类型 变量名 : 集合或数组) {

        循环体

    }

好处:减少代码量,方便做遍历;弊端:不能改动数组或集合中的元素

增强for循环并非新的语法,而是在编译过程中,编译器会将新循环转换为迭代器模式。所以新循环本质上是迭代器。

 

遍历集合的 3 种方式:迭代器,增强 for 循环,普通for 循环(size() + get())

 

List 接口 继承 Collection 接口

特点:有序集合,存取有序,有索引,允许重复

 

成员方法

void add(int index, E element) // 向指定索引处添加元素

E remove(int index) // 移除指定索引处的元素并返回该元素

E get(int index) // 获取指定索引上的元素

E set(int index, E element) // 替换指定索引上的元素并返回之前的元素

ListIterator<E> listIterator() // 获取迭代器

int lastIndexOf(Object o) // 返回指定元素出现的最后一个位置的索引

List<E> subList(int fromIndex, inttoIndex) // 获取子List

--------------------------------------------------------------------

importjava.util.ArrayList;

importjava.util.List;

 

/*

 * 证明 subList 获取的 List 与原 List 占用相同的存储空间,对子 List 的操作会影响原 List

 */

public classSubListDemo {

    public static void main(String[] args) {

       List<Integer> list = newArrayList<>();

       for (int i = 0; i < 10; i++) {

           list.add(i);

       }

       System.out.println("list " +list);

       // list [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

 

       List<Integer> subList =list.subList(3, 8);

       System.out.println("subList " +subList);

       // sublist [3, 4, 5, 6, 7]

 

       // subList 获得的 List 和原 List 占有相同的数据空间

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

           subList.set(i, subList.get(i) * 10);

       }

       System.out.println("changedsubList" + subList);

       // changedsublist [30, 40, 50, 60, 70]

       System.out.println("unchangedlist" + list);

       // unchangedlist [0, 1, 2, 30, 40, 50,60, 70, 8, 9]

 

       list.subList(3, 8).clear(); // 可以用于删除连续元素

       System.out.println(list);

       // [0, 1, 2, 8, 9]

    }

}

 

ListIterator 列表迭代器

    允许按任一方向遍历列表,迭代期间可以修改列表

    void add(E e)

    booleanhasNext() // 正向遍历

boolean hasPrevious() // 逆向遍历

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

int nextIndex() // 返回返回下一个索引

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

int previousIndex() // 返回前一个索引

void remove() // 移除本次迭代后迭代器返回的最后一个元素

void set(E e) // 替换此次迭代后迭代器返回的最后一个元素

 

  • 对 List 集合进行正向遍历和逆向遍历

List list= newArrayList<>();

       list.add("www");

       list.add("itcast.");

    list.add("cn");

       // 调用集合方法,获取ListIterator接口的实现类对象

       ListIteratoriterator=list.listIterator();

      

       while (iterator.hasNext()) {

           Objectobject= (Object) iterator.next();

           if ("www".equals(object)) {

              // 调用迭代器的方法

              // 添加元素到迭代到元素的下一个位置

//            iterator.add("0807Java");// 添加和修改不能在同一次迭代中

              // 修改迭代到的元素

              iterator.set("www.");

           }

       }

       //迭代器指针到了最后,不能再次获取,出现没有元素被取出异常

      

       // 逆向遍历逆向遍历之前要先做一次正向遍历

       while (iterator.hasPrevious()) {

           Objectobject= (Object) iterator.previous();

           System.out.print(object + " "); // cn itcast. www.

       }

 

  • 泛型机制 Generic since JDK5

泛型在集合中的应用

泛型的本质是参数化类型。在类、接口和方法的定义过程中,所操作的数据类型被传入的参数指定,强制集合必须存储指定的数据类型,保证程序的安全性。

Java泛型机制广泛的应用在集合框架中,所有的集合类型都带有泛型参数,这样在创建集合时可以指定放入集合中元素的类型。Java编译器可以据此进行类型检查,这样可以减少代码在运行时出现错误的可能性。

集合类<存储的数据类型> 变量名 = new 集合类<存储的数据类型>();

好处:减少代码量,避免类型强制转换,安全问题由运行时期提前到了编译时期。

Java中的泛型是伪泛型,只在编译时期有效,编译后的class文件中没有泛型,编译手段。

ArrayList类的定义中,<E> 中的 E 为泛型参数(理解为变量名,相当于定义了一个变量,负责接收数据类型),在创建对象时可以将类型作为参数传递,此时,类定义所有的 E 将被替换成传入的参数。

*注意:集合存储八种基本类型,泛型必须写包装类;迭代器迭代结合,泛型跟随集合

 

泛型类、泛型方法

 

package cn.itcast;

 

/*

 * 自定义泛型类

 *  自己写的类上,加上泛型<变量>

 *

 * 定义成员变量,也是泛型

 *

 * E 变量,等待建立此类对象的时候,由调用者指定他的数据类型

 */

class GenericClass<E> {

    private E e;

 

    /*

     * 泛型方法

     *  方法参数上,使用了一个和类上一样的泛型

     *  创建类的对象的时候,直接指定数据类型

     * 

     *  方法上泛型需要单独的定义,定义在方法的声明上

     *  创建类的对象同时,不能指定方法上泛型,调用者调用方法时直接指定

     * 

     * 静态方法参数上的泛型,不能和类上的泛型一样

     * 原因:静态不能直接调用非静态

     */

    publicvoid show(E e) {

       System.out.println(e);

    }

 

    public <W> void function(W w){

       System.out.println(w);

    }

   

    publicstatic <C> void method(C c){

       System.out.println(c);

    }

   

    public E getE() {

       returne;

    }

 

    publicvoid setE(E e) {

       this.e = e;

    }

 

}

 

publicclassGenericDefine {

 

    publicstaticvoid main(String[] args) {

       GenericClass<Integer>genericClass= newGenericClass<Integer>();

       genericClass.setE(123);

       Integerinteger= genericClass.getE();

       System.out.println(integer);

 

       GenericClass<String>genericClass2= newGenericClass<String>();

       genericClass2.setE("abc");

       Stringstring= genericClass2.getE();

       System.out.println(string + 1);

 

       System.out.println("--------------");

       genericClass2.show("传智播客");

    }

 

}

 

泛型接口

 

package cn.itcast;

 

/*

 * 泛型接口

 *  接口上定义泛型,接口中方法全抽象,实现类

 *  在使用上两种使用方式:

 *     实现类实现接口,不理会泛型

 *     实现类实现接口,同时也实现接口上的泛型

 */

interface Inter<T> {

    publicabstractvoid show(T t);

}

 

// 定义接口的实现类,实现接口,不理会接口上的泛型

// 泛型的指定,实现类没有做,让调用者来指定数据类型

class InterImpl<T> implements Inter<T> {

    @Override

    publicvoid show(T t) {

       System.out.println(t);

    }

}

 

// 定义接口的实现类,实现接口的同时,也实现泛型 -- 不灵活

class InterImpl2 implements Inter<String>{

    @Override

    publicvoid show(String t) {

       System.out.println(t);

    }

}

 

publicclassGenericInterfaceDemo {

 

    publicstaticvoid main(String[] args) {

       Inter<Integer>in = newInterImpl<Integer>();

       in.show(123);

      

       Inter<String>in2= newInterImpl<String>();

       in2.show("itcast");

    }

 

}

 

泛型的限定:泛型通配符 <?>

? extends E (向下限定,E及其子类)    ? super E (向上限定,E及其父类)

 

  • 线性表

    List接口是Collection的子接口,用于定义线性表数据结构,可以将List理解为存放对象的数组,只不过其元素个数可以动态的增加或减少。

    List接口的两个常用实现类为 ArrayList LinkedList,分别用动态数组和链表的方式实现了List接口。

 

    List 三个子类的特点

共同特点:有序,索引,重复。

    ArrayList LinkedList在性能上有一定的差别。

    ArrayList 更适合于随机访问,而LinkedList 更适合于插入和删除。

    ArrayList 底层数据结构是可变数组,元素查询速度快,增删慢

       线程不安全,不同步,运行速度快

       默认容量 10,增长率50%

    LinkedList 底层数据结构是双向链表,元素查询速度慢,增删快

       线程不安全,不同步,运行速度快

       存储和迭代器代码,和 ArrayList 完全一样

    Vector 底层数据结构是可变数组,元素查询速度快,增删慢

       线程安全,同步,运行速度慢

       默认容量 10,增长率 100%

 

Vector 特有方法:

    void addElement(E obj) // 将指定的组件添加到向量的末尾,容量+1

    E elementAt(int index) // 返回指定索引处的组件

    Enumeration elements() // 返回此向量的组件的枚举

LinkedList 特有方法:

    void addFirst(E e)       voidaddLast(E e);

    E getFirst()         EgetLast()

    E removeFirst()      EremoveLast()

 

  • 去除集合中存储的重复元素

 

package cn.itcast;

 

importjava.util.ArrayList;

importjava.util.Iterator;

 

/*

 * 去除集合中字符串的重复值 -- 去除数组中重复元素

 * 去除集合中自定义对象的重复值(需要重写自定义对象的equals()方法

 * ArrayList集合实现,List允许重复

 * String 类重写了equals() 方法,建立了自己的比较方式)

 * 如果原集合中元素没有出现在新集合中,将该元素存储到新集合中

 * 遍历完毕,新集合保存的就是去掉重复后的元素

 * 将原集合的引用指向新集合

 */

public classArrayListTest {

 

    public static void main(String[] args) {

       ArrayList<String> list = new ArrayList<String>();

       list.add("www");

       list.add(".itcast");

       list.add(".cn");

       list.add("www");

       list.add(".itheima");

       list.add(".com");

 

       list = removeSame(list);

       System.out.println(list); // [www, .itcast, .cn, .itheima,.com]

 

    }

 

    // 返回的是去重复之后的新集合

    public static ArrayList<String>removeSame(ArrayList<String> arrayList) {

       // 创建新集合,保存去重复之后的元素

       ArrayList<String> newList = newArrayList<String>();

      

       // 迭代原集合

       Iterator<String> iterator = arrayList.iterator();

       while (iterator.hasNext()) {

           // 接收迭代元素的结果

           String string = iterator.next();

           // 判断新集合中是否包含该元素,没有则添加进去

           if (!newList.contains(string)) {

              newList.add(string);

           }

       }

       return newList;

    }

}

 

  • LinkedList 模拟栈数据结构的集合

 

package cn.itcast;

 

import java.util.LinkedList;

 

/*

 * LinkedList集合,模拟数据结构

 *

 * LinkedList集合中的功能封装起来,调用者不直接面对集合,只能从外部调用

 * 表现为先添加的元素后被取出,存储和取出的顺序是相反的

 */

publicclassLinkedListTest {

 

    publicstaticvoid main(String[] args) {

       LinkedListToollist= newLinkedListTool();

       list.add(0);

       list.add(1);

       list.add(2);

       list.add(3);

 

       // 当列表不为空时,删除元素并返回

       while (!list.isEmpty()) {

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

       }

    }

 

}

 

// 自定义功能,封装LinkedList类功能

class LinkedListTool {

    // 定义成员变量

    privateLinkedList<Object> list;

 

    // 构造方法用于新建对象

    public LinkedListTool() {

       list = newLinkedList<Object>();

    }

 

    // 添加元素到列表结尾

    publicvoid add(Object object) {

       list.add(object);

    }

 

    // 判断列表是否为空

    publicboolean isEmpty() {

       returnlist.isEmpty();

    }

 

    // 从列表结尾删除元素并返回

    public Object remove() {

       returnlist.removeLast();

    }

 

}

 

List 集合 < == > 数组

List 转换为数组集合转成数组,带有泛型

    Object[] toArray()

    <T>T[] toArray(T[] a)

 

       List<String>strings = new ArrayList<>();

       strings.add("www");

       strings.add(".itcast");

       strings.add("cn");

       String[] str = strings.toArray(newString[strings.size()]);

       // 传入一个指定类型的数组,该数组的元素类型应与集合的元素类型一致。

       // 返回值则是转换后的数组,该数组会保存集合中所有的元素

       for (inti = 0; i< str.length; i++){

           System.out.print(str[i] + " ");

       }

 

数组转换为 List

    Arrays 类中提供了一个静态方法 asList,使用该方法我们可以将一个数组转换为对应的 List 集合。其方法定义为: static <T> List<T> asList<T… a>

    注意:返回的 List的集合元素类型由传入的数组的元素类型决定;返回的集合不能对其增删元素,否则会抛出异常,并且对集合的元素进行修改会影响数组对应的元素。

 

        String[] strArr = { "www", ".itcast", ".cn" };

        List<String>list =Arrays.asList(strArr); // fixed-size list

       System.out.println(list); // [www, .itcast, .cn]

       // 当前集合 list 的实际类型为 java.util.Array$ArrayList

       //而不是 List 接口的实现类 java.util.ArrayList,所以不支持对其添加或删除元素

 

       // list.add("IT"); // 会抛出 UnsupportedOperationException

      

       System.out.println(list.getClass().getName());

      

       list.set(0, "3w"); // 可以修改元素

       // 对集合元素的修改会影响原数组

       System.out.print("String[] ");

       for (String string : strArr) {

           System.out.print(string + " ");

       }

       System.out.println();

      

       // 如果想要添加元素,可以用如下方式:

       List<String>list2= newArrayList<>();

       list2.addAll(Arrays.asList(strArr));

       System.out.println(list2); // [3w, .itcast, .cn]

       list2.add("0807JavaSE");

       System.out.println(list2); // [3w, .itcast, .cn, 0807JavaSE]

 

可变参数 since JDK5

    如果定义方法的时候,参数类型明确但个数不明确,可使用可变参数

格式:修饰符返回值类型方法名(数据类型...变量名) {}

可变参数方法传递,传递实际参数,数量没有限制

注意:一个方法中只能写 1 个可变参数,如果有多个参数可变参数只能放在最后

 

package cn.itcast.arguments;

 

publicclassVarArgumentsDemo {

 

    publicstaticvoid main(String[] args) {

       intsum = getSum(0, 1,2, 3, 4, 5);

       System.out.println(sum);

    }

 

    publicstaticint getSum(int...is){

       intsum = 0;

       // 传递参数的个数,就是数组的长度

       // 如果不传递任何参数,可变参数的数组的长度就是 0

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

//         sum+= is[i];

//     }

       for (inti : is) {

           sum += i;

       }

       returnsum;

    }

}

 

l  获取101-20之间的随机数,要求不能重复

 

package cn.itcast.test;

 

importjava.util.ArrayList;

import java.util.List;

importjava.util.Random;

 

/*

 * 获取101-20之间的随机数,要求不能重复

 */

public class ListTest {

 

    public static void main(String[] args) {

       Random r = new Random();

       List<Integer> list = new ArrayList<Integer>();

      

       while (true) {

           // 获取随机数

           int num = r.nextInt(20) + 1;

           // 判断随机数如果不在集合中,就存储到集合

           if (!list.contains(num)) {

              list.add(num);

              // 判断集合容量为10就退出循环

              if (list.size() == 10) {

                  break;

              }

           }

       }

      

       for (Integer integer : list) {

           System.out.println(integer);

       }

    }

}

 

l  键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值

package cn.itcast.test;

 

importjava.util.ArrayList;

import java.util.List;

importjava.util.Scanner;

 

/*

 * 键盘录入多个数据,以0结束

 * 在控制台输出最大值:

 *  利用数组,将集合转成数组

 *     1.升序排序,获取最后一个元素

 *     2.获取数组中的最大值

 *

 */

public classListScannerTest {

 

    public static void main(String[] args) {

       Scanner sc = new Scanner(System.in);

       List<Integer> list = new ArrayList<Integer>();

       while (true) {

           int num = sc.nextInt();

           if (num == 0) {

              break;

           }

           // 数据存储到集合中

           list.add(num);

       }

       sc.close();

//     System.out.println(list);

      

       // 将集合转成数组

       Integer[] integers = list.toArray(new Integer[list.size()]);

       // 选择排序

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

           for (int j = i + 1; j < integers.length; j++) {

              if (integers[i] > integers[j]) {

                  int temp = integers[i];

                  integers[i] = integers[j];

                  integers[j] = temp;

              }

           }

       }

       // 输出数组中的最后一个索引

       System.out.println(integers[integers.length - 1]);

      

       // 求数组最值思想

//     int max = list.get(0);

//     for (Integer integer : integers) {

//         if (integer > max)

//            max = integer;

//     }

//     System.out.println(max);

      

    }

 

}

 

List 排序

Collections.sort() 方法实现排序

Collections 是集合的工具类,提供很多便于操作集合的方法。

void sort(List<T>list) // 该方法的作用是对给定的集合元素进行自然排序


你可能感兴趣的:(集合,泛型,list)