Java编程思想学习笔记十一:持有对象
在前面的学习过程中,我们使用的都是固定数量的且生命周期已知的对象。而在一些情况中,我们可能需要不确定数量不确切类型的对象,这种创建一个单一的对象显然是不行的了。Java提供了多种支持,比如数组,数组可以保存一组基本数据类型。但是数组的大小是固定的,在更特殊的编程条件下,固定长度显然是不友好的,所以Java类库提供了一套相当完整的容器类来解决这个问题。我们也称作是集合类。本章优先学习常用的集合以及用法,后续将会更加深入的讨论其它的集合。
一、泛型和类型安全的容器
package com.chenxyt.java.practice;
import java.util.ArrayList;
class Apple{
private static long counter;
private final long id = counter++;
public long getid(){
return id;
}
}
class Orange{
}
public class AppleAndOrangesWithoutGeneric {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
ArrayList al = new ArrayList();
for(int i=0;i<3;i++){
al.add(new Apple());
al.add(new Orange());
}
for(int i=0;i<al.size();i++){
Apple apple = (Apple) al.get(i);
System.out.println(apple.getid());
}
}
}
在这里我们实际上存入ArrayList是Object对象,因为所有的类都继承自Object类,所以这里实际上不光可以添加Orange对象还可以添加任意类型的对象。我们在get()获取数据的时候,我们以为获取的是一个Apple对象,实际上获取的是一个Obejct的引用,然后强制转换成我们需要的对象。在这里我们强制的将从ArrayList中取出的Object引用强制转换成Apple类型,那么当遇到这个对象类型实际上是Orange类型时,就会发生类型转换错误。所以说这种创建形式非常不安全。报错如下:
package com.chenxyt.java.practice;
import java.util.ArrayList;
class Apple{
private static long counter;
private final long id = counter++;
public long getid(){
return id;
}
}
class Orange{
}
public class AppleAndOrangesWithoutGeneric {
public static void main(String[] args) {
ArrayList<Apple> al = new ArrayList<Apple>();
for(int i=0;i<3;i++){
al.add(new Apple());
// al.add(new Orange());
}
for(Apple apple :al){
System.out.println(apple.getid());
}
}
}
现在你可以阻止将Orange对象加入到Apple容器中了,并且我们可以使用for-each循环获取容器中的内容。实际上当我们固定了一种泛型数据参数,正如前面几章说到的,继承的时候基类收发的消息,子类也可以收发,所以泛型同样支持向上转型,我们可以传递其导出类参数。
二、基本概念
List<Apple> apples = new ArrayList<Apple>();
这里ArrayList已经被向上转型为List,使用接口的目的是如何修改它的实现,这里实现由ArrayList完成。这种方式并非永远有效,会带来一个其它的问题,ArrayList类可能新添加了其它的方法,因此当它向上转型为List时,可能会是不完善的。因此如果我们要使用这类方法,那就需要使用更加确切的类型。
三、添加一组元素
package com.chenxyt.java.practice;
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) {
Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
Integer[] moreInts = {6,7,8,9,10};
collection.addAll(Arrays.asList(moreInts));
Collections.addAll(collection,11,12,13,14);
Collections.addAll(collection,moreInts);
List<Integer> list = Arrays.asList(15,16,17,18);
list.set(1,29);
//run error 数组不支持变更长度
list.add(21);
}
}
Collection的构造器可以传递另一个Collection用来初始化,但是这种方式不如定义个空的Collection然后使用addAll的形式添加数据灵活。
四、容器的打印
package com.chenxyt.java.practice;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
public class PrintingContainers {
static Collection fill(Collection<String> collection){
collection.add("one");
collection.add("two");
collection.add("three");
collection.add("four");
collection.add("five");
collection.add("five");
return collection;
}
static Map fill(Map<String,String> map){
map.put("one","ONE");
map.put("two","TWO");
map.put("three","THREE");
map.put("four","FOUR");
map.put("five","FIVE");
map.put("five","FIVE");
return map;
}
public static void main(String[] args) {
System.out.println("ArrayList===" + fill(new ArrayList<String>()));
System.out.println("LinkedList===" + fill(new LinkedList<String>()));
System.out.println("HashSet===" + fill(new HashSet<String>()));
System.out.println("TreeSet===" + fill(new TreeSet<String>()));
System.out.println("LinkedHashSet===" + fill(new LinkedHashSet<String>()));
System.out.println("HashMap===" + fill(new HashMap<String,String>()));
System.out.println("TreeMap===" + fill(new TreeMap<String,String>()));
System.out.println("LinkedHashMap===" + fill(new LinkedHashMap<String,String>()));
}
}
运行结果:
五、List
package com.chenxyt.java.practice;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
enum Pet{
Pet,Rat,Manx,Mutt,Pug,Cymric,Humaster
}
public class Pets {
public static List<Pet> arrayList(int n){
List<Pet> pets = new ArrayList<Pet>();
for(int i=0;i<n;i++){
Random rand = new Random();
int j = rand.nextInt(n);
switch(j){
case 0:
pets.add(Pet.Pet);
break;
case 1:
pets.add(Pet.Rat);
break;
case 2:
pets.add(Pet.Manx);
break;
case 3:
pets.add(Pet.Mutt);
break;
case 4:
pets.add(Pet.Pug);
break;
case 5:
pets.add(Pet.Cymric);
break;
case 6:
pets.add(Pet.Humaster);
break;
default:
break;
}
}
return pets;
}
}
然后是一个List的操作类,相关操作的注释已经标注:
package com.chenxyt.java.practice;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class ListFeature {
public static void main(String[] args) {
Random rand = new Random(47);
List<Pet> pets = Pets.arrayList(7);
//基本的List展示
System.out.println("1:" + pets);
pets.add(Pet.Humaster);
//List可以自动扩容 向其中添加的元素会被追加到最后
System.out.println("2:" + pets);
//a.contains(b)方法判断 集合a中是否包含b 返回的是boolean类型
System.out.println("3:" + pets.contains(Pet.Humaster));
//remove 移除指定的元素
pets.remove(Pet.Humaster);
Pet p = pets.get(2);
//get(2)获取指定位置上的元素 下标从0开始 indexOf(p) 返回指定元素的下标
System.out.println("4:" + p + " " + pets.indexOf(p));
Pet cymric = Pet.Cymric;
//indexOf(p) 返回指定元素的下标 如果没有则返回-1 存在多个则返回第一个
System.out.println("5:" + pets.indexOf(cymric));
//remove(p) 移除指定元素 返回boolean类型 不存在为false 存在多个则移除第一个
System.out.println("6:" + pets.remove(cymric));
System.out.println("7:" + pets.remove(p));
System.out.println("8:" + pets);
//在下标为3的位置插入元素,后边的元素顺序后移
pets.add(3,Pet.Mutt);
System.out.println("9:" + pets);
//截断 下标为1到4的元素 包括1但是不包括4
List<Pet> sub = pets.subList(1,4);
System.out.println("subList:" + sub);
//a.containsAll(b) a集合是否包含b集合中的全部元素 返回boolean类型
System.out.println("10:" + pets.containsAll(sub));
//排序
Collections.sort(sub);
System.out.println("sorted subList:" + sub);
System.out.println("11:" + pets.containsAll(sub));
//随机排序
Collections.shuffle(sub,rand);
System.out.println("suffle subList:" + sub);
System.out.println("12:" + pets.containsAll(sub));
List<Pet> copy = new ArrayList<Pet>(pets);
sub = Arrays.asList(pets.get(1),pets.get(4));
System.out.println("sub:" + sub);
//a.retainAll(b) a中保留所有与b的交集部分
copy.retainAll(sub);
System.out.println("13:" + copy);
copy = new ArrayList<Pet>(pets);
copy.remove(2);
System.out.println("14:" + copy);
//移除所有的元素
copy.removeAll(sub);
System.out.println("15:" + copy);
//将下标为1的元素更换为指定元素
copy.set(1,Pet.Pug);
System.out.println("16:" + copy);
copy.addAll(2,sub);
System.out.println("17:" + copy);
//判断是否为空 返回boolean类型
System.out.println("18:" + pets.isEmpty());
//清空数据
pets.clear();
System.out.println("19:" + pets);
System.out.println("20:" + pets.isEmpty());
pets.addAll(Pets.arrayList(4));
System.out.println("21:" + pets);
//将List转换成数组
Object[] o = pets.toArray();
System.out.println("22:" + o[3]);
}
}
运行结果:
因为数据的插入是随机的,所以后边对应的操作也是随机结果。相关操作已经写在注释中,这里不再阐述。
六、迭代器
package com.chenxyt.java.practice;
import java.util.Iterator;
import java.util.List;
public class SimpleIterator {
public static void main(String[] args) {
List<Pet> pets = Pets.arrayList(7);
Iterator<Pet> it = pets.iterator();
System.out.println("1:" + pets);
System.out.println("2:" + it);
while(it.hasNext()){
Pet p = it.next();
System.out.println("--->" + p);
}
it = pets.iterator();
for(int i = 0;i<7;i++){
it.next();
it.remove();
System.out.println(pets);
}
}
}
运行结果:
package com.chenxyt.java.practice;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.TreeSet;
public class SimpleIterator {
public static void display(Iterator<Pet> it){
System.out.println("===" +it.getClass().getName()+ "===");
while(it.hasNext()){
Pet p = it.next();
System.out.println(p);
}
}
public static void main(String[] args) {
ArrayList<Pet> pets = (ArrayList<Pet>) Pets.arrayList(7);
LinkedList<Pet> lkp = new LinkedList<Pet>(pets);
HashSet<Pet> hs = new HashSet<Pet>(pets);
TreeSet<Pet> ts = new TreeSet<Pet>(pets);
LinkedHashSet<Pet> lhs = new LinkedHashSet<Pet>(pets);
display(pets.iterator());
display(lkp.iterator());
display(hs.iterator());
display(ts.iterator());
display(lhs.iterator());
}
}
运行结果:
package com.chenxyt.java.practice;
import java.util.List;
import java.util.ListIterator;
public class SimpleListIterator {
public static void main(String[] args) {
List<Pet> pets = Pets.arrayList(7);
ListIterator<Pet> lit = pets.listIterator();
System.out.println(pets);
System.out.println(lit);
System.out.println("=====Next=====");
while(lit.hasNext()){
int index = lit.nextIndex();
Pet p = lit.next();
System.out.println("Index:" + index + "," + "Pet:" + p );
}
System.out.println("=====Previous=====");
lit = pets.listIterator(7);
while(lit.hasPrevious()){
int index = lit.previousIndex();
Pet p = lit.previous();
System.out.println("Index:" + index + "," + "Pet:" + p );
}
System.out.println("=====Update Set=====");
lit = pets.listIterator();
while(lit.hasNext()){
Pet p = lit.next();
lit.set(Pet.Humaster);
}
System.out.println(pets);
}
}
运行结果:
七、LinkedList
LinkedList与ArrayList相同都是实现了List接口,但是它在增删的时候效率较高,在随机访问的时候效率略低。LinkedList还增加了其作为栈、队列、双端队列的操作方法。这些方法有的只是名字有差异,或者是返回值有差异。package com.chenxyt.java.practice;
import java.util.LinkedList;
public class LinkedListFeatures {
public static void main(String[] args) {
LinkedList<Pet> pets = new LinkedList<Pet>(Pets.arrayList(7));
System.out.println(pets);
//以下两个方法都返回容器的第一个元素 在容器为空的时候抛异常
System.out.println("pets.getFirst()---》" + pets.getFirst());
System.out.println("pets.elements()---》" + pets.element());
//与上两个方法相同 区别在于为空时返回null
System.out.println("pets.peek()---》" + pets.peek());
//以下两个方法移除列表的第一个元素 在容器为空的时候抛出异常
System.out.println("pets.remove()--->" + pets.remove());
System.out.println("pets.removeFirst()--->" + pets.removeFirst());
//与上两个方法相同 区别在于容器为空时返回null
System.out.println("pets.pool()--->" + pets.poll());
System.out.println(pets);
//在容器第一个位置加入新的元素 其它元素依次后移
pets.addFirst(Pet.Manx);
System.out.println("After addFirst()" + pets);
//以下两个方法在容器尾部插入新元素
pets.add(Pet.Humaster);
System.out.println("After add()" + pets);
pets.addLast(Pet.Pug);
System.out.println("After addLast()" + pets);
//offer 是针对queue 在尾部插入数据 add是针对list 在尾部插入数据
pets.offer(Pet.Rat);
System.out.println("After offer()" + pets);
//移除最后一个并返回该元素
System.out.println("pets.removeLast()" + pets.removeLast());
System.out.println("After removeLast()" + pets);
}
}
运行结果:
八、Stack
package com.chenxyt.java.practice;
import java.util.LinkedList;
public class Stack<T> {
private LinkedList<T> storage = new LinkedList<T>();
public void push(T v){
storage.addFirst(v);
}
public T peek(){
return storage.getFirst();
}
public T pop(){
return storage.removeFirst();
}
public boolean empty(){
return storage.isEmpty();
}
public String toString(){
return storage.toString();
}
}
这里使用<T>泛型来告诉编译器这个Stack是持有参数化类型T的容器,这个Stack是使用LinkedList实现的,而LinkedList也被告知是使用了T类型的对象。peek()方法返回栈顶元素,但是并不是移除。而pop()方法这里是弹出栈顶元素,也就是移除了栈顶元素。如果我们只是需要栈的行为,而不需要其它无关的行为方法,那么这里使用继承就显然不合适了。后边会讨论在Java1.0中,java.util.Stack这个类的设计。
package com.chenxyt.java.practice;
public class StackTest {
public static void main(String[] args) {
Stack<String> stack = new Stack<String>();
for(String s : "My Dog has fleas".split(" ")){
stack.push(s);
}
while(!stack.empty()){
System.out.print(stack.pop() + " ");
}
}
}
这里使用了push方法将字符串“My Dog has fleas”用空格分开的单词压入栈中,然后使用pop方法弹出栈顶元素。因为pop方法调用之后会移除栈顶元素,所以会依次弹出栈中的所有元素。在这里我们使用了自己定义的Stack,如果我们导入了java.util.Stack类的话,那么我们这样使用可能会产生命名冲突的现象,解决方法是我们在实例化的时候使用完整的类名,或者修改我们自己定义的Stack类名。
九、Set
package com.chenxyt.java.practice;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class SetofInteger {
public static void main(String[] args) {
Random random = new Random(47);
Set<Integer> set = new HashSet<Integer>();
for(int i=0;i<10000;i++){
set.add(random.nextInt(30));
}
System.out.println(set);
}
}
运行结果:
package com.chenxyt.java.practice;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public class SetOperations {
public static void main(String[] args) {
Set<String> set1 = new HashSet<String>();
Collections.addAll(set1,"A B C D E F G H I J K L".split(" "));
set1.add("M");
System.out.println("H:" + set1.contains("H"));
System.out.println("N:" + set1.contains("N"));
Set<String> set2 = new HashSet<String>();
Collections.addAll(set2,"H I J K L".split(" "));
System.out.println("set2 in set1:" + set1.containsAll(set2));
set1.remove("H");
System.out.println("set1: " + set1);
System.out.println("set2 in set1:" + set1.containsAll(set2));
set1.removeAll(set2);
System.out.println("set2 removed from set1:" + set1);
Collections.addAll(set1,"X Y Z".split(" "));
System.out.println("XYZ added to set1:" + set1);
}
}
运行结果:
十、Map
package com.chenxyt.java.practice;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class RandomTest {
public static void main(String[] args) {
Random random = new Random(47);
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
for(int i =0;i<1000000;i++){
int x = random.nextInt(20);
Integer freq = map.get(x);
map.put(x,freq == null?1:freq+1);
}
System.out.println(map);
}
}
运行结果:
package com.chenxyt.java.practice;
import java.util.HashMap;
import java.util.Map;
public class PetMap {
public static void main(String[] args) {
Map<String,Pet> petMap = new HashMap<String,Pet>();
petMap.put("MyCat",Pet.Cymric);
petMap.put("MyDog",Pet.Humaster);
petMap.put("MyPig",Pet.Mutt);
System.out.println(petMap);
Pet p = petMap.get("MyDog");
System.out.println(p);
System.out.println(petMap.containsKey("MyDog"));
System.out.println(petMap.containsValue(Pet.Cymric));
}
}
运行结果:
package com.chenxyt.java.practice;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MapOfList {
public static void main(String[] args) {
Map<String,List<Pet>> petList = new HashMap<String,List<Pet>>();
petList.put("MyDog",Arrays.asList(Pet.Cymric,Pet.Humaster,Pet.Mutt));
System.out.println(petList);
System.out.println("key:" + petList.keySet());
System.out.println("value:" + petList.values());
for(String s:petList.keySet()){
System.out.print(s + ":");
for(Pet p:petList.get(s)){
System.out.print(p + " ");
}
}
}
}
运行结果:
十一、Queue
package com.chenxyt.java.practice;
import java.util.LinkedList;
import java.util.Queue;
public class QueueDemo {
public static void printQ(Queue queue){
//不移除的情况下返回队列头部元素 element()方法相同 peek为空返回null element为空抛出异常
while(queue.peek()!=null){
//remove()移除头元素 为空抛出异常 poll 为空返回null
System.out.println(queue.remove() + " ");
}
}
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<Integer>();
for(int i = 0;i<5;i++){
//元素插入队尾
queue.offer(i);
}
printQ(queue);
Queue<Character> qc = new LinkedList<Character>();
for(char c:"QUEUEDEMO".toCharArray()){
qc.offer(c);
}
printQ(qc);
}
}
package com.chenxyt.java.practice;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
public class QueueDemo {
public static void printQ(Queue queue){
//不移除的情况下返回队列头部元素 element()方法相同 peek为空返回null element为空抛出异常
while(queue.peek()!=null){
//remove()移除头元素 为空抛出异常 poll 为空返回null
System.out.println(queue.remove() + " ");
}
}
public static void main(String[] args) {
List<Integer> ints = Arrays.asList(25,22,20,18,14,9,3,1,5,6,14,18,22,23,25);
PriorityQueue<Integer> queue = new PriorityQueue<Integer>(ints.size(),Collections.reverseOrder());
queue.addAll(ints);
printQ(queue);
}
}
十二、Collection和Iterator
package com.chenxyt.java.practice;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class InterfaceVsIterator {
public static void display(Iterator<Pet> it){
System.out.println("IT-P:");
while(it.hasNext()){
Pet p = it.next();
System.out.print(p + ",");
}
System.out.println("");
}
public static void display(Collection<Pet> collection){
System.out.println("CL-P:");
for(Pet p:collection){
System.out.print(p + ",");
}
System.out.println("");
}
public static void main(String[] args) {
List<Pet> petList = Pets.arrayList(7);
Set<Pet> petSet = new HashSet<Pet>(petList);
Map<String,Pet> petMap = new LinkedHashMap<String,Pet>();
String[] names = ("A,B,C,D,E").split(",");
for(int i =0;i<names.length;i++){
petMap.put(names[i],petList.get(i));
}
display(petList);
display(petSet);
display(petList.iterator());
display(petSet.iterator());
System.out.println(petMap);
System.out.println(petMap.keySet());
display(petMap.values());
display(petMap.values().iterator());
}
}
十三、Foreach与迭代器
package com.chenxyt.java.practice;
import java.util.Iterator;
public class IterableClass implements Iterable<String> {
protected String[] words = ("And that is how we know the earth").split(" ");
@Override
public Iterator<String> iterator() {
// TODO Auto-generated method stub
return new Iterator<String>(){
private int index = 0;
public boolean hasNext(){
return index<words.length;
}
public String next(){
return words[index++];
}
public void remove(){
//---
}
};
}
public static void main(String[] args) {
for(String s :new IterableClass()){
System.out.print(s + " ");
}
}
}