容器

容器

1. 容器概述

  • 数组的缺点

  • 容器体系概述

2. Collection 体系

  • 特点

  • List

    • ArrayList

    • LinkedList

    • Vector

      • Stack

  • Set

    • HashSet

      • LinkedHashSet

    • TreeSet

package com.qf.collection;
/**
* java 的集合框架。collection framework。
* 主要学习的内容:
* 各种不同特点的容器。
*
* 数组的缺点:
* 1:数组定长。不能自动扩容。
* 2:数组的元素的类型必须是唯一的。
* 3:数组插入删除效率比较低。
* 4:没有封装。
*
* 大概学习三类容器:
* 1:序列 Sequence(List)。元素是有序的(有序号,有下标)元素不唯一。
* 2:集 Set 元素的特点:无序,唯一。
* 3:映射 Map。元素的特点:一个元素由一对数据构成。一个称为键key,一个称为值value。(key+value-->Node)Node Map 中的元素。
* 例子:身份证号key,人的信息:value。
* key 的特点:无序唯一。
* value 特点:无序,不唯一。
*
*
* 集合框架部分的内容都在 java.util 包下。
*
* 1:Collection:
* 1:是 java 集合框架部分的顶级接口。
* 2:Collection 容器的特点:
* 对实现的子类的要求:元素可以【不唯一】,可以【无序】。子类实现的时候可以添加更加严苛的功能。
* Collection接口中定义的抽象方法,没有提供根据下标添加元素的方法。添加的方法没有要求,重复的内容不能添加。
*
* 2:java.util.Collection 有两个主要的子接口。
* --- List
* 在Collection的基础上,增加了根据下标处理元素的方法。元素的特点:有序(添加的顺序(添加的序号)),不唯一。
* --- Set
* 在Collection的基础上,增加去重的要求,元素的特点:无序,唯一的。
*
* 3:java.util.List
* --- 接口。它有两个重要的实现的子类。
* ---ArrayList
* ---LinkedList
*
*/

3. List 接口 ***

4. ArrayList ***

  • 基本使用

    • null

    • package com.qf.collection;

      import java.util.ArrayList;

      /**
      * java.util.ArrayList 介绍: 1:容器底层使用的数据结构,底层使用的数据结构是数组。 transient Object[]
      * elementData; 2:相比于数组的优点: 1:有封装了。 2:自动扩容。
      * 初始容量为0,第一次添加元素容量为10.需要扩容的时候,每次扩容为现有容量的50%。 3:元素类型多样。 缺点:数组剩下的缺点。
      *
      * 3:ArrayList 的特点: 1:底层使用Object[] 数组作为数据结构。可以将ArrayList 容器理解为 有封装数组的。
      * 2:扩容规则:初始容量为0,第一次添加元素容量为10.需要扩容的时候,每次扩容为现有容量的50%。 3:元素有序,不唯一,可以有多个null.
      * 4:元素类型任意。 5: 如果想根据内容删除对象,那么需要重写 equals 方法。
      * 5:private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
      * 容器的最大容量。如果超过容量,就添加不成功。
      *
      */
      public class ArrayListTest {

      @SuppressWarnings({ "unchecked", "rawtypes" })
      public static void main(String[] args) {
      // 基本使用。
      ArrayList list = new ArrayList();
      // 添加元素。尾部追加。
      list.add("abc");
      Student tom = new Student("tom");
      list.add(tom);
      list.add(1);
      list.add(1);
      list.add(true);

      list.add(null);
      list.add(null);
      //
      // for (int i = 0; i < 20; i++) {
      // list.add(i);
      // }
      // 插入功能
      list.add(list.indexOf(1), 'A');
      // 将容器中的所有的内容追加尾部
      // list.addAll(c)
      // 删除。
      list.remove(list.indexOf(true));
      list.remove(new Student("tom"));
      // list.remove(100);
      list.remove(Integer.valueOf(1));
      // list.removeAll(c)
      // 修改
      list.set(list.indexOf('A'), 'a');
      // 获取
      System.out.println(list.get(2));
      //
      // 其他的方法
      // list.clear();
      // list.contains(o)
      // list.indexOf(o) 返回下标
      // list.lastIndexOf(o)
      // list.isEmpty()
      // list.sort(c);
      // list.toArray()
      // list.size() 元素个数。
      System.out.println(list);
      }
      }

      class Student {
      private String name;

      public Student(String name) {
      super();
      this.name = name;
      }

      @Override
      public String toString() {
      return "学生:" + name;
      }

      @Override
      public boolean equals(Object obj) {
      if (this == obj)
      return true;
      if (obj == null)
      return false;
      if (getClass() != obj.getClass())
      return false;
      Student other = (Student) obj;
      if (name == null) {
      if (other.name != null)
      return false;
      } else if (!name.equals(other.name))
      return false;
      return true;
      }
      }
  • 遍历方式

  • package com.qf.collection;

    import java.util.ArrayList;
    import java.util.Comparator;
    import java.util.Iterator;

    import com.qf.util.MyUtil;

    /**
    * ArrayList 遍历:
    *
    * 迭代器遍历: Iterator 接口类型中定义了三个方法: 1:hasNext(). 被遍历的元素中,还有没有下一个等待遍历的元素。返回boolean。
    * 2:next().返回下一个等待遍历的元素。 3:remove(): 删除刚刚被遍历的元素。刚刚next 方法返回的元素。
    *
    */
    public class ArrayListTest2 {

    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static void main(String[] args) {
    ArrayList list = new ArrayList(20);
    // 添加内容
    for (int i = 0; i < 20; i++) {
    String str = MyUtil.randomString(MyUtil.random(2, 20));
    list.add(str);
    }

    // 遍历方式。
    // 基本的for 循环(经常使用,效率高)
    final int size = list.size();
    for (int i = 0; i < size; i++) {
    Object obj = list.get(i);
    // 如果要使用元素的实际类型中的特殊的方法,那么需要向下强制转换。
    System.out.println(obj);
    }
    System.out.println();

    // 使用 增强的for 循环 for-each 底层使用迭代器实现的。
    for (Object o : list) {
    System.out.println(o);
    }

    System.out.println();
    // 使用迭代器。容器部分的标准遍历方式。
    // 获取当前容器上的迭代器对象。
    Iterator iterator = list.iterator();
    // iterator
    while (iterator.hasNext()) {
    Object next = iterator.next();
    String s = (String) next;
    // 将长度大于10 的删除。
    if (s.length() > 10)
    iterator.remove();
    // System.out.println(next);
    }

    System.out.println(list);

    // 对list 排序。排序的规则是字符串的长度。根据长度降序排序。
    list.sort(new Comparator() {
    @Override
    public int compare(Object o1, Object o2) {
    String s1 = (String) o1;
    String s2 = (String) o2;
    return s2.length() - s1.length();
    }
    });
    System.out.println(list);
    }
    }
  •  

  • 特点

    • 底层使用Object[] 数组作为数据结构保存元素。

    • 初识容量默认是0,第一次添加容量扩容到10. 如果需要扩容,每次扩容到现有容量的1.5倍。

    • 通过索引访问元素的效率很高。通过下标遍历元素的效率很高。

    • 缺点:插入删除元素的效率比较低。

    • 总结:ArrayList 就是一个 带封装的 数组的容器实现类。使用的场景遍历很多,增删比较少。

  • 源码分析

5. LinkedList ***

  • 基本使用

  • 特点

  • 源码分析

  • ArrayList 和 LinkedList 的比较

  • package com.qf.collection;

    import java.util.ArrayList;
    import java.util.LinkedList;
    import java.util.List;
    /**
    * transient int size = 0;元素个数。
    * transient Node<E> first;头结点的引用。
       transient Node<E> last;尾结点的引用
       节点内部类。
    * private static class Node<E> {
           E item;
           Node<E> next;
           Node<E> prev;

           Node(Node<E> prev, E element, Node<E> next) {
               this.item = element;
               this.next = next;
               this.prev = prev;
           }
       }
       
      总结:
      LinkedList 和 ArrayList 相比的优缺点
      1:插入元素删除元素。LinkedList效率相对要高。
      2:遍历元素,ArrayList 效率要高的多。
      3:LinkedList 不需要初始容量。
      4:LinkedList 每次都需要将数据封装成一个Node。创建一个新对象。缺点。
      5:LinkedList 的元素是不连续,ArrayList 数组的元素内存是连续的。
     
       效率测试结论:
       1:添加 ArrayList good
       2:元素数量比较少,效率查不到。元素数量比价多,LinkedList效率更优。尤其是头部插入删除数据。
       3: 遍历元素的效率,ArrayList good。
       4:总结: ArrayList 是一个性能优良的容器类。
       
    */
    public class LinkedListTest {

    public static void main(String[] args) {
    testIterator(50000);
    }

    private static void testAdd(int count) {
    long start = System.currentTimeMillis();
    List list = new LinkedList();
    for(int i=0;i<count;i++){
    list.add(i);
    }
    long cost = System.currentTimeMillis() - start;
    System.out.println(cost);
    }

    private static void testInsert(int count) {
    long start = System.currentTimeMillis();
    List list = new ArrayList();
    for(int i=0;i<count;i++){
    list.add(0,i);
    }
    long cost = System.currentTimeMillis() - start;
    System.out.println(cost);
    }

    private static void testIterator(int count) {

    List list = new LinkedList();
    for(int i=0;i<count;i++){
    list.add(i);
    }

    long start = System.currentTimeMillis();
    for(int i=0;i<list.size();i++){
    list.get(i);
    }
    long cost = System.currentTimeMillis() - start;
    System.out.println(cost);
      }
    }
  •  

6. Vector

  • package com.qf.collection;

    import java.util.Enumeration;
    import java.util.Vector;

    /**
    * Vector 向量。
    * 1:是 jdk 最早的一批容器类。jdk1.0 。ArrayList 是jdk1.2出现的。
    * 2:早期使用 Vector 作为 ArrayList 的替代使用。
    * 3:特点:
    * 1:底层使用数组实现。
    * 2:扩容规则:每次扩容到现有容量的2倍。比较浪费内存。
    * 3:在没有实现List接口之前,有自己特殊的一套对元素操作的方法。这些方法比较复杂。方法名字很长。
    * 4:有自己特殊的遍历方式。使用枚举器遍历。
    * 5:【Vector是一个线程安全的容器类。效率比较低。ArrayList 是一个线程非安全的容器类,效率高。】
    */
    public class VectorTest {

    public static void main(String[] args) {
    Vector vector = new Vector();

    // vector.addElement(obj);
    // vector.removeElementAt(index);
    // vector.setElementAt(obj, index);

    Enumeration elements = vector.elements();
    while(elements.hasMoreElements()){
    System.out.println(elements.nextElement());
    }
    }
    }
  •  

7. Stack

  • Vector的子类,在Vector 的基础上增加了对栈的操作。主要是push 和 pop。

8. Queue

  • 接口 描述的队列这种数据结构应该遵守的功能列表。

  • offer 优于 add

  • poll 优于 remove

9. Deque

  • 参看 Deque 接口

10. 泛型

  • jdk 1.5

10.1 泛型类

  • 语法

  • 使用泛型类型定义成员

  • 使用泛型类型成员

10.2 泛型接口

  • 实现泛型接口时确定泛型类型

  • 创建实现类对象的时候确定泛型类型

10.3 泛型方法

  • 返回类型前<T>

10.4 注意事项

  • 泛型类中不能使用泛型声明静态属性

  • 泛型类型不能 new T()

    • 因为构造方法不确定是否可以访问。

  • 泛型类型不能 new T[100],只能声明。

    • 因为T一旦确定,也可能给数组中加入其它的类型。

  • 类中的方法的参数如果是用了泛型,那么重载的方法的参数个数不能相同。

  • 使用不同的泛型类型创建的泛型类对象之间不能相互赋值。

  • 方法实现打印任意的 ArrayList 的多种解决方案。

    • 泛型方法

    • <?>

  • 泛型的擦除

    • 泛化和非泛化的代码编译之后是一致的。

10.5 泛型限制

  • <? extends XXX> 泛型的上限

  • <? super XXX> 泛型的下限

  • package com.qf.generic;

    import java.util.ArrayList;

    /**
    * 泛型:也称为参数化类型。generic type
    *
    * 初期主要使用在 容器类中。
    * 1:限定了容器中的元素的类型。
    * 2:避免过多的使用前置类型转换。
    *
    * 泛型的主要使用方式:
    * 1:泛型类
    * 2:泛型接口
    * 3:泛型方法。
    *
    * 泛型(未知的一种类类型)。
    * E T K V
    *
    * 1:泛型类。
    * 泛型类的泛型的类型是在创建反类型对象的时候指定的。
    * 2:泛型接口
    * 泛型接口的第一种用法,实现接口的时候指定泛型的类型。
    * 泛型接口的第二种使用方式:实现泛型接口的时候不指定泛型的类型。实现类必须也得是泛型类。
    * 3:泛型方法
    * 泛型方法,类型的确定是在方法的调用的时候。
    *
    * 4:泛型的上限和下限
    * ArrayList<? extends Father> list 设置上限。
    * ArrayList<? super Father> list 设置下限
    *
    * 5:泛型的擦除:
    * class 文件中是没有任何的泛型信息的。
    * 运行的时候jvm是不会进行泛型的类型检查的。
    * 为了实现有泛型的代码和没有泛型的代码的兼容性。
    * 有泛型的代码和没泛型的代码编译之后应该是相同的。
    *
    * 结论:泛型是编译期的问题。
    *
    *
    */
    public class TestGeneric {

    public static void main(String[] args) {
    MyStack<String> myStack = new MyStack<String>("abc");

    B<String,Integer> b = new B<>();

    ArrayList<String> list = new ArrayList<>();
    list.add("123");

    test1(list);

    ArrayList<Son> list1 = new ArrayList<>();

    test3(list1);
    }

    // 遍历一个ArrayList 的方法。泛型是任意类型。 ? 代表了任意类型。
    public static void test(ArrayList<?> list){

    }

    // 泛型方法,类型的确定是在方法的调用的时候。 T只能当Object 使用。
    public static <T> void test1(ArrayList<T> list){

    }
    // 泛型方法,
    public static <T> void test2(T t){
    // t 只能当Object 使用。
    }

    // 规定了泛型的上限。只能是 Father 或者时候 Father 子类类型。
    public static void test3(ArrayList<? extends Father> list){
    }

    // 规定了泛型的下限。只能是 Father 或者时候 Father 父类类型。
    public static void test4(ArrayList<? super Father> list){
    }

    }

    class Father{

    }
    class Son extends Father{

    }

    //E 代表了 栈中的元素的类型。
    class MyStack<E>{
    // 不能确定 E 类型的构造方法能否使用。
    private E e ;//= new E();
    public MyStack(E e) {
    super();
    this.e = e;
    }
    public E get(){
    return e;
    }
    }

    interface MyInterface<K,V>{
    K getK(K k);
    V getV(V v);
    }

    //泛型接口的第一种用法,实现接口的时候指定泛型的类型。
    class A implements MyInterface<String,Integer>{
    @Override
    public String getK(String k) {
    return null;
    }
    @Override
    public Integer getV(Integer v) {
    return null;
    }
    }
    class Student implements Comparable<Student>{
    @Override
    public int compareTo(Student o) {
    return 0;
    }
    }
    //泛型接口的第二种使用方式:实现泛型接口的时候不指定泛型的类型。实现类必须也得是泛型类。
    class B<K,V> implements MyInterface<K,V>{
    @Override
    public K getK(K k) {
    // TODO Auto-generated method stub
    return null;
    }
    @Override
    public V getV(V v) {
    // TODO Auto-generated method stub
    return null;
    }
    }
  •  

10. Collections 工具类

  • 添加元素

  • 排序

  • 复制

  • 元素出现的个数

  • 翻转

  • 打乱顺序

  • Arrays.asList

  • list.toArray

11. Set ***

  • 特点

  • 方法全部继承自父接口

11.1 HashSet ***

  • 基本使用

    • null

  • 底层实现原理:数组+链表

  • LinkedHashSet

    • 双向链表

11.2 TreeSet (**)

  • 基于排序实现不重复

  • 元素需要实现内部比较器接口 java.lang.Comparable 或者指定外部比较器。

  • 图示

  • 先序遍历(先根)

  • 中序遍历(中根)

  • 后序遍历(后根)

  • package com.qf.set;

    import java.util.Comparator;
    import java.util.TreeSet;

    import com.qf.util.MyUtil;

    /**
    * TreeSet的核心用法
    * 对若干个学生数据根据年龄的降序排序,年龄相同,根据名字的升序排序。
    *
    * 1:如果使用默认无参的 TreeSet的构造方法,那么要求,所有的元素类型,需要实现内部比较器接口。Comparable.
    * 2:使用外部比较器,需要有参的构造方法。
    *
    * 总结:
    * 1:使用TreeSet 要么元素实现内部比较器接口。要么指定 TreeSet对象的外部比较器对象。
    * 2:如果指定了外部比较器,那么内部比较器失效。
    * 3:如果比较添加的过程中,返回0,那么准备添加的元素失败,去重。根据比较 大小相等 的结果决定是否去重。
    * 4:TreeSet 效率适中,根据内容查找元素,比List快,比 HashSet 要慢。
    */
    public class TestTreeSet1 {

    public static void main(String[] args) {
    test1();
    }
    // 使用外部比较器实现年龄的升序的排序。
    private static void test1() {
    TreeSet<Stu> stus = new TreeSet<>(new Comparator<Stu>(){
    @Override
    public int compare(Stu o1, Stu o2) {
    // 根据年龄的升序排序,年龄相同的就去重了。
    return o1.getAge()-o2.getAge();
    }
    });
    for (int i = 0; i < 10; i++) {
    int age = MyUtil.random(16, 20);
    String name = Character.toString((char)MyUtil.random('A', 'F'));
    stus.add(new Stu(name,age));
    }
    System.out.println(stus);
    }
    // 对若干个学生数据根据年龄的降序排序,年龄相同,根据名字的升序排序。
    private static void test() {
    TreeSet<Stu> stus = new TreeSet<>();
    for (int i = 0; i < 10; i++) {
    int age = MyUtil.random(16, 20);
    String name = Character.toString((char)MyUtil.random('A', 'F'));
    stus.add(new Stu(name,age));
    }

    System.out.println(stus);
    }





    }
    class Stu implements Comparable<Stu>{
    private String name;
    private int age;

    public Stu() {
    }

    public Stu(String name, int age) {
    super();
    this.name = name;
    this.age = age;
    }

    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }

    public int getAge() {
    return age;
    }

    public void setAge(int age) {
    this.age = age;
    }

    @Override
    public String toString() {
    return "Stu [name=" + name + ", age=" + age + "]\n";
    }

    @Override
    public int compareTo(Stu o) {
    System.out.println("compare");
    // 根据年龄的降序和名字的升序排序。这两个都一样的就去重了。
    int result = o.age - this.age;
    if(result == 0){
    return this.name.compareTo(o.name);
    }
    return result;
    }
    }
  •  

12 Map

  • 概述

  • HashMap

    • LInkedHashMap

  • TreeMap

  • HashTable

12.1 HashMap ***

  • jdk1.2 、线程非安全、快、key 和 value 允许 null

  • 基本使用

  • package com.qf.map;

    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    import java.util.Set;

    /**
    * Map 概述 1:是一个顶级接口。描述了映射容器应该具有的功能。
    * 2:映射,是一对数据(key+value)。key:通常是比较简单的数据。value通常是比较负责的数据。 key+value
    * 构成了一个Node对象。就是 映射中的数据。 往往是通过key 来操作 value的。
    *
    * 3:Map 接口有两个重要的子类 HashMap TreeMap
    *
    * 4: java.uitl.HashMap 1:底层使用的数据结构是哈希表。 2:HashMap 中保存的是Node,一个Node 由 key+value
    * 构成。 通过计算 key 对象的哈希码来决定整个Node的位置。 3:hashMap 中的元素 Node 的key 的特点? 【key
    * 是无序的,唯一的(业务需求)】 HashMap 中的Node 的key的特点就是 HashSet 中元素的特点。 要求:HashMap 中的key
    * 要求【重写 hashCode 和equals】。 【value 的特点:无序,不唯一(Collection)】 4:Node 中的key
    * 可以是null,只能有一个null。 5:Node 中的value 可以是null,可以有多个null. 6: 一般情况下使用 String 和
    * Integer 作为key。 这两个类都重写了hashCode 和 equals。
    *
    * 7: 后添加的内容,如果key 有相同的,那么后添加的会覆盖前面的value。 8: 通过key 可以删除整个Node。
    *
    */
    public class TestMap {

    public static void main(String[] args) {
    //
    HashMap<String, String> map = new HashMap<>();
    // 添加
    map.put("cn", "China");
    map.put("jp", "Japan");
    map.put("usa", "America");
    map.put("uk", "England");
    map.put("fr", "France");
    map.put("uk", "United Kindom");

    // 删除 返回的是删除的key对应的value。
    String str = map.remove("jp");
    System.out.println(str);

    // 修改,覆盖。
    map.put("usa", null);

    // 获取
    String value1 = map.get("cn");
    System.out.println(value1);

    // 测试特点
    map.put(null, null);
    map.put(null, null);

    // 其他的方法
    // map.clear();
    // map.containsKey(key)
    // map.isEmpty()
    // map.size()

    System.out.println(map);

    // 遍历map
    // 1:获取所有的key。以Set 形式获取到。遍历所有的key,通过key获取到value。
    Set<String> keys = map.keySet();
    Iterator<String> iterator = keys.iterator();
    while (iterator.hasNext()) {
    String key = iterator.next();
    String value = map.get(key);
    System.out.println(key + "-->" + value);
    }

    // 2:获取所有的value。但是不能通过value获取到对应的key。
    Collection<String> values = map.values();
    Iterator<String> iterator2 = values.iterator();
    while (iterator2.hasNext()) {
    String value = iterator2.next();
    System.out.println(value);
    }

    // 3: 获取到所有的键值对数据。一个键值对数据被封装成了一个Entry.以Set 形式返回,里面存储的是Entry。
    Set<Entry<String, String>> entrySet = map.entrySet();
    Iterator<Entry<String, String>> iterator3 = entrySet.iterator();
    while (iterator3.hasNext()) {
    Map.Entry<String, String> entry = iterator3.next();
    String key = entry.getKey();
    String value = entry.getValue();
    System.out.println(key + "-->" + value);
    }
    }
    }
  •  

  • 查看 HashSet 源码 和 HashMap 源码

12.2 TreeMap

  • 根据 key 进行排序

12.3 Hashtable

  • jdk1.0 线程安全,效率低,不允许 key 和 value 是null。

13. Properties

  • Hashtable 的子类,没有泛型,要求key 和 value 都是 String,通常用于配置文件

14. 总结

  • Iterable

    • Collection

      • List

        • ArrayList

        • LinkedList

        • Vector

          • Stack

      • Set

        • HashSet

          • LinkedHashSet

        • TreeSet

  • Map

    • HashMap

      • LinkedHashMap

    • TreeMap

    • Hashtable

other

package com.qf.map;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
 * ListIterator
 * 	1: Iterator 接口的子接口。
 * 	2:ListIterator 迭代器是专门用于遍历 List 子类对象的。
 * 	3:Iterator 迭代器 只能实现 单向 单次的遍历。
 * 	4:ListIterator 迭代器可以实现双向,多次遍历。
 *
 * IdentityHashMap
 * 	1:map 中,可以保存内容相同的key ,但是前提,内容相同的key 是不同的key对象。
 * 
 * WeakHashMap
 * 	容器中保存的对象,是弱引用保存的。关键的时候可以被GC 清除掉。
 * 
 * Collections
 * 	针对容器的一个工具类。
 * 	主要的功能:
 * 		搜索
 * 		复制
 * 		打乱顺序
 * 		翻转
 * 		最大值
 * 		最小值
 */
public class TestOther {

	public static void main(String[] args) {
		test();
	}

	private static void test() {
		List<String> list = new ArrayList<String>();
		
		list.add("a");
		list.add("b");
		list.add("c");
		list.add("d");
		list.add("e");
		
//		从前往后遍历。
		ListIterator<String> iterator = list.listIterator();
		while(iterator.hasNext()){
			String next = iterator.next();
			System.out.println(next);
		}
//		iterator.add(e);
//		iterator.hasPrevious()
//		iterator.previous();
//		从后往前遍历
		while(iterator.hasPrevious()){
			System.out.println(iterator.previous());
		}
		
//		死循环
		while(iterator.hasNext()){
			iterator.next();
			iterator.previous();
		}
		
		System.out.println(1);
	}

}

 

1. 自定义容器类MyStack

package com.qf.test;

import java.util.Arrays;

/**
 * 自定义容器。栈。
 * 底层使用数组作为栈的容器。
 */
public class MyStack<E> {
	//	初始容量。
	private final static int DEFAULT_SIZE = 6;
	private final static int MAX_SIZE = 20;

	//	用于保存元素的数组。
	private Object[] elementData;

	//	定义栈顶指针。代表了要存入数据的索引,还代表了元素的个数。
	private int index;

	public MyStack() {
		elementData = new Object[DEFAULT_SIZE];
		index = 0;
	}

	//	压栈操作。
	public boolean push(E e)throws Exception{
		//		特殊情况 满了。
		if(isFull()){
			throw new Exception("栈满!压栈失败!");
		}

		//		判断是否需要扩容。
		grow();

		//		常规情况
		elementData[index] = e;
		index ++;
		return true;
	}
	
//	获取栈顶元素。
	public E pop()throws Exception{
//		特殊情况。
		if(isEmpty()){
			throw new Exception("感觉身体被掏空!");
		}
		
//		常规情况
		index--;
		E e = (E)elementData[index];
//		避免内存泄漏。
		elementData[index] = null;
		return e;
	}

//	栈是否满了,不能扩容了。
	private boolean isFull(){
		return index == MAX_SIZE;
	}
	
//	判断栈是否为空。
	public boolean isEmpty(){
		return index == 0;
	}

	//	判断扩容和扩容的实现。
	private void grow(){
		//		需要扩容。扩容规则,每次是现有容量的1.5倍。
		if(elementData.length == index){
			int newSize = index + index / 2;
			if(newSize > MAX_SIZE)
				newSize = MAX_SIZE;

			//创建一个新的数组,将原数组的内容复制过来。elementData 指向新数组。
			elementData = Arrays.copyOf(elementData, newSize);
		}
	}
	
	public void clear(){
//		清空所有的元素,并指向栈底
		for (int i = 0; i < index; i++) {
			elementData[i] = null;
		}
		index = 0;
	}
	
//	获取元素个数。
	public int size(){
		return index;
	}
	
	public String toString(){
//		将elementData 中有效数据复制到一个新数组中,返回。
		return Arrays.toString(Arrays.copyOf(elementData, index));
	}
}
 
posted @   ITboy搬砖人  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示