今天第一次发表博客,也是因为我正在学习JAVA编程思想,想自己做个记录,也有个总结。
第十一章 持有对象
引文:如果一个程序只包含固定数量的且其生命期都是已知的对象,那么这是一个非常简单的程序--来自《JAVA编程思想》
一:LIst接口
package com.cn.collection;
import java.util.ArrayList;
class Apple{
private static long counter;
private final long id = counter++;
public long id()
{
return id;
}
}
class Orange{}
public class ApplesAndOrangesWithoutGenerics {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
//前面的Apple是泛型,声明只能添加Apple类型对象。后面的Apple为返回值类型。
ArrayList<Apple> apples = new ArrayList<Apple>();
for (int i = 0; i < 3; i++) {
apples.add(new Apple());
}
for (int i = 0; i < apples.size(); i++) {
//你认为是ArrayList是Apple(),其实是Object的对象。
System.out.println(apples.get(i).id());
}
for (int i = 0; i < apples.size(); i++) {
System.out.println(apples.get(i).id());
}
}
}
package com.cn.collection;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
class A extends Apple{}
class B extends Apple{}
class C extends Apple{}
class D extends Apple{}
public class GenericsAndUpcasting {
public static void main(String[] args) {
List<Apple> arraylist = new LinkedList<Apple>();
arraylist.add(new A());
arraylist.add(new B());
arraylist.add(new C());
arraylist.add(new D());
for (Apple c : arraylist) {
System.out.println(c);
}
}
}
因此,你可以将Apple的子类型添加到指定为保存Apple对象的容器中。
package com.cn.collection;
import typeinfo.pets.*;
import java.util.*;
public class LinkedListFeatures {
public static void main(String[] args) {
//Pet是一个类,已经Pet的各种子类型。(不需要深入了解)
LinkedList<Pet> pets = new LinkedList<Pet>(Pets.arrayList(5));
//输出:[Rat, Manx, Cymric, Mutt, Pug]
System.out.println(pets);
//获得节点的头节点
System.out.println("pets.getFirst(): "+pets.getFirst());
//获得当前节点
System.out.println("pets.element(): "+pets.element());
//查看顶部
System.out.println("pets.peek(): "+pets.peek());
//remove掉Rat
System.out.println("pets.remove(): "+pets.remove());
//去掉首节点
System.out.println("pets.removeFirst(): "+pets.removeFirst());
//remove掉下一个节点
System.out.println("pets.poll(): "+pets.poll());
System.out.println(pets);
//添加首节点
pets.addFirst(new Rat());
//添加到最后一个节点
pets.offer(Pets.randomPet());
System.out.println("After offer(): "+pets);
//添加节点
pets.add(Pets.randomPet());
System.out.println("After add(): "+pets);
pets.addLast(new Hamster());
System.out.println("After addLast(): "+pets);
System.out.println("pets.removeLast(): "+pets.removeLast());
}
}
package com.cn.collection;
import java.util.*;
public class SetOfInteger {
public static void main(String[] args) {
Random rand = new Random(47);
Set<Integer> set = new HashSet<Integer>();
for(int i=0;i<10000;i++)
set.add(rand.nextInt(30));
System.out.println(set);
}
}
//输出:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
Map:将对象映射到其他对象的能力是一种解决编程问题的杀手锏。例如,考虑一个程序,他将用来检查JAVA的Random类的随机性。理想情况下,Rondom可以将产生理想的数字分布,但要想测试它,则需要生产大量的随机数,并对落下各种不同范围的数字进行计数。Map可以很容易地解决该问题。
package com.cn.collection;
import java.util.*;
public class Statistics {
public static void main(String[] args) {
//声明随机数
Random ran = new Random(47);
//建立Map持有对象。Map是个借口,HashMap是实现方法。
Map<Integer,Integer> m = new HashMap<Integer,Integer>();
//在一万个for循环中
for (int i = 0; i < 10000; i++) {
//将在29以内的随机数种赋给给r
int r = ran.nextInt(29);
//m添加随机数
Integer frep = m.get(r);
m.put(r, frep == null? 1:frep+1);
}
System.out.println(m);
}
}
//输出:{0=323, 1=325, 2=332, 3=353, 4=367, 5=363, 6=341, 7=357, 8=340, 9=331, 10=328, 11=336, 12=352, 13=353, 14=353, 15=373, 16=349, 17=336, 18=336, 19=333, 20=355, 21=351, 22=369, 23=337, 24=360, 25=350, 26=344, 27=325, 28=328}
Queue:队列是一个典型的先进先出(FIFO)的容器。即从容器的一段放入事物,从另一端取出,并且事物放入容器的顺序和取出的顺序是相同的。队列常被当做一种可靠的将对象从程序的某个区域传输到另一个区域的途径。
package com.cn.collection;
import java.util.*;
public class QueueDemo {
public static void printQ(Queue queue)
{
while(queue.peek()!=null)
System.out.println(queue.remove()+" ");
System.out.println();
}
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<Integer>();
Random ran = new Random(47);
for (int i = 0; i < 10; i++)
queue.offer(ran.nextInt(i+10));
printQ(queue);
Queue<Character> qc = new LinkedList<Character>();
for (char c : "Brontosaurus".toCharArray())
qc.offer(c);
printQ(qc);
}
}
//输出:8 1 1 1 5 14 3 1 0 1
//B r o n t o s a u r u s
Foreach与迭代器:到目前为止,foreach语法主要用于数组,但是它也可以应用于任何Collection对象。你实际上已经看到过很多使用ArrayList时用到它的实例,下面是一个更通用的证明:
package com.cn.collection;
import java.util.*;
public class IterableClass implements Iterable<String>{
protected String[] words =("And that is how "+ "We know the Earth to be banana.").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();}
};
}
public static void main(String[] args) {
for (String s : new IterableClass())
System.out.println(s+" ");
}
}
//输出:And that is how We know the Earth to be banana.
小结:
1)数组将数字与对象联系起来。它保存类型明确的对象,查询对象时,不需要对结果做类型转换,它可以是多维的,可以保存基本类型数据。但是,数组一旦生成,其容量就不能改变。
2)Collection保存单一元素,而Map保存相关的键值对。有了Java泛型,你就可以指定容器中存放的对象,因此你就不会将错误的对象放入容器中,并且在容器中获取元素时,不必类型转换。各种Collection和各种Map都可以在你向其中添加元素时,自动调整其尺寸。容器不能持有基本类型,但是自动包装机制会仔细地执行基本类型到容器中所持有的包装器类型之间的双向转换。
3)像数组一样,List也建立数字索引与对象的关联,因此,数组和list都是排好序的容器,LIst能够自动扩充容量。
4)如果要大量的随机访问,就使用ArrayList,如果经常从表中插入或删除元素,则应该使用LinkedList.
5)各种Queue以及队列的行为由LinkedList提供支持。
6)Map是一种将对象(而非数字)与对象相关联的设计。HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快,LinkedHashMap保持元素插入的顺序,但是也通过散列提供快速访问能力。
7)Set不接受重复元素。HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态。LinkedHashSet以插入顺序保存元素。
8)新程序中不应该使用过时的Vector,Hashtable和Stack.