使用普通的容器是不安全的,因为什么都可以放进去,没有限制,拿出来转换也没有限制,所有都需要程序员自己判断;如ArrayList al = new ArrayList();
我们用案例来说明,以下是实验代码
package com.JavaSE06.demo01;
import java.util.ArrayList;
class Apple{
private static long counter;
private final long id=counter++;
public long id (){
return id;
}
}
class Orange{
}
public class AppleAndOrangesWithoutGenerics {
public static void main(String[] args) {
//这个普通容器是不安全的
ArrayList apples = new ArrayList();
for (int i = 0; i < 3; i++) {
apples.add(new Apple());
}
apples.add(new Orange());
for (int i = 0; i < apples.size(); i++) {
//这条语句会报错,因为ArrayList存储了不同类型的对象
//因为Orange不能转换成Apple
//因为ArrayList没有限制,什么类型都可以放,所以是不安全的;所有的限制都需要人为的指定
System.out.println( ((Apple)apples.get(i)).id());
}
}
}
以下是使用泛型的容器,是安全的。
package com.JavaSE06.demo01;
import com.JavaSE02.demo02.Array;
import java.util.*;
public class AppleAndOrangleWithGenerics {
public static void main(String[] args) {
//使用泛型的安全容器
//我们使用泛型是为了限制进入容器的对象类型
ArrayList<String> alstrs = new ArrayList<String>();
alstrs.add("china");
alstrs.add("USA");
for (int i = 0; i < alstrs.size(); i++) {
System.out.println(alstrs.get(i));
}
System.out.println("------------------------------------------");
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++) {
System.out.println(apples.get(i).id());
}
System.out.println("************");
for(Apple c:apples){//这种是针对容器的打印方式
System.out.println(c.id());
}
}
}
同时使用泛型的容器允许我们实现向上转型
package com.JavaSE06.demo01;
import java.util.*;
class GrannySmith extends Apple{ }
class Gala extends Apple{}
class Fuji extends Apple{}
class Bracburn extends Apple{}
public class GenericesAndUpcasting {
public static void main(String[] args) {
ArrayList<Apple> apples = new ArrayList<Apple>();
apples.add(new GrannySmith());
apples.add(new Gala());
apples.add(new Bracburn());
apples.add(new Fuji());
for (Apple apple : apples) {
System.out.println(apple.id());
}
}
}
###容器类的基本概念
Java容器类的用途是保存对象,并把它划分为两个不同的概念:集合和映射
集合是一个独立元素的序列,这些元素都符合一条或多条规则;
以下是Collection继承图
ArrayList中的一些常用操作
以下是实验代码
package com.JavaSE06.demo02;
import java.util.*;
public class AddingGroups {
public static void main(String[] args) {
//Arrays是集合的一个工具类,提供了很多方法给我们用
Collection<Integer> c = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
Integer [] moreInts = {6,7,8,9,10};
//需要先将数组转换成集合对象
c.addAll(Arrays.asList(moreInts));
//collections是工具类,提供了很多操作集合的方法
Collections.addAll(c,11,12,13,14,15);//批量添加 方式1
Integer [] moreInts2 = {16,17,18,19,20};
Collections.addAll(c,moreInts);//传数组 批量添加 方式2
for(Integer i:c) System.out.print(i+",");
System.out.println();
List<Integer> list= Arrays.asList(1,2,3,4,5);
list.set(1,99);//list.set(index,element) 这是list自己的方法,它可以有父类的方法,也有自己的方法
for (Integer integer : list) {
System.out.print(integer+",");
}
}
}
List中的几种赋值方式
package com.JavaSE06.demo02;
import java.util.*;
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) {
List<Snow> snowList1=Arrays.asList(new Crusty(),new Slush(),new Powder());
//ArrayList是List下的一个子类
List<Snow> snowList2 = new ArrayList<Snow>();
Collections.addAll(snowList2,new Light(),new Heavy());//使用Collections工具类添加
List<Snow> snowList3 = new ArrayList<Snow>(snowList1);//初始化时添加
Snow [] sa =new Snow[snowList2.size()];
Collections.addAll(snowList3,snowList2.toArray(sa));//使用工具类添加,区别于上面 是先把list转换为数组
List<Snow> snowList4 = Arrays.<Snow>asList(new Light(),new Heavy());//在初始化时,显式指定类型
for(Snow s:snowList1) System.out.print(s);
System.out.println();
for(Snow s:snowList2) System.out.print(s);
System.out.println();
for(Snow s:snowList3) System.out.print(s);
System.out.println();
for(Snow s:snowList4) System.out.print(s);
System.out.println();
}
}
以下是实验代码
package com.JavaSE06.demo02;
import java.util.*;
public class PrintngContainers {
public static void main(String[] args) {
System.out.println(fill(new ArrayList<String>()));
System.out.println(fill(new LinkedList<String>()));
//set这一分支是不允许重复的,
System.out.println(fill(new HashSet<String>()));//hash算法底层
System.out.println(fill(new TreeSet<String>()));//底层是树
System.out.println(fill(new LinkedHashSet<String>()));//链表和hash算法
System.out.println("------------------------------------------");
//map这一分支是键值对对象
System.out.println(fill(new HashMap<String, String>()));
System.out.println(fill(new TreeMap<String, String>()));
System.out.println(fill(new LinkedHashMap<String, String>()));
}
static Collection fill(Collection<String> collection){
collection.add("rat");
collection.add("cat");
collection.add("dog");
collection.add("dog");
return collection;
}
static Map fill(Map<String,String> map){
map.put("rat","Fuzzy");
map.put("cat","Rags");
map.put("dog","Bosco");//这个会被覆盖
map.put("dog","Spot");
return map;
}
}
List是一个接口底下有两个子类:ArrayList和LinkedList
ArrayList底层是数组,支持随机访问,但增删慢
LinkedList底层是链表,增删快,访问较慢。
如果有频繁的查询操作,则用ArrayList;否则,用LinkedList
以下是实验代码
package com.JavaSE06.demo03List;
import java.util.*;
public class ListFeatures {
public static void main(String[] args) {
List<Integer> list =new ArrayList<Integer>();
list.add(1);
list.contains(1);//集合从是否包含指定对象
list.indexOf(1);//查看对象索引
list.get(1);//得到对象
list.remove(1);//删除一个对象,当对象不存在时,返回false
list.add(1,new Integer(2));
List<Integer> integers = list.subList(0, 2);//截取子list;指出哪里开始哪里结束 list.[fromIndex,toIndex)
list.containsAll(integers);//判断是否包含此子串,对象本身的比较;即使是打乱顺序,对象(引用)一样的话,返回ture
Collections.sort(integers);//使用工具类排序
Collections.shuffle(integers);//打乱顺序,会打乱其引用;如果多个list对象指向同一片空间,那么都会受到影响。
List<Integer> copy =new ArrayList<Integer>(integers);
List<Integer> list2 =Arrays.asList(copy.get(0),copy.get(1));//另一种初始化方式
copy.retainAll(list2);//保留两者都共有的对象
copy.retainAll(list);//删除子集合
copy.set(1,2);//将制定index的element重新赋值
copy.addAll(2,list);//从指定的index开始添加元素,index后的元素往后移动list.length位
copy.isEmpty();//判断list集合是否为空
Object[] objects = copy.toArray();//将list集合转为数组
}
}
由于容器的种类有很多,而且每种容器的特点都不一样,如ArrayList底层是一个数组,LinkedList底层是链表,很多时候不知道怎么去遍历容器。所以我们需要有一个迭代器去实现对容器的遍历。
迭代器在java中是一个对象,它的工作是遍历容器;
迭代器有两种:Iterator和ListIterator
Iterator只能够单向移动
ListIterator可以双向移动,还可以指定开始遍历的位置;它是Iterator的子类,对基类进行了扩展。
一个简单迭代器的使用案例
public class SimpleIteration {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,12);
//得到一个普通迭代器,得到数据
Iterator<Integer> it =list.iterator();
while(it.hasNext()){
Integer next = it.next();
System.out.print(next+" ");
}
System.out.println();
//时候循环得到数据
for (Integer integer : list) {
System.out.print(integer+" ");
}
System.out.println();
System.out.println("---------分割线------------------");
}
}
使用迭代器遍历不同类型的容器
public class CrossContainerInteration {
public static void display(Iterator<String> it){
while(it.hasNext()){
String next = it.next();
System.out.print(next+" ");
}
System.out.println();
}
public static void main(String[] args) {
//如果要考虑顺序,就用list底下的容器
ArrayList<String> list = new ArrayList<String>(Arrays.asList("cat","dog","pug","yellow dog","big cat"));
LinkedList<String> link = new LinkedList<String>(list);
HashSet<String> hs=new HashSet<String>(list);
TreeSet<String> ts = new TreeSet<String>(list);
display(list.iterator());
display(link.iterator());
//可以看到set容器是无序的。
//如果只考虑容器速度,可以用set
display(hs.iterator());
display(ts.iterator());
}
}
ListIterator的简单使用案例
package com.JavaSE06.demo04Iterator;
import java.util.*;
public class CrossContainerInteration {
public static void display(Iterator<String> it){
while(it.hasNext()){
String next = it.next();
System.out.print(next+" ");
}
System.out.println();
}
public static void main(String[] args) {
//如果要考虑顺序,就用list底下的容器
ArrayList<String> list = new ArrayList<String>(Arrays.asList("cat","dog","pug","yellow dog","big cat"));
LinkedList<String> link = new LinkedList<String>(list);
HashSet<String> hs=new HashSet<String>(list);
TreeSet<String> ts = new TreeSet<String>(list);
display(list.iterator());
display(link.iterator());
//可以看到set容器是无序的。
//如果只考虑容器速度,可以用set
display(hs.iterator());
display(ts.iterator());
}
}
LinkedList 可以被当做栈,队列,双端队列来使用;当有频繁的增删操作时,推荐使用LinkedList。
以下是一些简单的使用方法
package com.JavaSE06.demo05LinkedListAndStack;
import java.util.*;
public class LinkedListFeatures {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<String>(Arrays.asList("dog","cat","big dog","big cat","dragon"));
System.out.println(list);
//获取集合第一个元素的三种方式
System.out.println("list.getfirst: "+list.getFirst());
System.out.println("list.element()"+list.element());
System.out.println("list.peek()"+list.peek());
//删除集合中的元素 三种方式
System.out.println("list.remove() "+list.remove());
System.out.println("list.removeFirst() "+list.removeFirst());
System.out.println("list.poll() "+list.poll());//常用在栈场景中
System.out.println(list);
//表头插入
list.addFirst(new String("Yellow Cat"));
System.out.println("After addFirst"+list);
//表尾插入的三种方式
list.offer("Blue Dog");
System.out.println("After offer"+list);
list.add("green Dog");
System.out.println("After add"+list);
list.addLast("green Dog");
System.out.println("After addLast"+list);
//删除表尾元素 返回被删除的元素
System.out.println("After removeLast "+list.removeLast());
}
}
使用LinkedList实现一个简单的Stack
//MyUtil包下自己写的栈
import java.util.LinkedList;
//Stack : First in Last out
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();}
}
import com.JavaSE06.demo05LinkedListAndStack.MyUtil.Stack;
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);
}
System.out.println(stack);
while(!stack.empty()){
System.out.print(stack.pop()+" " );
}
}
}
一组成对的键值对对象,允许使用键来查找值;也被称为关联数组,有时候也被称为字典
Map是没有顺序的。