与数组差别:数组固定长度,集合可变长度;集合中不可以存储基本数据类型。
集合中的共性内容(
框架的顶层)
在Collection(接口):
添加 add addAll
删除 remove removeAll clear
判断 contains
containsAll isEmpty
equals
获取 size iterator取出元素的方式,迭代器
其他 toArray retainAll取交集
2.迭代器
该对象必须依赖具体容器,所以迭代器对象是在容器内部实现的。对于使用容器者而言,具体实现不重要,只要通过容器获取该迭代器对象即可,即通过
iterator()方法。
I
terator接口就是对所有collection对象取出元素的公共接口。
内部类
/**
*
*/
package p4.collection.demo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
coll.add("abc4");
// java.util.Iterator it = coll.iterator();
// while(it.hasNext()){
// System.out.println(it.next());
// }
//结束后不需要it了,开发中用这种方法,这样做不占内存 ,
for(Iterator it = coll.iterator();it.hasNext(); ){
System.out.println(it.next());
}
}
}
3.Collection
---
List :有序(存入取出顺序一致),元素都有索引(角标),元素可以重复
---set : 元素不能重复,无序
List:---特有的常见方法:(特点)都可以操作角标
ListIterator
获取列表迭代器对象,可以实现在迭代过程中完成对元素
增删改查,只有list集合具有该功能
package p4.collection.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class ListDemo {
/**
* @param args
*/
public static void main(String[] args) {
List list = new ArrayList();
show(list);
}
public static void show(List list){
list.add("abc1");
list.add("abc2");
list.add("abc3");
System.out.println(list);
/*System.out.println(list);
list.add(1,"a");
System.out.println(list);
System.out.println(list.set(0, "a"));
System.out.println(list.subList(0, 2));
System.out.println(list.get(0));
*/
//Iterator it = list.iterator();迭代过程中不要使用集合操作元素,出现异常
ListIterator it = list.listIterator();//获取列表迭代器对象,可以实现在迭代过程中完成对元素
// 增删改查,只有list集合具有该功能
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("abc2")){
// list.add("abc5");迭代过程中不要使用集合操作元素,出现异常
it.set("abc8");
}
else
System.out.println(obj);
}
System.out.println(list);
}
}
---list子类:
Vector: 内部是数组数据结构,是同步的,现在几乎不用了
ArrayList:
内部是数组数据结构,
是不同步的,替代了
Vector,查询速度快(内存地址空间连续)
LinkedList:
内部是链表数据结构,
是不同步的。增删元素的速度很快
package p4.collection.demo;
import java.util.LinkedList;
/*
*用LinkedList模拟一个堆栈或则队列数据结构
*思路:
*1.堆栈:先进后出FILO,队列:FIFO
*2.描述这样一个容器,给使用者提供一个容器对象,其中利用到LinkedList的addfirst,removefirst以及removelast等方法。
*3.创建一个类,主函数调用
*/
class MyQueue{
private LinkedList link;
MyQueue(){
link = new LinkedList();
}
public void myAdd(Object obj){
link.addFirst(obj);
}
public Object myGet(){
return link.removeLast();
}
public boolean isNull(){
return link.isEmpty();
}
}
public class LinkedListTest {
/**
* @param args
*/
public static void main(String[] args) {
MyQueue q = new MyQueue();
q.myAdd("abc1");
q.myAdd("abc2");
while(!q.isNull()){
System.out.println(q.myGet());
}
}
}
ArrayList存储集合自定义对象。
package p4.collection.demo;
import java.util.ArrayList;
import java.util.Iterator;
import cn.itcast.p.bean.Person;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList al = new ArrayList();
al.add(new Person("jiao",22));
al.add(new Person("YJT",20));
al.add(new Person("TTTY",23));
Iterator it = al.iterator();
while(it.hasNext()){
Person p = (Person) it.next();//
ArrayList存储的是Object,不能直接it.next().getname(),Person类才有这方法System.out.println(p.getName()+","+p.getAge());
}
}
}
set接口中的方法和colloection一致。
---set子类:
Hashset
:存储无序,元素唯一,数据结构是哈希表。(
Hashset无序,因此,
LinkedHashSet)
哈希表:
确定元素是否相同:先判断哈希值hashCode(),再判断内容equals()。
存储自定义对象时,重新定义比较对象相同方法
package cn.itcast.p.bean;
public class Person extends Object implements Comparable {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/*
*以下重新定义比较对象的方法,用于hashset集合调用
*
*/
@Override
public int hashCode(){
return name.hashCode()+age*27;
}
@Override
public boolean equals(Object obj){
if(this == obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型错误");
Person p = (Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
@Override
public int compareTo(Object o) {
Person p = (Person)o;
int temp = this.age-p.age;
return temp==0?this.name.compareTo(p.name):temp;
/*if(this.age>p.age)
return 1;
if(this.age<p.age)
return -1;
return this.name.compareTo(p.name);*/
}
}
TreeSet:可对set集合中元素进行排序,是不同步的。判断元素唯一性即使根据比较方法的返回结果是否是0.
(二叉树结构)
对元素进行排序方法一:元素需要实现comparable接口,覆盖compareTo方法
如果不按照对象中具备的自然顺序进行排序或是对象中不具备自然顺序(对象根本不是我们肯定义的,我们无法修改),可以使用第二种排序方式二:让集合自身具备功能。比较器comparator(常用):定义一个类实现
comparator<T>接口,覆盖compare(T o1,T o2)方法,将该类对象作为参数传递给Treeset集合的构造函数。
4.Map
一次添加一对元素,双列集合,存储的是键值对,必须保证键的唯一性。
方法:
1.添加:value put(key,value):返回前一个与key关联的值,没有则返回空
2.删除:void clear()
value remove(key):根据指定的值翻出这个键值对
3.判断:boolean containsKey(key)
boolean containsValue(value)
boolean isEmpty()
4.获取: value get(Object key)
int size()
重要方法:
Set<K> keySet():返回键集合。再通过
迭代器
it.next()获取键以及
get(Object key)获取键值
Set<
Map.Entry<K,V>
> entrySet()
:返回映射关系,类型是Map.Entry。再获取迭代器(存储的是关系),调取getvalue以及getkey获取(将map转换为有迭代器的集合)
Collection<V> values():返回值集合
Map常用子类
|
---Hashtable:内部结构是哈希表,是同步的,不允许null作为键和值
|---Properties:用来存储键值对型的配置文件信息,可以和io技术相结合
|
---HashMap:
内部结构是哈希表,不是同步的。允许
null作为键,null作为值
|
---TreeMap:二叉树,不同步,可以对Map中的键进行排序
package p5.map.demo;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import cn.itcast.p.bean.Person;
public class HashMapDemo {
public static void main(String[] args) {
/*
* 将学生对象和学生的归属地通过键值存储在Map集合中。
*/
HashMap<Person,String> hm = new HashMap<Person,String>();
hm.put(new Person("srf",44),"北京");
hm.put(new Person("hjk",34),"上海");
hm.put(new Person("yti",77),"广州");
hm.put(new Person("hjk",34),"xinyu");//会覆盖“上海”
//Set<Person> keyset = hm.keySet();
//Iterator<Person> it = keyset.iterator();
Iterator<Person> it = hm.keySet().iterator();
while(it.hasNext()){
Person key = it.next();
String value = hm.get(key);
System.out.println(key.getName()+":"+key.getAge()+"--"+value);
}
}
}
package p5.map.demo;
import java.util.Map;
import java.util.TreeMap;
import java.util.Iterator;
import java.util.Set;
import cn.itcast.comparator.ComparatorByName;
import cn.itcast.p.bean.Person;
public class TreeMapDemo {
public static void main(String[] args) {
/*
* 将学生对象和学生的归属地通过键值存储在Map集合中。
*/
TreeMap<Person,String> hm = new TreeMap<Person,String>(new ComparatorByName());//Person类中用的是年龄排序,此处用名字排序,下面要新建一个比较器
hm.put(new Person("srf",44),"北京");
hm.put(new Person("hjk",34),"上海");
hm.put(new Person("yti",77),"广州");
Set<Map.Entry<Person, String>> es = hm.entrySet();
Iterator<Map.Entry<Person, String>> it = es.iterator();
while(it.hasNext()){
Map.Entry<Person, String> me = it.next();
Person key = me.getKey();
String value = me.getValue();
System.out.println(key.getName()+":"+key.getAge()+"--"+value);
}
}
}
package cn.itcast.comparator;
import java.util.Comparator;
import cn.itcast.p.bean.Person;
public class ComparatorByName implements Comparator<Person> {
@Override
public int compare(Person o1,Person o2) {
int temp = o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
5.泛型<>
jdk1.5出现的安全机制,泛型技术是给编译器使用的技术,用于编译时期,确保类型的安全。运行时会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除,因为为了兼容运行时的类加载器。但是有一个泛型补偿机制,在运行时通过获取元素类型进行转换,不需在使用时进行强制转换,保证能够识别取出元素。
好处:将运行时的问题ClassCastException转到编译时期,避免了强制转换的麻烦。
<>什么时候用?---当操作的数据类型不确定的时候,将要操作的引用数据类型传入即可。其实<>就是一个用于接收具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确具体引用数据类型,注意:integer是引用数据类型,int是基本数据类型
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<String>();
al.add("afre");
al.add("df");
Iterator<String> it = al.iterator();
while(it.hasNext()){
String str = it.next();
System.out.println(str);
}
自定义泛型类:
package p6.generic.demo;
/**
* @author dell
*功能:操作对象的工具类,是原来的做法
*/
/*
public class Tool {
private Object object;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
*/
//jdk1.5后,用泛型来接收类中要操作的引用数据类型,泛型类
public class Tool<Q>{
private Q q;
public Q getObject() {
return q;
}
public void setObject(Q q) {
this.q = q;
}
}
package p6.generic.demo;
/**
* @author hjj
*
*/
public class GenericDemo2 {
public static void main(String[] args) {
//原来做法
// Tool tool = new Tool();
//tool.setObject(new Person1());
// Person1 p = (Person1) tool.getObject();
Tool<Person1> tool = new Tool<Person1>();
tool.setObject(new Person1());
Person1 p = tool.getObject();//避免强转
}
}
泛型方法 将泛型定义在方法上 ,放在修饰符后,返回值前
public <W>void show(W str){
System.out.println("show:"+str);
}
//当方法静态时,不能访问类上定义的泛型,此时需要定义在方法上,如上
泛型接口:将泛型定义在接口上
泛型的通配符<?>
public static void main(String[] args) {
HashSet<String> al1 = new HashSet<String>();
al1.add("hjj");
al1.add("dg");
ArrayList<Integer> al2 = new ArrayList<Integer>();
al2.add(2);
al2.add(4);
printcollection(al1);
printcollection(al2);
}
/**
* 迭代并打印集合中元素
* @param al1
*/
private static void printcollection(Collection<?> al) {
Iterator<?> it =al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
泛型限定
1上限: <?
extends Person>表示只能接受Personl类或其子类,这就与Object区别开来(
Object所有都可以
)。如果上面例子中al1中存Person一个子类,al2存另一个。则需要用这个。
此时,可以写 Person p=it.next();
2下限: <? super Person>表示只接收Person类或其父类型
注意:一般在存元素时都使用上限,因为这样取出都是按照上限类型来运算,不会出现类型安全隐患。例如:API中collection的addAll()方法。
通常对集合中元素进行取出操作时,可以使用下限,例如:比较器,Person有两个子类,子类比较器中方法是使用Person的,所以可以用Person来接收子类比较。
集合的一些技巧:
需要唯一?
需要:Set
需要制定顺序?
要:Treeset 不:Hashset,但是想要一个和存储一致新的顺序(有序):linkedhashset
不需要:List
需要频繁增删?
要:linkedlist 不:arraylist
如何记录每一个容器的结构及所属体系?看名字
list
arraylist,linkedlist
set
hashset,treeset
后缀名就是所属体系,前缀名是数据结构
看到array想到数组,查询快,有角标
看到link,链表,增删快,add get remove+first last方法
看到hash,哈希表,唯一性,元素需要覆盖hashcode方法和equals方法
看到tree,二叉树,排序,两个接口comparable,comparator
而且通常这些集合容器都是不同步的