热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java编程思想第四版第十一章总结

1.容器类被分为两类:Collection和MapCollection是一个接口:包括:List接口:ArrayList:按照被插入顺序保存元素,查询快,增删改慢Li

1. 容器类被分为两类:Collection和Map

  • Collection是一个接口:包括:
    • List接口:
      • ArrayList:按照被插入顺序保存元素, 查询快, 增删改慢
      • LinkedList:按照被插入顺序保存元素, 增删改块,查询慢。
    • Set接口:元素不能重复
      • HashSet:已相当复杂的方式来存储元素,这种技术是最快的获取元素的方式
      • TreeSet:按照结果的升序保存元素
        • 可以自行执行排序方式。默认是按照字典顺序排序。如果想按照字母顺序排序,可以向TreeSet构造器中传入String。CASE_INSENTIVE_ORDER.
      • LinkedHashSet:按照添加顺序保存元素
    • Queue接口
  • Map接口
    • HashMap:已相当复杂的方式来存储元素(散列函数),这种技术是最快的获取元素的方式
    • TreeMap:按照比较结果的升序保存,元素存储在红黑树数据结构。
    • LinkedHashMap:按照添加顺序保存元素。

2. 定义集合的时候,使用向上转型,是一个好的习惯

  List list = new ArrayList();

  注意:ArrayList已经被向上转型为List,这样做的好处是,如果你想使用其他List的实现类也是可以的。缺点是,在ArrayList中有一些额外的方法,不包含在List中,如果需要调用这些方法,还需要使用ArrayList来定义。

3. Collection集合的使用

  • 添加一组元素
    package net.mindview.holding;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.Collections;
    import java.util.List;
    
    public class AddingGroups {
    
        public static void main(String[] args) {
            //1. Collection集合,有一个构造方法, 可以接受一个集合作为参数, 将数组内容直接作为Collections的内容.
            
            Collection collection = new ArrayList(Arrays.asList(1,2,3,4,5));
            Integer[] moreInts = {6, 7, 8, 9, 10};
            //2. 集合有一种方法,添加一个数组为它的元素. 这种方法没有Collections.addAll高效
            //原因: 第一种方式首先要初始化,然后将数组转换为集合后, 赋值. 第二种方法方法直接赋值,所以更高效
            collection.addAll(Arrays.asList(moreInts));
            
            //定义一个集合, 使用Collections.addAll()方式添加元素是一种推荐的方式.效率高
            Collections.addAll(collection, 11,12,13,14,15);
            Collections.addAll(collection, moreInts);
            
            //将数组直接转换为list,有两点需要说明:1. 大小固定, 不能添加元素,删除元素, 可以修改. 2. 局限性,下面的代码说明.
            List list = Arrays.asList(16,17,18,19,20);
            list.set(1, 99);                
        }
    }

    相信看上面的注释, 下面说一说Arrays.asList()的局限性.

    package net.mindview.holding;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.List;
    
    /**
     * 这里说的是一个间接继承和直接继承的问题
     */
    class Snow {}
    class Powder extends Snow{}
    class Light extends Powder{}
    class Heavy extends Powder{}
    class Crusty extends Snow{}
    class Slush extends Snow{}
    public class AsListInference {
    
        public static void main(String[] args) {
            //1. 下面的定义可以通过, 他们都继承自Snow
            List snow1 = Arrays.asList(new Powder(), new Crusty(), new Slush());
            
            //2. 下面的定义不能通过, 因为他们都是间接继承自snow.而非直接
            //List snow2 = Arrays.asList(new Light(), new Heavy());
            
            //3. 上面的方式编译不通过,但是下面的却可以.为什么呢? 因为他从第一个元素了解到了此目标类型是snow
            List snow3 = new ArrayList();
            Collections.addAll(snow3, new Light(), new Heavy());
            
            //4. 方法2可以通过显示类型参数说明,来明确指出转换的类型
            List snow4 = Arrays.asList(new Light(), new Heavy());
        }
    
    }

     

  • 容器的打印
    • 数组的打印,使用Arrays.toString(数组名);
      public static void main(String[] args) {
          String[]  str = new String[5];
          System.out.println(str);
          System.out.println(Arrays.toString(str));
      }

       

    • 容器的打印, 直接打印容器名, 无需任何帮助.

 4. Stack

  栈: 先进后出(LIFO),有时栈也被称为叠加栈, 因为最后“压入”的,最先弹出。

  LinkedList具有能够直接实现栈的所有功能的方法。因此可以直接将LinkedList作为栈直接使用。

  也就是说LinkedList中有方法是先进后出的。

package net.mindview.holding;

import java.util.LinkedList;

/**
 * 模拟栈
 */
public class Stack {
    private LinkedList storage = new LinkedList();
    
    //进入
    public void push(T v){
        storage.addFirst(v);
    }
    
    public T peek(){
        return storage.removeFirst();
    }
    
    //取出
    public T pool(){
        return storage.removeFirst();
    }
    
    public boolean empty(){
        return storage.isEmpty();
    }
    
    public String toString(){
        return storage.toString();
    }

}

 

package net.mindview.holding;

public class StackTest {
    
    public static void main(String[] args) {
        Stack stack = new Stack();
        for(String s:"this is my dog!".split(" ")){
            stack.push(s);
        }
        
        if(!stack.empty()){
            System.out.println(stack.peek());
            System.out.println(stack.pop()+" ");
            System.out.println(stack.pop()+" ");
            System.out.println(stack.peek());
        }
    }
}

运行结果:

dog!
dog!
my
is

  通过这个案例: 可以看出, 所谓的先进后出,指的是, add最后进来的, remove时最先出去. 跟排序没有任何关系.

 5. Queue 队列

  队列是一个典型的先进先出的容器. 即从容器的一段放入,从另一端取出. 并且事物放入容器的顺序与取出的顺序是相同的。

  LinkedList提供了方法以支持队列的行为。并且它实现了Queue接口。因此LinkedList可以用作Queue的一种实现。通过将LinkedList向上转型为Queue,下面展示了Queue的用法。

package net.mindview.holding;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

public class QueueDemo {

    public static void print(Queue queue){
        //从队列中取元素--先放进去的,先取出来
        while(queue.peek() != null){
            //从队列中删除一个元素
            System.out.print(queue.remove() + " ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        Queue queue = new LinkedList();
        Random rand = new Random(47);
        for(int i=0; i<10; i++){
            //向队列里放入元素
            queue.offer(rand.nextInt(i+10));
        }
        print(queue);
        
        Queue qc = new LinkedList();
        for(char c:"Brontosaurus".toCharArray()){
            //向队列里放入元素
            qc.offer(c);
        }
        print(qc);
    }
}
8 1 1 1 5 14 3 1 0 1 
B r o n t o s a u r u s 

 

  • offer()方法,:在允许的情况下,将一个元素插入到队尾。或者返回false。
  • peek()和element():在不移除的情况下返回对头。但是peek方法在队列为空时,返回null。而element()会抛出NoSuchElementException异常。
  • poll()和remove():将移除并返回队头。poll在队列为空时返回null,remove在队列为空是抛出NoSuchElementException异常。

这里想Queue中放入元素使用的时offer,取出元素使用的时peek,删除元素使用的remove。先放进去的先取出来。

  我们再说到Stack时,看到LinkedList可以实现Stack先进后出。看到队列的Queue的时候, 又说LinkedList可以实现Queue先进先出。这是怎么回事呢?来看看API,原来是这么回事

6. PriorityQueue:优先级队列

  优先级队列声明,下一个弹出元素是最需要的元素。也就是说是优先级最高的元素。当你使用offer方法来出入一个对象时,这个对象会在队列中被排序。默认的顺序将使用对象在队列中的自然顺序。但你也可以通过自己的Comparator来修改这个顺序。

  PriorityQueue可以确保当你调用peek(), poll(), remove()方法时, 获取元素将是队列中优先级最高的元素.

package net.mindview.holding;

import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Random;
import java.util.Set;

public class PriorityQueueDemo {

    public static void main(String[] args) {
        /*
         * 对于数字而言, 最小的数字优先级最高
         */
        PriorityQueue priorityQueue = new PriorityQueue();
        Random rand = new Random(47);
        for(int i=0;i<10;i++){
            priorityQueue.offer(rand.nextInt(i+10));
        }
        QueueDemo.print(priorityQueue);
        /*
         * 将一个list集合中的元素放入队列
         * 并且使用自定的排序方式排序
         */
        List ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2,
                3, 9, 14, 18, 21, 23, 25);
        priorityQueue = new PriorityQueue(ints);
        QueueDemo.print(priorityQueue);
        //提供了一个构造器, 使用自定义的排序方法.第二个参数是新的排序方法,继承了Comparator类.
        priorityQueue = new PriorityQueue(ints.size(), Collections.reverseOrder());
        priorityQueue.addAll(ints);
        QueueDemo.print(priorityQueue);
        
        /*
         * 字符串集合放入到优先级队列
         */
        String fact = "EDUCATION SHOULD ESCHEW OBFUSACTION";
        List strings = Arrays.asList(fact.split(" "));
        PriorityQueue stringPQ = new PriorityQueue(strings);
        QueueDemo.print(stringPQ);
        
        /*
         * 使用set存储不重复的字符集合
         * 最小的值有最高的优先级. 空格的优先级比字母高
         */
        Set charSet = new HashSet();
        for(char c: fact.toCharArray()){
            charSet.add(c);
        }
        PriorityQueue charPQ = new PriorityQueue(charSet);
        QueueDemo.print(charPQ);
    }
}

运行结果:

0 1 1 1 1 1 3 5 8 14 
1 1 2 3 3 9 9 14 14 18 18 20 21 22 23 25 25 
25 25 23 22 21 20 18 18 14 14 9 9 3 3 2 1 1 
EDUCATION ESCHEW OBFUSACTION SHOULD 
  A B C D E F H I L N O S T U W 

 

  1. 数字越小,优先级越高

  2. 空格的优先级比字母高

  3. 字符串,字符都可转换为对应的数字处理.

7. Iterator 

  java中, 用迭代器Iterator而不是集合Collection来表示集合间的共性。但是, 实现了Collection就意味着需要提供Iterator()方法。 

  (未完,待完善)

8. Foreach和迭代器

  Iterable接口:该接口包含一个能够产生Iterator的iterator()方法,并且Iterable接口被foreach用来在序列中移动。因此,如果你创建的类实现了Iterable接口,都可以将它用于foreach语句中:

package net.mindview.holding;

import java.util.Iterator;

/**
 * Iterable 接口包含一个能够产生Iterator的iterator()方法. 并且Iterable接口被用来在foreach用来在序列中移动。
 * 因此,如果你创建了任何实现Iterable的类,都可以将其用于foreach语句中。
 * @author samsung
 *
 */
public class IterableClass implements Iterable{
    protected String[] words = ("And that is how we know the Earth to be banana-shaped.").split(" ");
    
    @Override
    public Iterator iterator() {
        // TODO Auto-generated method stub
        return new Iterator(){
            private int index = 0;
            
            @Override
            public boolean hasNext() {
                return index < words.length;
            }

            @Override
            public String next() {
                return words[index++];
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }
    
    public static void main(String[] args) {
        //只要这个类实现了Iterable,就可以使用foreach语句遍历
        for(String str: new IterableClass()){
            System.out.println(str);
        }
    }
}

运行结果

And
that
is
how
we
know
the
Earth
to
be
banana-shaped.

 

9.适配器方法

  我们知道一个类如果实现了Iterable接口, 他就要重写返回Iterator类型的iterator方法,我们使用的时候,就可以使用foreach的方式来遍历这个类。但是,这种实现接口的方式,只能够有一个种遍历方法。假如:我现在想要有多种遍历方案。比如:正序遍历,反序遍历,该如何实现呢?我们使用适配器方法来实现。代码如下:

package net.mindview.holding;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;

class ReversibleArrayList extends ArrayList{
    private static final long serialVersiOnUID= 1L;

    public ReversibleArrayList(Collection c) {
        super(c);
    }
    
    /**
     * 实现了一个反转, 将传递过来的集合,反向输出
     */
    public Iterable reversed(){
        return new Iterable(){
            @Override
            public Iterator iterator() {
                return new Iterator(){
                    int current = size()-1;

                    @Override
                    public boolean hasNext() {
                        return current >= 0;
                    }

                    @Override
                    public T next() {
                        return get(current--);
                    }

                    @Override
                    public void remove() {
                        // TODO 
                    }
                };
            }
        };
    }
}

public class AdapterMethodIdiom {

    public static void main(String[] args) {
        ReversibleArrayList r = new ReversibleArrayList(Arrays.asList("To be or not to be".split(" ")));
        for(String str: r){
            System.out.print(str + " ");
        }
        System.out.println();
        for(String str:r.reversed()){
            System.out.print(str + " ");
        }
    }

}

  这个例子展示了, 我在一个类中,可以定义多种foreach循环的方式。下面我们使用这种方式,为IterableClass定义两种其他的循环方式:

package net.mindview.holding;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

/**
 * 继承了IterableClass类,就拥有了一种遍历方法了
 * @author samsung
 *
 */
public class MultiIteratorClass extends IterableClass{

    /**
     * 反序遍历
     * @param args
     */
    public Iterable reverse(){
        return new Iterable(){
            @Override
            public Iterator iterator() {
                return new Iterator(){
                    int count = words.length-1;
                    @Override
                    public boolean hasNext() {
                        return count >= 0;
                    }

                    @Override
                    public String next() {
                        return words[count--];
                    }

                    @Override
                    public void remove() {
                    }
                };
            }
        };
    }
    
    /**
     * 随机访问遍历
     * 这里没有创建自己的Iterator,而是直接返回被打乱的List中的Iterator.
     * 这里使用Collections.shuffle()方法并没有影响到原来的数组,这是将原来数组的元素的引用打乱了.注意,是引用打乱了.
     * 
     */
    public Iterable randomized(){
        return new Iterable(){
            @Override
            public Iterator iterator() {
                List shuffled = new ArrayList(Arrays.asList(words));
                Collections.shuffle(shuffled, new Random(47));
                return shuffled.iterator();
            }
            
        };
    }
    
    public static void main(String[] args) {
        MultiIteratorClass m = new MultiIteratorClass();
        for(String s:m){
            System.out.print(s+" ");
        }
        System.out.println();
        for(String s: m.reverse()){
            System.out.print(s+" ");
        }
        System.out.println();
        for(String s: m.randomized()){
            System.out.print(s+" ");
        }
    }
}

  这里面在说说Collection.shuffle()方法. 看下面的例子就明白了

package net.mindview.holding;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class ModifyingArraysAsList {
    
    public static void main(String[] args) {
        Random rand = new Random(47);
        Integer[] ia = {1,2,3,4,5,6,7,8,9,10};
        /*
         * list1包装了一层
         * 从结果可以看出: 如果数组转List后被包装一层,调用Collections.shuffle打乱顺序,
         * 打乱的是数组中元素的引用,数组的顺序没有改变
         */
        List list1 = new ArrayList(Arrays.asList(ia));
        System.out.println("Before shuffling:"+list1);
        Collections.shuffle(list1, rand);
        System.out.println("After shuffling: "+list1);
        System.out.println("array: "+Arrays.toString(ia));
        
        
        /*
         * list2没有包装
         * 从结果可以看出: 如果数组转List后没有包装,调用Collections.shuffle打乱顺序,打乱的是数组中元素的顺序
         */
        List list2 = Arrays.asList(ia);
        System.out.println("Before shuffling:"+list2);
        Collections.shuffle(list2, rand);
        System.out.println("After shuffling: "+list2);
        System.out.println("array: "+Arrays.toString(ia));
        
        
        
    }

}

 

 

  

 


推荐阅读
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了在多平台下进行条件编译的必要性,以及具体的实现方法。通过示例代码展示了如何使用条件编译来实现不同平台的功能。最后总结了只要接口相同,不同平台下的编译运行结果也会相同。 ... [详细]
  • 本文介绍了H5游戏性能优化和调试技巧,包括从问题表象出发进行优化、排除外部问题导致的卡顿、帧率设定、减少drawcall的方法、UI优化和图集渲染等八个理念。对于游戏程序员来说,解决游戏性能问题是一个关键的任务,本文提供了一些有用的参考价值。摘要长度为183字。 ... [详细]
  • STL迭代器的种类及其功能介绍
    本文介绍了标准模板库(STL)定义的五种迭代器的种类和功能。通过图表展示了这几种迭代器之间的关系,并详细描述了各个迭代器的功能和使用方法。其中,输入迭代器用于从容器中读取元素,输出迭代器用于向容器中写入元素,正向迭代器是输入迭代器和输出迭代器的组合。本文的目的是帮助读者更好地理解STL迭代器的使用方法和特点。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 本文介绍了Java的集合及其实现类,包括数据结构、抽象类和具体实现类的关系,详细介绍了List接口及其实现类ArrayList的基本操作和特点。文章通过提供相关参考文档和链接,帮助读者更好地理解和使用Java的集合类。 ... [详细]
  • Python SQLAlchemy库的使用方法详解
    本文详细介绍了Python中使用SQLAlchemy库的方法。首先对SQLAlchemy进行了简介,包括其定义、适用的数据库类型等。然后讨论了SQLAlchemy提供的两种主要使用模式,即SQL表达式语言和ORM。针对不同的需求,给出了选择哪种模式的建议。最后,介绍了连接数据库的方法,包括创建SQLAlchemy引擎和执行SQL语句的接口。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 本文介绍了Java的公式汇总及相关知识,包括定义变量的语法格式、类型转换公式、三元表达式、定义新的实例的格式、引用类型的方法以及数组静态初始化等内容。希望对读者有一定的参考价值。 ... [详细]
  • EzPP 0.2发布,新增YAML布局渲染功能
    EzPP发布了0.2.1版本,新增了YAML布局渲染功能,可以将YAML文件渲染为图片,并且可以复用YAML作为模版,通过传递不同参数生成不同的图片。这个功能可以用于绘制Logo、封面或其他图片,让用户不需要安装或卸载Photoshop。文章还提供了一个入门例子,介绍了使用ezpp的基本渲染方法,以及如何使用canvas、text类元素、自定义字体等。 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
  • C++语言入门:数组的基本知识和应用领域
    本文介绍了C++语言的基本知识和应用领域,包括C++语言与Python语言的区别、C++语言的结构化特点、关键字和控制语句的使用、运算符的种类和表达式的灵活性、各种数据类型的运算以及指针概念的引入。同时,还探讨了C++语言在代码效率方面的优势和与汇编语言的比较。对于想要学习C++语言的初学者来说,本文提供了一个简洁而全面的入门指南。 ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • 本文介绍了Python函数的定义与调用的方法,以及函数的作用,包括增强代码的可读性和重用性。文章详细解释了函数的定义与调用的语法和规则,以及函数的参数和返回值的用法。同时,还介绍了函数返回值的多种情况和多个值的返回方式。通过学习本文,读者可以更好地理解和使用Python函数,提高代码的可读性和重用性。 ... [详细]
  • 本文介绍了Cocos2dx学习笔记中的更新函数scheduleUpdate、进度计时器CCProgressTo和滚动视图CCScrollView的用法。详细介绍了scheduleUpdate函数的作用和使用方法,以及schedule函数的区别。同时,还提供了相关的代码示例。 ... [详细]
author-avatar
菲呀菲呀飞呀
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有