Java学习笔记——容器和泛型
容器
Java提供的一套容器类,其中基本类型是List、Set(集)、Queue和Map(映射),这些对象类型也称之为集合类。
列表( List ):数组方式实现,维护元素的索引顺序
– 对象按索引存储
– 可以存储重复元素
- 主要实现类
– ArrayList:动态数组
•遍历比较快,插入删除偏慢
– LinkedList:链表
•双向链表,遍历速度慢,快速插入删除
ArrayList
ArrayList就是动态数组,动态的增加和减少元素,可灵活的设置数组的大小
- 构造方法
– List list=new ArrayList();
– import java.util.List; import java.util.ArrayList; - 其他方法
–add(E e):将指定的元素添加到此列表的尾部 // E:任意的对象类型
–add(int index, E element):将指定的元素插入此列表中的指定位置
–remove(int index):移除此列表中指定位置上的元素
–remove(E e):移除此列表中指定元素
–get(int index):返回此列表中指定位置上的元素
–set(int index, E element):用指定的元素替代此列表中指定位置上的元素
–size():返回此列表中的元素数
–isEmpty():判断是否为空
–contains(E e):判断是否包含元素
对于动态数组,有人可能会使用Vector类
为什么用ArrayList取代Vector类?
Vector类的方法是同步的,同步操作将耗费大量时间
ArrayList类的方法不是同步的,故建议在不需要同步时使用
集合和数组之间的转换问题
//1.把集合(List,Set)转换为数组
Object[] objs=set.toArray();
//2.把数组转换成集合(List),需要依靠Arrays工具实现
List<Object> list=Arrays.asList(objs);
LinkedList
- 构造方法
–List names=new LinkedList();
–//import java.util.List; import java.util.LinkedList;
打印结果:
集(Set)是最简单的一种集合:关心唯一性
–对象无序存储
–不能存储重复元素,不维护元素的索引顺序
主要实现类
- HashSet:使用被插入对象的Hash码(效率最高),无序,不是同步的,底层通过散列函数来进行元素的存储。
- LinkedHashSet:继承于HashSet、又基于LinkedHashMap来实现,遍历性能比HashSet好,以元素插入的顺序来维护集合的链接表,在散列函数的基础上添加了链表支持。
- TreeSet:二叉树结构(通过红黑树生成二叉排序树),保证元素按照元素的自然顺序进行升序排序,添加操作速率比散列集慢,访问和遍历的时间很快
元素添加顺序:B、A、D、E、C、F
HashSet
- 构造方法
–HashSet(Collection<? extends E> c)):构造一个散列集,并将集合中的所有元素添加到这个散列集中
–Set name=new HashSet();
–import java.util.Set; import java.util.HashSet; - 其他方法
–add(E e):如果此 set 中尚未包含指定元素,则添加指定元素
–clear():从此 set 中移除所有元素
–remove(Object o):如果指定元素存在于此 set 中,则将其移除
–size():返回此 set 中的元素的数量(set 的容量)
–isEmpty():如果此 set 不包含任何元素,则返回 true
–contains(E e):判断是否包含元素
打印结果:
TreeSet
•构造方法
–TreeSet name=new TreeSet();
–import java.util.TreeSet;
–import java.util.Set;
•其他方法
–add():将指定的元素添加到此 set(如果该元素尚未存在 set 中)
–remove(Object o):将指定的元素从 set 中移除(如果该元素存在于此 set 中)
–first():返回此 set 中当前第一个(最低)元素
–last():返回此 set 中当前最后一个(最高)元素
–isEmpty():如果此 set 不包含任何元素,则返回 true
–size():返回 set 中的元素数(set 的容量)
打印结果:
LinkedHashSet
- 构造方法
–LinkedHashSet():构造一个带默认初始容量 (16) 和加载因子 (0.75) 的新空链接哈希 set - 其他方法
–包含继承自HashSet的方法:add, clear, isEmpty, remove, size
Queue接口
– java.util.Queue
队列是一种特殊的线性表,只允许在表的前端(front,队头)进行删除操作,而在表的后端(rear,队尾)进行插入操作
LinkedList实现了Queue接 口
- add(E e): 增加一个元素。成功时返回true,如果队列已满,则抛出一个IIIegaISlabEepeplian异常
- remove(): 移除并返回队列头部的元素。如果队列为空,则抛出一个NoSuchElementException异常
- Element(): 返回队列头部的元素。如果队列为空,则抛出一个NoSuchElementException异常
- offer(E e): 添加一个元素并返回true。如果队列已满,返回false
- poll(): 移除并返问队列头部的元素。如果队列为空,则返回null
- peek(): 返回队列头部的元素。如果队列为空,则返回null
- put(E e): 添加一个元素。如果队列满,则阻塞
- take(): 移除并返回队列头部的元素。如果队列空,则阻塞
Map接口
对象以键-值对(key-value)存储
key不允许有重复,value允许有重复
Map中元素,可以将key序列、value序列单独抽取出来
–使用keySet()抽取key序列,将map中的所有keys生成一个Set。
–使用values()抽取value序列,将map中的所有values生成一个Collection。(通常转成list)
HashMap
- HashMap是非线程安全的,无序
- 常用方法:
–put(K key,V value)
–get(Object K) //里面是key
–size()
–isEmpty()
–containsKey(K key)
–containsValue(V value)
–keyset()
–values()
打印结果:
TreeMap
– 基于红黑树实现
– 按照元素的自然顺序排序
打印结果:
LinkedHashMap
- 维护key值的插入顺序
打印结果:
迭代器(Iterator)
iterator()方法是java.lang.Iterable接口,被Collection继承。
- 主要功能:用于对容器的遍历
- Iterator:相当于指针,能够指向集合中的元素(在内存中通过索引表来记录元素的顺序,并在遍历过程中,对该索引表加锁,达到的效果是不允许在遍历过程中改变元素的顺序性),一般不对集合进行编辑操作(不进行添加操作,允许删除)
Iterator()得到Iterator对象,通过hasNext()方法判断是否遍历结束,通过next()方法移动到指针指向,即指向集合中的下一个元素 - 主要方法
–boolean hasNext():判断是否有可以元素继续迭代
–Object next():返回迭代的下一个元素
–void remove():从迭代器指向的集合中移除迭代器返回的最后一个元素
//遍历集合
//通过foreach结构遍历
for(Student stu:set) {
System.out.println(stu.getName());
System.out.println(stu.getAge());
}
//通过foreach结构遍历map
Map<Integer,Student> map=new HashMap();
map.put(1,lily);
map.put(2,Lucy);
System.out.println(map);
for(Entry<Integer, Student> entry:map.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
//通过索引遍历List
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i));
}
//使用Iterator遍历集合set
Iterator<Student> it=set.iterator();
while(it.hasNext()) {
Student stu=it.next();
if(stu.getName().equals("lily")) {
it.remove();
//set.add(new Student());运行时错误,不允许修改内存中索引顺序表
}
}
System.out.println(set);
//使用Iterator遍历map
Iterator<Integer> itinteger=map.keySet().iterator();//遍历所有key组成的set集合
Iterator<Student> itStudent=map.values().iterator();//遍历所有value组成的集合
Iterator<Entry<Integer,Student>> itEntry =map.entrySet().iterator();//遍历map集合中所有元素组成的set集合,集中每一个元素的类型是entry类型
while(itEntry.hasNext()) {
Entry entry=(Entry)it.next();
entry.getKey();//得到元素的key
entry.getValue();//得到元素的value
}
泛型(Generics)
所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型。
泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。
泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束。
- Java 中的泛型只接受引用类型作为类型参数。
–如:可以定义 List,不可以定义 List。 - 语法
class 名称<泛型列表>
如:class ArrayList< E >
–参数E是泛型,它可以是任何类或接口(除基本数据类型外) - 集合中使用泛型
List< E >
方法参数:
void do(List< Dog > dogs){…}
返回类型:
–List< Dog> getDogs(){…}
变量声明的类型必须匹配传递给实际对象的类型
使用通配符:
- 接受所声明变量类型的任何子类型
–void addAnimal(List<? extends Animal> animals)
–Animal可以是类或接口 - 接受父类型的变量
–void addAnimal(List<? super Dog> animals)
–接受super右边类型或其超类型 - List<?> 与List<? extends Object>完全相同
- List与List<?>完全不同
- 泛型通配符只能用于引用的声明中,不可以在创建对象时使用(不能出现在等号右面)
–Fruit<?> fruit=new Fruit<?>();×