第二阶段-day04_Generic

今天我们主要讲了List的子类:ArrayList, Vector, LinkedList 以及 JDK5 的一些特性:静态导入和泛型。

接昨天的练习:

Ex3:反转链表

 1 package com.cskaoyan.exercise;
 2 
 3 public class Ex1 {
 4     public static Node reverse(Node head) {
 5         if (head.next == null) return head;
 6         // 如果链表不止一个结点,反转head.next
 7         Node reversed = reverse(head.next);
 8         // 反转head结点
 9         head.next.next = head;
10         head.next = null;
11         return reversed;
12     }
13     public static void print(Node head) {
14         Node x = head;
15         while (x != null) {
16             System.out.print(x.value);
17             if (x.next != null) System.out.print(" --> ");
18             x = x.next;
19         }
20         System.out.println();
21     }
22 
23     public static void main(String[] args) {
24         Node head = new Node(3);
25         head = new Node(2, head);
26         head = new Node(1, head);
27         print(head);
28         head = reverse(head);
29         print(head);
30     }
31 }

 

数组VS链表

 

 

 

数组和链表的插入,删除,随机访问操作的时间复杂度刚好相反。
① 数组使用的是连续的内存空间,可以利用CPU的高速缓存预读数据。链表的内存空间不是连续的,不能有效预读数据。当然如果数组过大,系统没有足够的连续内存空间,会抛出OOM。
 
② 数组的缺点是大小固定,没法动态的调整大小。如果要存储一些对象,如果数组太大,浪费内存空间;如果数组太小,我们需要重新申请一个更大数组,并将数据拷贝过去,耗时。
 
③如果业务对内存的使用非常苛刻,数组更适合。因为结点有指针域,更消耗内存。而且对链表的频繁插入和删除,会导致结点对象的频繁创建和销毁,有可能会导致频繁的GC活动。

List子类

  • ArrayList

底层数据结构是数组,查询快,增删慢
线程不安全,效率高

 1 package com.cskaoyan.list;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Collection;
 5 
 6 /*
 7 ArrayList
 8 特性:
 9     底层数据结构是数组,增删慢,查找快。
10     不同步, 线程不安全, 效率高。
11     存储null元素
12 构造方法:
13     ArrayList(): 默认初始大小为10
14     ArrayList(int initialCapacity): 可以指定数组的初始大小
15     ArrayList(Collection c)
16 API:
17     void ensureCapacity(int minCapacity): 避免频繁扩容
18     void trimToSize():慎用,确保元素不会在添加的情况下用。
19  */
20 public class ArrayListDemo1 {
21     public static void main(String[] args) {
22         // ArrayList list = new ArrayList();
23         // ArrayList list = new ArrayList(100);
24         // System.out.println(list);
25 
26         Collection c = new ArrayList();
27         c.add("hello");
28         c.add("world");
29         c.add("java");
30         ArrayList list = new ArrayList(c);
31         System.out.println(list);
32         list.add(null);
33         list.add(null);
34         list.add(null);
35         System.out.println(list);
36     }
37 }

 

  • Vector

底层数据结构是数组,查询快,增删慢
线程安全,效率低
Vector 特有的API
public void addElement(E obj)
public E elementAt(int index)
public Enumeration elements()

 1 package com.cskaoyan.list;
 2 
 3 import java.util.Vector;
 4 
 5 /*
 6 Vector
 7 特性:
 8     底层是数组,增删慢,查找快
 9     同步, 线程安全, 效率比较低
10     存储null元素
    JDK1.0就已经有了
11 API: 12 void addElement(E obj) --> void add(E e) 13 void copyInto(Object[] anArray) --> Object[] toArray() 14 E elementAt(int index) --> E get(int index) 15 void insertElementAt(E obj, int index) --> void add(int index, E e) 16 void removeAllElements() --> void clear() 17 boolean removeElement(Object obj) --> boolean remove(Object obj) 18 void removeElementAt(int index --> E remove(int index) 19 void setElementAt(E obj, int index) --> E set(int index) 20 Enumeration<E> elements() --> Iterator iterator() 21 22 int capacity() 23 void setSize(int newSize) 24 E firstElement() 25 E lastElement() 26 int indexOf(Object o, int index) 27 int lastIndexOf(Object o, int index) 28 29 Enumeration<E> elements() 30 */ 31 public class VectorDemo1 { 32 public static void main(String[] args) { 33 34 Vector vector = new Vector(); 35 // int capacity() 36 /*System.out.println(vector.capacity()); // 10 37 System.out.println(vector.size()); // 0 38 System.out.println(vector);*/ 39 40 // void setSize(int newSize) 41 /*vector.setSize(20); 42 System.out.println(vector.capacity()); 43 System.out.println(vector.size()); 44 System.out.println(vector);*/ 45 vector.add("hello"); 46 vector.add("world"); 47 vector.add("java"); 48 /*System.out.println(vector.capacity()); 49 System.out.println(vector.size()); 50 System.out.println(vector); 51 52 vector.setSize(1); 53 System.out.println(vector.capacity()); 54 System.out.println(vector.size()); 55 System.out.println(vector);*/ 56 57 // vector.clear(); 58 //E firstElement() 59 // System.out.println(vector.firstElement()); // NoSuchElementException 60 //E lastElement() 61 // System.out.println(vector.lastElement()); NoSuchElementException 62 63 vector.add("hello"); 64 vector.add("hello"); 65 vector.add("hello"); 66 System.out.println(vector); 67 // int indexOf(Object o, int index) 68 // System.out.println(vector.indexOf("hello")); 69 /* System.out.println(vector.indexOf("hello", 1)); 70 System.out.println(vector.indexOf("hello", 3));*/ 71 72 // int lastIndexOf(Object o, int index) 73 /*System.out.println(vector.lastIndexOf("hello")); 74 System.out.println(vector.lastIndexOf("hello", 3)); 75 System.out.println(vector.lastIndexOf("hello", 1));*/ 76 } 77 }

 

 1 package com.cskaoyan.list;
 2 
 3 import java.util.Enumeration;
 4 import java.util.Iterator;
 5 import java.util.Vector;
 6 
 7 /*
 8 Enumeration:                        -->     Iterator
 9     boolean hasMoreElements()       -->     boolean hasNext()
10     E nextElement()                 -->     E next()
11  */
12 public class VectorDemo2 {
13     public static void main(String[] args) {
14         Vector vector = new Vector();
15         vector.add("hello");
16         vector.add("world");
17         vector.add("java");
18 
19         for(Enumeration e = vector.elements(); e.hasMoreElements(); ) {
20             String s = (String) e.nextElement();
21             System.out.println(s);
22         }
23 
24         for(Iterator it = vector.iterator(); it.hasNext(); ) {
25             String s = (String) it.next();
26             System.out.println(s);
27         }
28     }
29 }

 

  • LinkedList
底层数据结构是链表,查询慢,增删快
线程不安全,效率高
LinkedList 特有的API
      ① public void addFirst(E e)及addLast(E e)
      ② public E getFirst()及getLast()
      ③ public E removeFirst()及public E removeLast()

 

                                                                         栈和队列 

 

 1 package com.cskaoyan.list;
 2 
 3 import java.util.Iterator;
 4 import java.util.LinkedList;
 5 
 6 /*
 7 Deque接口
 8     概述:双端队列,可以在两端插入和删除
 9 
10 LinkedList implements List, Deque
11 特性:
12     底层数据结构是链表,增删快,查找慢
13     不同步, 线程不安全, 效率高
14     允许null元素
15     实现了Deque这个接口,可以当作栈,队列和双端队列来使用
16 
17 构造方法:
18     LinkedList()
19     LinkedList(Collection c)
20 
21 API:
22      Iterator<E> descendingIterator()
23      boolean removeFirstOccurrence(Object o)
24      boolean removeLastOccurrence(Object o)
25 
26 在两端的操作
27     boolean offerFirst
28     boolean pollFirst
29     boolean peekFirst
30 
31  */
32 public class LinkedListDemo1 {
33     public static void main(String[] args) {
34         LinkedList list = new LinkedList();
35         list.add("hello");
36         list.add("world");
37         list.add("java");
38 
39         // Iterator<E> descendingIterator()
40         /*for(Iterator it = list.descendingIterator(); it.hasNext(); ) {
41             String s = (String) it.next();
42             System.out.println(s);
43         }*/
44 
45         /*list.addFirst(null);
46         list.addLast(null);
47         System.out.println(list);*/
48         //  boolean removeFirstOccurrence(Object o)
49         // list.removeFirstOccurrence(null);
50 
51         // boolean removeLastOccurrence(Object o)
52         /*list.removeLastOccurrence(null);
53         System.out.println(list);*/
54 
55         //  boolean offerFirst
56         // list.offerFirst(null);
57         // System.out.println(list);
58 
59         //  boolean pollFirst
60         /*System.out.println(list.pollFirst());
61         System.out.println(list);*/
62         //  boolean peekFirst
63 
64         System.out.println(list.peekFirst());
65         System.out.println(list);
66     }
67 }

 

 1 package com.cskaoyan.list;
 2 
 3 import java.util.Deque;
 4 import java.util.LinkedList;
 5 
 6 /*
 7 栈的API:
 8     void push(E e)
 9     E pop()
10     E peek()
11 注意事项:Java中提供了Stack类,但是我们应该优先使用Deque, 而不应该使用Stack
12 
13 为什么?
14 a. Stack同步的, 效率相对来说比较低。
15 b. Stack继承了Vector, 所以Stack拥有Vector中所有的方法, 使用起来不安全。
16 
17  */
18 public class LinkedListDemo2 {
19     public static void main(String[] args) {
20         Deque stack = new LinkedList();
21         stack.push("hello");
22         stack.push("world");
23         stack.push("java");
24 
25         System.out.println(stack.peek());
26 
27         while (!stack.isEmpty()) {
28             String s = (String) stack.pop();
29             System.out.println(s);
30         }
31 
32         System.out.println(stack.peek()); // null
33     }
34 }
 
总结:
Iterable
  |--Collection
    |--List
      |--ArrayList
      |--Vector
        |---Stack
      |--LinkedList
    |--Queue
      |--Deque
        |--LinkedList
    |--Set
 
练习:
1.   去重
2.   请用ArrayList实现栈数据结构,并测试。
3.   集合的嵌套遍历
4.   获取10个1-20之间的随机整数,要求集合中的数不能重复。
 
 
Ex1:去重

 

 1 package com.cskaoyan.exercise;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Iterator;
 5 import java.util.List;
 6 import java.util.ListIterator;
 7 
 8 /*
 9 1.去重
10 输入:[a, b, c, a, a, b, c]
11 输出:[a, b, c]
12 
13 思路1:
14 1. 新键一个List result = new ArrayList();
15 2. 遍历原来的list, 判断元素是否在result中存在
16    存在:不添加
17    不存在:添加
18 3. 遍历结束后, 返回result
19 
20 思路2:
21 1. 逆序遍历list
22 2. 获取元素, 截取从0到nextIndex的子列表,判断元素是否在子列表中存在
23    存在:删除元素
24    不存在:
25 3. 遍历结束后,完成去重
26  */
27 public class Ex2 {
28     public static List disctinct1(List list) {
29         List result = new ArrayList();
30         for(Iterator it = list.iterator(); it.hasNext(); ) {
31             Object obj = it.next();
32             if (!result.contains(obj)) result.add(obj);
33         }
34         return result;
35     }
36 
37     public static void disctinct2(List list) {
38         for(ListIterator it = list.listIterator(list.size()); it.hasPrevious(); ) {
39             Object element = it.previous();
40             List subList = list.subList(0, it.nextIndex());
41             if (subList.contains(element)) it.remove();
42         }
43     }
44 
45     public static void main(String[] args) {
46         // [a, b, c, a, a, b, c]
47         List list = new ArrayList();
48         list.add('a');
49         list.add('b');
50         list.add('c');
51         list.add('a');
52         list.add('a');
53         list.add('b');
54         list.add('c');
55         // List result = disctinct1(list);
56         disctinct2(list);
57         System.out.println(list);
58     }
59 }
 
 
Ex2:请用ArrayList实现栈数据结构,并测试。
 1 package com.cskaoyan.exercise;
 2 
 3 import java.util.ArrayList;
 4 import java.util.EmptyStackException;
 5 
 6 /*
 7 a. 如果一个类持有某个类的成员,那么就能够"拥有"这个类的所有公共方法。
 8    但是我们可以对这些方法进行限制。
 9 b. 组合还可以"加强"另一个类的方法。
10 c. 可以组合多个对象
11 
12 "加强"一个方法
13 a. 继承
14 b. 组合
15 
16 设计原则:
17     优先使用组合,而不是继承
18 
19 什么情况下,可以使用继承呢?
20 如果两个类之间有"is a"的关系,可以使用继承。
21 
22 GO语言不支持继承。
23  */
24 public class MyStack {
25     private ArrayList list; //组合
26     private String str;
27 
28     public MyStack(ArrayList list) {
29         this.list = list;
30     }
31 
32     public void push(Object obj) {
33         list.add(obj);
34     }
35 
36     public Object pop() {
37         if (isEmpty()) throw new EmptyStackException();
38         return list.remove(list.size() - 1);
39     }
40 
41     public Object peek() {
42         if (isEmpty()) throw new EmptyStackException();
43         return list.get(list.size() - 1);
44     }
45 
46     public boolean isEmpty() {
47         return list.isEmpty();
48     }
49 }

 

 1 package com.cskaoyan.exercise;
 2 
 3 public class Node {
 4     int value;
 5     Node next;
 6 
 7     public Node(int value) {
 8         this.value = value;
 9     }
10 
11     public Node(int value, Node next) {
12         this.value = value;
13         this.next = next;
14     }
15 
16     @Override
17     public String toString() {
18         return "Node{" +
19                 "value=" + value +
20                 '}';
21     }
22 }

 

 

 

 

 
JDK5的新特性
 
 1 package com.cskaoyan.jdk5;
 2 
 3 import java.util.Date;
 4 import java.util.Map;
 5 import static java.lang.Math.*;
 6 /*
 7 静态导入
 8 导包
 9     必须导入到类这一级别
10     作用:导入的类就好像定义在当前这个包下面。
11 静态导入:
12     必须导入到方法这一级别,并且必须是静态方法。
13     作用:导入的静态方法就好像定义在当前这个类中一样。
14 推荐:不要使用静态导入,可读性差
15 
16 总结:static的用法有哪些?
17 a. 静态代码块:对类进行初始化,类加载的时候执行,并且只执行一次
18 b. 静态变量:该变量是类所有,被该类的所有成员共享
19 c. 静态方法
20 d. 静态内部类
21 e. 静态导入:导入静态方法
22  */
23 public class StaticImportDemo1 {
24     public static void main(String[] args) {
25         // java.util.Date date = new java.util.Date();
26         // Date date = new Date();
27 
28         System.out.println(sqrt(1.0));
29         System.out.println(abs(-100));
30         System.out.println(max(2, 3));
31     }
32 }

 

泛型

 
泛型的引入
泛型的好处
 1 package com.cskaoyan.jdk5;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Iterator;
 5 import java.util.List;
 6 
 7 /*
 8 泛型的好处:
 9    a. 提高了程序的安全性
10    b. 将运行期遇到的问题转移到了编译期
11    c. 省去了类型强转的麻烦
12 
13 设计原则:
14     及早失败原则
15 
16 对大家的要求:
17 a. 可以利用泛型操作集合
18 b. 能够看懂别人些的泛型代码
19 
20  */
21 public class GenericDemo1 {
22     public static void main(String[] args) {
23         /*List list = new ArrayList();
24         list.add("hello");
25         list.add("world");
26         list.add("java");
27         list.add(1);
28         doSomething(list);*/
29 
30         List<String> list = new ArrayList<>();
31         list.add("hello");
32         list.add("world");
33         list.add("java");
34         // list.add(1);
35         doSomething(list);
36     }
37 
38     private static void doSomething(List list) {
39         /*for(Iterator it = list.iterator(); it.hasNext(); ) {
40             String s = (String) it.next(); // ClassCastException
41             s.toUpperCase();
42         }*/
43 
44         for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
45             String s = it.next();
46             System.out.println(s.toUpperCase());
47         }
48     }
49 }



 1 package com.cskaoyan.jdk5;
 2 /*
 3 泛型类:
 4     泛型定义在类上面
 5     作用域:整个类
 6     格式: public class 类名<泛型类型1,…>
 7 
 8 泛型的命名规则:
 9     必须满足标识符的规则
10 业界规范:
11     一般用大写字母表示
12     T:type
13     E:element
14     K:key
15     V:value
16  */
17 public class Tool2<T> { // 定义泛型, T就是泛型, 类似于形式参数
18     T obj; // 使用泛型
19 
20     public T getObj() {
21         return obj;
22     }
23 
24     public void setObj(T obj) {
25         this.obj = obj;
26     }
27 }

 

 1 package com.cskaoyan.jdk5;
 2 /*
 3 如果创建对象的时候指定类型:
 4     默认是Object类型
 5 
 6 JDK7特性:<>棱形操作符,可以利用类型推断机制。
 7  */
 8 public class GenericDemo2 {
 9     public static void main(String[] args) {
10         /*Tool2<String> tool2 = new Tool2<String>(); // String是参数化类型, 类似实参
11         tool2.setObj("hello");
12         // tool2.setObj(1);
13         String s = tool2.getObj();
14         System.out.println(s);*/
15 
16         Tool2<Object> tool1 = new Tool2();
17         tool1.setObj("hello");
18         Object obj = tool1.getObj();
19 
20         Tool2<String> tool2 = new Tool2<>();
21 
22         Tool2 tool3 = new Tool2<String>();
23 
24     }
25 }

 

 

 
泛型应用

泛型类
把泛型定义在类上
格式:public class 类名<泛型类型1,…>
注意:参数化类型必须是引用类型
 
泛型方法
把泛型定义在方法上
格式:public <泛型类型> 返回类型 方法名(泛型类型 .)
 1 package com.cskaoyan.jdk5;
 2 /*
 3 泛型方法:
 4     把泛型定义在方法上面
 5     作用域:方法签名上或者方法体内
 6     格式:public <泛型类型> 返回类型 方法名(泛型类型...)
 7 
 8 为什么泛型要定义在返回值类型的前面呢?
 9     因为返回值类型也可以是泛型,泛型必须先定义才能使用
10 
11 问题:
12     有泛型方法的类一定是泛型类吗? 不是
13 
14  */
15 public class Tool3 {
16 
17     /*public String echo(String s) {
18         return s;
19     }
20 
21     public Date echo(Date s) {
22         return s;
23     }*/
24 
25     /*public Object echo(Object obj) {
26         return obj;
27     }*/
28     // T t;
29     public <T> T echo(T t) {
30         return t;
31     }
32 
33     /*public void method(T t) {
34 
35     }*/
36     // ...
37 }
 1 package com.cskaoyan.jdk5;
 2 
 3 public class GenericDemo3 {
 4     public static void main(String[] args) {
 5         /*Tool3 tool3 = new Tool3();
 6         Object obj = tool3.echo("hello");
 7         String s = (String) obj;
 8         System.out.println(s.toUpperCase());*/
 9 
10         Tool3 tool3 = new Tool3();
11         String s = tool3.echo("hello");
12         System.out.println(s);
13     }
14 }

 

泛型接口
把泛型定义在接口上
格式:public  interface 接口名<泛型类型1…>
package com.cskaoyan.jdk5;

/*
泛型接口:
    在接口上面定义放行
    作用域:接口内
    格式:格式:public  interface 接口名<泛型类型1…>

 */
public interface Auto<T> {
    T run(T t);
}

 

 

package com.cskaoyan.jdk5;
/*
泛型接口的实现类
a. 普通类
b. 泛型类
 */
public class Car implements Auto<String> {
    @Override
    public String run(String s) {
        return null;
    }
}

 

package com.cskaoyan.jdk5;

/*public class Bus<T> implements Auto<String> {
    @Override
    public String run(String s) {
        return null;
    }
}*/

public class Bus<T> implements Auto<T> {// Bus<T>是定义泛型T, Auto<T>是使用泛型T
    @Override
    public T run(T t) {
        return null;
    }
}
 
 1 package com.cskaoyan.jdk5;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Date;
 5 import java.util.List;
 6 
 7 /*
 8 数组:
 9 问题1:String是Object的子类吗? 是
10 问题2:String[]是Object[]的子类吗? 不是
11 父类的引用变量可以指向子类的对象。
12 
13 JVM对数组进行特殊"照顾",但是这样也会引入一些问题。
14  */
15 public class GenericDemo4 {
16     public static void main(String[] args) {
17         /*String[] strs = {"hello", "world", "java"};
18         Object[] objs = strs; // JVM对数组进行特殊"照顾"
19         objs[1] = new Date(); // ArrayStoreException*/
20 
21         /*List<String> strs = new ArrayList<>();
22         strs.add("hello");
23         strs.add("world");
24         strs.add("java");
25         List<Object> objs = strs;*/
26     }
27 }

 

泛型通配符:

① 泛型通配符<?>
任意类型,如果没有明确,那么就是Object以及任意的Java类了
② ? extends E
向下限定,E及其子类
③ ? super E
向上限定,E及其父类
 1 package com.cskaoyan.jdk5;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Collection;
 5 
 6 /*
 7 泛型通配符:
 8     目的:提供类似数组的功能,但是不要引入数组中可能出现的问题。
 9 
10 ① 泛型通配符<?>
11 任意类型,如果没有明确,那么就是Object以及任意的Java类了
12 ② ? extends E
13 向下限定,E及其子类
14 ③ ? super E
15 向上限定,E及其父类
16 
17  */
18 public class GenericDemo5 {
19     public static void main(String[] args) {
20         // Collection<Object> c1 = new ArrayList<Object>();
21         /*Collection<Object> c2 = new ArrayList<Animal>();
22         Collection<Object> c3 = new ArrayList<Cat>();
23         Collection<Object> c4 = new ArrayList<Dog>();*/
24 
25         /*Collection<?> c1 = new ArrayList<Object>();
26         Collection<?> c2 = new ArrayList<Animal>();
27         Collection<?> c3 = new ArrayList<Cat>();
28         Collection<?> c4 = new ArrayList<Dog>();*/
29         // c2.add(new Dog());
30         // c2.add(new Animal());
31 
32         // Collection<? extends Animal> c1 = new ArrayList<Object>();
33        /* Collection<? extends Animal> c2 = new ArrayList<Animal>();
34         Collection<? extends Animal> c3 = new ArrayList<Cat>();
35         Collection<? extends Animal> c4 = new ArrayList<Dog>();*/
36         /*c3.add(new Animal());
37         c3.add(new Dog());
38         c3.add(new Cat());*/
39 
40         Collection<? super Animal> c1 = new ArrayList<Object>();
41         Collection<? super Animal> c2 = new ArrayList<Animal>();
42         // Collection<? super Animal > c3 = new ArrayList<Cat>();
43         // Collection<? super Animal> c4 = new ArrayList<Dog>();
44         c2.add(new Animal());
45         c2.add(new Dog());
46         c2.add(new Cat());
47         // c2.add(new Object());
48     }
49 }
50 
51 class Animal {
52 }
53 
54 class Dog extends Animal {
55 }
56 
57 class Cat extends Animal {
58 }

 

 

posted @ 2020-05-15 01:25  dust--  阅读(194)  评论(0编辑  收藏  举报