11持有对象-Java编程思想


Java提供一套相当完整的容器类来存储数量不确定的对象。集合类:list,set.queue,map。通过使用泛型,可以在编译器防止将错误类型的对象放置到容器中去,在取出的时候也会帮忙转型。

Collection,一个独立元素序列。List按照插入的顺序保存元素,set不能有重复的元素,Queue按照队列的规则确定对象顺序。

Map键值对,允许用键来找值。

HashSet\TreeSet\LinkedHashSet都是Set类型。HashSet是最快的获取元素的方式,顺序看起来杂乱无章(通常只用关心某个元素是否是其成员,不关心顺序)。TreeSet将元素存储在红黑树数据结构中,按照结果的升序保存对象。LinkedHashSet因为查询速度也使用了hash,同时使用了链表来维护顺序,按照添加的顺序保存对象。

HashMap是最快的获取元素的方式,顺序看起来杂乱无章。TreeMap按照结果的升序保存对象。LinkedHashMap按照添加的顺序保存键,同时还保留了HashMap的查询速度。

List在Collection的基础上添加了较多的方法。ArrayList 和LinkedList两种,前者在随机访问方面有较大优势,在插入和移除的时候较慢。后者插入和删除的代价较低,顺序访问也较快,但是对于随机访问则相对较慢。

迭代器(也是一种设计模式):我们在设计的时候一直考虑的是,怎么去抽象到更高的高度,不对确切的内容进行编程,而是抽象到更高的高度,方便复用。接收对象容器并使用它,使每个对象都能执行操作。

class Pets{
    List<String> pets=new ArrayList<>();
    public List<String> getPets(){
        pets.add("pet1");
        pets.add("pet2");
        pets.add("pet3");
        return pets;
    }

}

public class IteratorTest {
    public static void display(Iterator<String> it){
        while (it.hasNext()){
            String s=it.next();
            System.out.print(s);
        }
        System.out.println();
    }
    public static void display(Collection<String> c){
        for (String s:c) {
            System.out.print(s);
        }
        System.out.println();
    }
    public static void main(String args[]){
        Pets p=new Pets();
        List<String> petsList=p.getPets();
        Set<String> petsSet=new HashSet<>(petsList);
        Map<String,String> petsMap=new HashMap<>();
        String[] name=("cat,pig,dog".split(","));
        for (int i=0;i<3;i++){
            petsMap.put(name[i],petsList.get(i));
        }
        display(petsList);
        display(petsSet);
        display(petsList.iterator());
        display(petsSet.iterator());
        System.out.println(petsMap);
        System.out.println(petsMap.keySet());
        display(petsMap.keySet());
        display(petsMap.values());
        display(petsMap.values().iterator());

    }
}

迭代器就是为了达到这样的目的。迭代器是一个对象,遍历并选择其中的对象。不用关心底层的结构。Java的interator只能单向移动。使用方法interator()要求容器返回一个Interator对象,其准备好返回序列的第一个元素,使用next返回下一个,hasnext检查是否还有下一个,remove将元素删除。在调用remove前一定要调用next。

ListInterator是更强大的interator的子类型。可以双向移动。

Linkedlist额外提供了栈,队列,双端队列的方法。

Stack栈,后进先出的容器LIFO,自助餐托盘。实际上LinkedList就能当栈来使用。

public class Stack<T> {
    //大概的了解栈的功能,了解本质上Linkedlist是可以实现栈的功能的
    private LinkedList<T> storage=new LinkedList<>();
    public void push(T t){storage.add(t);}
    public T peek(){return storage.getFirst();}
    public T pop(){return storage.removeFirst();}
    public boolean isEmpty(){return storage.isEmpty();}
    public String toString(){return  storage.toString();}
}

public class StackTest {
    public static void main(String args[]){
        java.util.Stack<String> stack=new Stack<>();
        for (String s:"my name is haha".split(" ")
             ) {
            stack.push(s);
        }
        while (!stack.isEmpty()){
            System.out.println(stack.pop());
        }
    }
}

Set不保存重复的元素,实际上set就是collection。

Map与其他的Collection一样,很容易就扩展为多维的形式。可多重嵌套使用。例如跟踪某个拥有多个宠物的人,Map<Person,List<Pet>>.Map可以返回它的key的Set,它的键值对的set。keyset()方法产生了前者的set集合,可以方便用foreach语法进行遍历。

public class MapTest {
    public static void test1(){
        Random random=new Random(47);
        Map<Integer,Integer> m=new HashMap<>();
        for(int i=0;i<1000;i++){
            int r= random.nextInt(20);
            Integer freq=m.get(r);
            m.put(r,freq==null?1:freq+1);//这种语法有点意思
        }
        System.out.println(m);
    }
    public static void test2(){
        Map<String,Animal> map=new HashMap<>();
        map.put("cat",new Animal("miao"));
        map.put("dog",new Animal("wang"));
        System.out.println(map);
        Animal dog=map.get("dog");
        System.out.println(dog);
        System.out.println(map.containsKey("cat"));
        System.out.println(map.containsValue(dog));
    }
    public static void main(String args[]){
        test1();
        test2();
    }
}


class Animal{
    String name;
    public Animal(String name){
        this.name=name;
    }
}

Queue队列,典型的先进先出FIFO,在并发编程中特别重要。实际上LinkedList就能当队列来使用。注意还存在PriorityQueue即是优先级队列。队列规则是给定一组队列中的元素的情况下,下一个弹出队列元素的规则。先进先出声明的是下一个元素应该是等待时间最长的元素。优先级队列返回的元素是最需要的元素,如飞机场某飞机要起飞,该飞机的乘客可以优先登机。当优先队列调用offer方法进行插入对象的时候,对象会自动根据规则排序。同时peek,poll,remove的时候也是获取的优先级最高的。注意可以通过自己提供Comparator方法来修改顺序。

public class QueueTest {
    public static void main(String args[]){
        Queue<Integer> queue=new LinkedList<>();
        //我注意到,如果是对于Stack而言,后面的实现我写出Stack<String> s=new Stack<>();是默认OK的
        //但是对于Queue,我写了相似的结构以后,马上出了一堆方法要我覆盖
        //offer方法将一个元素插入到队尾或者返回false
        //peek方法和element方法都在不移除的情况下返回队头
        //peek方法在队列为空的时候返回null,而element方法返回NoSuchElementException异常
        //poll和remove方法将移除并返回对头,但poll方法在队列为空的时候返回null,而remove抛出NoSuchElementException异常
        Random random=new Random(47);
        for (int i=1;i<10;i++){
            queue.offer(random.nextInt(i+10));
        }
        printQ(queue);
        System.out.println(queue);
        Queue<Character> qc=new LinkedList<>();
        for (char c:"Helloworld".toCharArray()){
            qc.offer(c);
        }
        System.out.println(qc);
        printQ(qc);
    }
    public static void printQ(Queue q){
        while (q.peek()!=null){
            System.out.println(q.remove());
        }
    }
}

foreach可以用于数组,也可以用于任何collection对象。之所以能够正常工作,是因为Javase5引入了新的Iterator接口,该接口包含一个能产生Iterator的iterator方法。如果你创建了Iterable实现的类,都可以用于foreach。

Java提供了大量关于持有对象的操作,数组将数字与对象关联起来。保存类型明确的对象,查询对象的时候无需类型转换。数组一旦形成就不能改变大小。

public class ForeachCollections {
    public static void main(String args[]){
        Collection<String> cs=new LinkedHashSet<>();
        Collections.addAll(cs,"go home or go big".split(" "));
        for (String s:cs
             ) {
            System.out.println(" "+s+" ");
        }
    }
}
只要实现了Iterable类就可以用于foreach中。
public class IterableClass implements Iterable<String> {
    //这段很精彩,要背背
    //返回了实现Iterator<String>的匿名内部类的实例
    protected String[] words=("you should study hard so you can go big".split(" "));
    public Iterator<String> iterator(){
        return new Iterator<String>() {
            private int index=0;
            public boolean hasNext() {
                return index<words.length;
            }
            public String next() {
                return words[index++];
            }
            public void remove(){
                throw new UnsupportedOperationException();
            }
        };
    }
    //注意这个地方的ItearbleClass
    public static void main(String args[]){
        for (String s:new IterableClass()
             ) {
            System.out.println(s);
        }
    }
}

Collection保存单一的元素,而map保存相关联的键值对。有了Java泛型就可以指定容器中存储对象的类型,并且取出元素时候无需进行类型转换。容器大小可自动调整,容器不能存放基本数据类型,但是包装机制可以实现双向转换。各种栈和队列的行为,由linkedlist提供支持。

map是一种将对象(而非数字)与对象相关联的设计。hashmap用于快速访问,treemap用于保持键始终是排序状态,linkedhashmap保持插入的顺序同时也提供快速访问的支持。

Set不接受相同的元素。hashset快速查询,treeset保持排序状态,linkedhashset保持插入顺序也提供快速访问机制。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值