Java编程思想笔记11——第11章:持有对象

11 持有对象

​ 通常,程序总是根据运行时才知道某些条件去创建新的对象。

​ 不需要事先定义好创建的数量,可以根据需要创建任意数量的对象。

​ 数组则必须实现指定数量,所以有所约束。

​ Java提供了容器类来解决这个问题,基本的类型是List、Set、Queue和Map。这些称之为集合类,且都是Collection类或Map类的子类。

​ Set不能保存重复值。 Map允许将对象与其他对象关联起来。

​ 这些容器不需要事先指定大小。

11.1 泛型和类型安全的容器

​ 在JavaSE5之前,可以像容器插入不正确的类型,例如创建一个Arraylist,既可以插入Apple类型,也可以插入Orange类型

​ 通过add()方法插入对象,通过get方法访问这些数据。

(1)不使用泛型

​ 因为没有使用泛型,所以会提示警告,可以使用@SuppressWarnings来抑制。

class Cat{ }
class Dog{ }

public class Test {
    @SuppressWarnings("unchecked")  //不提示警告
	public static void main(String[] args) {	
		ArrayList dogs = new ArrayList();
		dogs.add(new Cat());
		dogs.add(new Dog());	
	}
}

当不指定类型时,默认是Object类。因为所有类都继承Object

(2)使用泛型

​ 使用泛型,意味着你不可以插入其他类型的数据

class Cat{ }
class Dog{ }

public class Test {
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {	
		ArrayList<Dog> dogs = new ArrayList<Dog>();
//		dogs.add(new Cat()); // 会报错,不可以插入
		dogs.add(new Dog());	
        for (Dog dog : dogs) { //使用增强for循环进行遍历
			System.out.println(dog);
		}
	}
}

(3)使用泛型,可以插入其子类

class Dog{ }
class Hasiqi extends Dog{} //哈士奇
class Keji extends Dog{} //柯基


public class Test {
	public static void main(String[] args) {	
		ArrayList<Dog> dogs = new ArrayList<Dog>();
		dogs.add(new Hasiqi());
		dogs.add(new Keji());
		
	}
}

11.2 基本概念

​ Java容器的用途是"保存对象",并将其分为两个不同大类

​ (1)Collection。 包括List、Set、Queue等接口。

​ List表示数据是有顺序的,Set则不可以有重复元素,Queue则按照规则来确定顺序

​ (2)Map, 由一堆键值对组成,通过字典的形式将其关联起来。

List<Dog> dogs = new ArrayList<Dog>();
List<Dog> dogs = new LinkedList<Dog>();
// 这里的List是接口, 接口可以指向其子类。

import java.util.Collection;
Collection<String> c = new ArrayList<String>();
c.add("abc");

11.3 添加一组元素

​ Arrays.asList()方法接受一个数组或者用逗号分割的元素列表(可变参数),将其转换为List对象

​ Collections.addAll()方法接受一个Collection对象,或者可变参数,将其添加到Collection中

import java.util.*;

public class Test {
	public static void main(String[] args) {		
		List<Integer> list = Arrays.asList(1,2,3,4,5);	
		Integer[] ins = {5,6,7,8};
		List<Integer> list2 = Arrays.asList(ins);
		
		Collection<Integer> coll = new ArrayList<Integer>(
				Arrays.asList(1,2,3,4,5) );
		Collections.addAll(coll, 1,2,3,4,5);
		Collections.addAll(coll,ins);
	}
}

11.4 容器的打印

​ 使用Arrays.toString()来进行打印

public class Test {
	public static void main(String[] args) {		
		Collection coll = new ArrayList<Integer>();
		coll.add("zhangsan");
		coll.add("lisi");
		System.out.println(coll);
		
		Map map = new HashMap();
		map.put("name","zhangsan");
		map.put("age",18);
		System.out.println(map);
	}
}
// 输出结果
// [zhangsan, lisi]
// {name=zhangsan, age=18}

List : 以特定的顺序保存元素

Set:不能存储重复元素

Queue: 只允许一端插入,另一端移出

ArrayList和LinkedList都是List类型

HashSet、TreeSet和LinkedHashSet都是Set类型。 HashSet使用哈希表存储,查询时间快。

HashMap、TreeMap、LinkedHashMap都是Map类型。

11.5 List

​ List接口在Collection的基础上添加了大量的方法。

​ ArrayList,随机查询元素快,但是插入和删除速度慢

​ LinkedList,随机查询元素慢,但是插入和删除快。

import java.util.*;
class Dog{} 
class Hasiqi extends Dog{}

public class Test {
	public static void main(String[] args) {		
		List<Dog> dogs = Arrays.asList(new Dog(),new Dog());
		
		Dog d = new Dog();
		dogs.add(d);//添加一个dog数据
		dogs.remove(d); //删除
		Dog hashqi = new Hasiqi();
		System.out.println(dogs.indexOf(hashqi)); //查看哈士奇的下标
		
		dogs.get(1); //获取元素
		dogs.add(1,new Dog()); //给指定位置添加
		List<Dog> sub = dogs.subList(1, 2);//获得子串
		dogs.containsAll(sub); //是否都包含
	}
}

11.6 迭代器

​ 为什么要使用迭代器?如果刚开始使用的是List编码,后来发现还需要应用于Set,那么就得重头开始编码。

​ 使用迭代器(Iterable)则没有这个问题。

​ Java的Iterable只能单向移动。使用iterator()来获得迭代器对象,使用next()获得下一个元素,使用hashNext()检查是否还有下一个,使用remove()来删除元素。

public class Test {
	public static void main(String[] args) {	
		
		List<Integer> list = new ArrayList<Integer>(
				Arrays.asList(1,2,3,4,5,6,7,8));
		Iterator<Integer> it = list.iterator();
		while(it.hasNext()) {
			Integer temp = it.next();
			System.out.println(temp);
		}	
	
	}
}

11.6.1 ListIterator

​ ListIterator是一个更加强大的Iterator的子类。

​ Iterator只能向前移动,但是ListIterator可以双向移动。

​ 可以通过listIterator(n)来指定起始位置

public class Test {
	public static void main(String[] args) {	
		
		List<Integer> list = new ArrayList<Integer>(
				Arrays.asList(1,2,3,4,5,6,7,8));
		ListIterator<Integer> it = list.listIterator();
		while(it.hasNext()) {
			Integer t1 = it.next();
			System.out.println(t1);
		}
		
		while(it.hasPrevious()) {
			Integer t2 = it.previous();
			System.out.println(t2);
		}
	}
}

11.7 LinkedList

​ LinkedList 在查询方面速度慢,但是插入和删除速度较快

​ LinkedList还添加了栈,队列,双端队列的方法

​ getFirst() 和 element()完全一样,返回第一个元素,若为空则抛出异常

​ peek() 返回第一个元素,为空则返回null

​ removeFirst() 和 remove() 完全一样,删除第一个元素,为空抛出异常

​ poll() 删除第一个元素,为空则返回null

​ addFirst() 与 add() 和 addList() ,将某个元素插入列表尾部

​ removeLast() 删除并返回最后一个元素

11.8 Stack

​ 栈,先进后出。 FILO

​ push() 入栈

​ pop() 出栈

​ peek() 返回栈顶元素

​ empty() 是否为空

11.9 Set

​ 保存不重复的元素

​ Set具有与Collection完全一样的接口,没有额外的功能。

public class Test {
	public static void main(String[] args) {	
		
		Set<String> set1 = new HashSet<String>();
		Collections.addAll(set1,"2","3");
		set1.add("4");
		System.out.println(set1);
	}
}

11.10 Map

​ 计算数字出现的次数

import java.util.*;
public class Test {
	public static void main(String[] args) {		
		Random rand = new Random(5);	
		Map<Integer,Integer> map = new HashMap<Integer, Integer>();
			
		for(int i=0;i<1000;i++) {
			int t = rand.nextInt(66);//生成0-66的随机数
			
			Integer f = map.get(t);
			if (f == null) {
				f = 0;
			}else {
				f += 1;
			}
			map.put(t,f);			
		}
		
		System.out.println(map);
	}
}

11.11 Queue

​ 队列是一个先进先出(FIFO)的容器,从一段放入事物,从另一端取出。

​ LinkedList提供支持队列的行为,且实现了Queuue接口。

Queue<Integer> queue = new LinkedList<Integer>();

​ offer() 方法插入列表尾

​ poll() 和 remove() 方法 删除列表头

​ peek() 和 element() 方法 返回队头

11.11.1 PriorityQueue

​ 优先级队列,优先弹出最需要的元素。

​ 使用offer()方法插入一个对象时,会在队列中被排序。

​ 可以通过自己的Comparator来修改这个顺序。

import java.util.*;
public class Test {
	public static void main(String[] args) {	
		PriorityQueue<Integer> pq = new PriorityQueue<Integer>();
		for(int i =10;i>0;i--) {
			pq.offer(i);
		}
		
		while(pq.peek() != null) {	
			Integer temp = pq.remove();
			System.out.println(temp);	
		}
		
	}
}
// 输出结果
// 1
// 2
// 3
// 4
// 5
// 6
// 7
// 8
// 9
// 10

11.12 Collection和Iterator

​ Collection时描述所有序列容器共性的根接口。

​ java.util.AbstractCollection 提供了Collection的默认实现(抽象类中的非抽象方法),可以创建AbstractCollection的子类型。

import java.util.*;
class Seq extends AbstractCollection<Integer>{

	private Integer[] int_list = {1,2,3,4,5};
	
	@Override
	public Iterator<Integer> iterator() {
		return new Iterator<Integer>() { //匿名内部类, 实现 Interator<Integer> 
			private int index = 0;
			@Override
			public Integer next() { //下一个数据
				return int_list[index++];
			}
			
			@Override
			public boolean hasNext() { // 判断是否有下一个数据
				return index < int_list.length;
			}
		};
	}

	@Override
	public int size() {
		return int_list.length;
	}
	
}


public class Test {
	public static void main(String[] args) {	
		Collection seq = new Seq();
		Iterator<Integer> it = seq.iterator();
		while(it.hasNext()) {
			Integer temp = it.next();
			System.out.println(temp);
		}
	}
}

11.13 Foreach与迭代器

​ (1)Foreach可以适用于任何Collection对象

import java.util.*;
public class Test {
	public static void main(String[] args) {	
		Collection<String> cs = new ArrayList<String>();
		Collections.addAll(cs, "long time no see".split(" "));//添加数据
		for (String str : cs) {//增强for循环
			System.out.println(str);
		}
		
	}
}

(2)继承Iterable之后,就可以使用Foreach增强for循环

import java.util.*;
class Hello implements Iterable<String>{
	private String[] str_list = {"a","b","c"};
	
	public Iterator<String> iterator(){
		return new Iterator<String>() {
			private int index =0;
			
			@Override
			public boolean hasNext() {
				return index < str_list.length;
			}

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

public class Test {
	public static void main(String[] args) {			
		for (String str : new Hello()) {
			System.out.println(str);
		}
		
	}
}

(3)循环map数据

public class Test {
	public static void main(String[] args) {			
		Map<String, String> map = new HashMap<String, String>();
		map.put("name", "zhangsan");
		map.put("age","18");
		
		for (Entry entry : map.entrySet()) {// entry是一个键值对, 对所有的键值对进行遍历
			System.out.println(entry.getKey()+":"+entry.getValue());
		}
		
	}
}

11.13.1 适配器方法惯用法

​ 如果想在Iterator的基础上,添加一个向后的方法,则可以使用适配器方法。

​ 适配器设计模式,通过继承,在原有的基础上添加一个向前迭代的foreach循环。

import java.util.*;
class NewArray<T> extends ArrayList<T>{
	
	public NewArray(Collection<T> c){//构造方法
		super(c);
	}
	public Iterable<T> reversed(){
		return new Iterable<T>() { //返回实现Iterable的匿名内部类
			@Override
			public Iterator<T> iterator() { //实现iterator方法
				return new Iterator<T>() { //返回匿名内部类
					int index = size()-1;

					@Override
					public boolean hasNext() {
						return index>-1;
					}
					
					@Override
					public T next() {
						// TODO Auto-generated method stub
						return get(index--);
					}
					
				};
			} // public Iterator<T> iterator()
			
		};	// return new Iterable<T>()
	}//Iterable<T> reversed()
}

public class Test {
	public static void main(String[] args) {			
		Collection<String> cs = new ArrayList<String>();
		Collections.addAll(cs, "a b c d e".split(" "));
		
		NewArray<String> n_list = new NewArray(cs);
		
		for (String str : n_list) {
			System.out.println(str);
		}
		for (String str : n_list.reversed()) {
			System.out.println(str);
		}
		
	}
}

11.14 总结

​ (1)数组的容量是事先确定的,但是容器则不需要事先确定

​ (2)Collection保存单一元素,Map保存键值对。

​ (3)数组和List都是排好序的容器,List能够自动扩充容量

​ (4)随机访问,使用ArrayList, 经常在表中间插入和删除,则使用LinkedList

​ (5)LinkedList提供实现Queue和栈的行为

​ (6)HashMap快速访问数据,TreeMap保持key的排序状态,LinkedHashMap保持元素插入的顺序

​ (7)Set不允许元素重复, HashSet查询速度快,TreeSet保持排序状态,LinkedHashSet保持插入的顺序

​ (8)不使用过时的Vector,Hashtable和Stack

其关系为

  1. Collection(接口)
    1. List(接口)
      1. LinkedList
      2. ArrayList
    2. Set(接口)
      1. LinkedList
      2. HashSet
        1. LinkedHashSet
      3. TreeSet
    3. Queue(接口)
      1. LinkedList
      2. PriorityQueue
  2. Map(接口)
    1. HashMap
      1. LinkedHashMap
    2. TreeMap

Collection可以生成Iterator

List可以生成ListIterator

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值