一、先来看两张图:
二、集合的分类:
2.1 Collection接口:
List接口:存储有序,可重复的元素 ,遍历出来的顺序与添加顺序相同
Set接口:存储无序(存储的元素是无序的(指的是元素在底层存放的位置无序)),不可重复的元素(不可
重复性:当向Set中添加相同的元素的时候,后面的这个不能添加进去), Set中常用的方法都
是Collection下定义的
2.2 Map接口:
注:Map接口不是Collection接口的子接口, 两者是并列关系
三、关于List接口:
3.1 List接口:
存储有序,可重复的元素 遍历出来的顺序与添加顺序相同
3.2 具体的实现类:
①: ArrayList(主要的实现类)
②: LinkedList(对于频繁的插入,删除操作 较适用)
③: Vector(古老的实现类,线程安全的,但效率低于ArrayList)
四、关于Set接口:
4.1 需要注意的是:
①: 通常说的" Set是无序的, 不可重复的 " 这句话中的无序是指的**存储无序. **
②: 无论是HashSet,还是LinkedHashSet 存储都是无序, 且不可重复的元素((指的是元素在底层存放的位置无序))
③: **遍历是分为有序和无序的 **, HashSet遍历是无序的,不是按照添加的顺序遍历, 而LinkedHashSet遍历是有序的,按照添加的顺序遍历.
4.2 如何保证set中元素不可重复?
要求添加进Set中的元素所在的类,一定要重写equals()和hashCode()方法.
让equals方法比较的是值而不是比较地址(Object类是任何类的父类,equals方法是Object类中的方法),
重写hashCode()方法让同一个对象能算出相同的hashCode值, 进而保证Set中元素的不可重复性, 注意:List只用重写equals方法就可以了
4.3 Set中元素是如何存储的呢?
使用了哈希算法
当向Set中添加对象时,首先调用此对象所在类的hashCode()方法,计算此对象的哈希值,此哈希值决定了此对象在Set中的存储位置(通过这样保证无序)。若此位置之前没有对象存储,则这个对象直接存储到此位置,若此位置已有对象存储,再通过equals方法比较这两个对象是否相同,如果相同返回true,则后一个对象就不能添加进来(通过这样保证不可重复).
要求:hashCode()方法要与equals()方法一致(也就是说: 同一个类的两个对象,如果属性都相同,那么算出来的两个对象的hashCode值应该相同,且equals方法返回值应该为true; 如果属性不相同,那么算出来的两个对象的hashCode值应该不相同,且equals方法返回值应该为false; )
万一 一个类的两个对象属性不同却算出相同的hashCode值,且equals方法返回false,那么都存储到同一个位置(不建议如此)
4.4 具体的实现类:
①: HashSet(主要的实现类)
②: LinkedHashSet(HashSet的子类)
③: TreeSet(是SortedSet接口的实现类,而SortedSet接口是Set的子接口)
注: 一个TreeSet对象必须存储同一种数据类型( 例如:不能既存储Integer 又存储String类型)
4.4.1 关于TreeSet:
当向TreeSet中添加自定义类的对象时,有两种排序方法:①自然排序②定制排序
①自然排序:(实现comparable接口,并重写compareTo方法)(从小到大,从大到小排序)
②定制排序:(实现Comparator接口,重写compare方法)
**两种排序的区别: **
前者要求在自定义类中实现java.lang.Comparable接口并重写其compareTo(Objecto)方法
后者可以在方法中创建一个实现了Comparator接口的类对象(匿名内部类),并重写compare方法.
向TreeSet中添加元素时,首先执行元素所属类的compareTo方法比较元素,一旦返回0,虽然仅是两个对象的此属性组相同,但是程序会认为这两个对象相同,进而后一个对象不能添加进来
注: 只有当compareTo比较后得两个对象不相同时,再调用执行元素所属类的hashCode方法,最后调用equals方法 compareTo()与hashCode()以及equals()三者保持一致!
五、关于Map接口:
5.1 Map接口元素的存储原理:
Map接口中的key是用set存放的,不许重复,也就是说同一个Map对象所对应的类,**需要重写hashCode和equals方法, ** 进而保证Set中元素的不可重复性, value是用Collection来存放的可以重复
例如:
向HashMap中添加元素时,会调用key所在类的equals()方法,判断两个key是否相同,若相同 ,则只能添加进后添加的那个元素(后面的会覆盖前面的,这个与HashSet不同,HashSet是后面的那个不能添加进来)。
5.2 遍历Map:
有三类,分别是遍历key,遍历value,遍历key-value对
//1.遍历key集
Set set = map.keySet();
//2.遍历value集
Collection values = map.values();
//3.遍历key-value对
Set set2 = map.entrySet(); //所有entry的集合就是entrySet
for (Object obj:set2) { //遍历entrySet得到entry
Map.Entry entry = (Map.Entry)obj; //获取entry
//System.out.println(entry.getKey()+"------>"+entry.getValue()); //分别获取entry中的键 和 值
System.out.println(entry);
}
5.3 Map的初始化:
不能初始化为: Map<String,List>map=null;
而要用new对象的方式:Map<String,List>map=newHashMap<String,List>();否则会报错
5.4 从map中取值:
正确方法:
方法一: String str = String.valueOf(map.get("键名"));
方法二:
String str = (String) map.get("ACCEPT_CHANNEL");
if (null != str && !"".equals(str)) {
…………
}
错误的取值方法:
String str = map.get("键名").toString; //如果键对应的值不存在即为null,那么再调用tostring()方法时,就会抛出空指针异常
注: Map中的Key value可以是任何引用类型的数据
5.5 Map接口的具体实现类:
①: HashTable : 古老的实现类,线程安全,不建议使用
②: HashMap:
③: LinkedHashMap(是HashMap的子类)
④: TreeMap:(实现了SortedMap接口,而SortedMap接口是Map的子接口)
5.5.1 Properties介绍:
Properties:是Hashtable的子类,常用来处理属性文件。键和值都为String类型的
读取属性文件jdbc.properties:
Properties pros = new Properties();
FileInputStream fi = new FileInputStream(new File("jdbc.properties"));
pros.load(fi);
读取xml配置文件config.xml:
Properties properties = new Properties();
InputStream configInputStream = new FileInputStream("config/config.xml");
properties.loadFromXML(configInputStream);
六、关于Collections 工具类:
6.1 作用:
操作Collection以及Map
6.2 注意:
区分Collection与Collections
6.3 实现list的复制:
//错误的方式:出现java.lang.indexOutOfBoundsException
//List list1=new ArrayList();
//Collections.copy(list1,list);//list1长度为0,list长度为5,所以无法将list复制到list1
//System.out.println(list1);
//正确的方式
List list2 = Arrays.asList(newObject[list.size()]);
Collections.copy(list2,list);
System.out.println(list2);//[123,456,12,78,456]
6.4 考虑线程安全问题:
List 是线程不安全的, synchronizedList方法可以保证List线程安全
//通过如下的方法保证list的线程安全
List list3=Collections.synchronizedList(list);
System.out.println(list3);
6.5常用函数:
reverse(List):反转List中元素的顺序
shuffle(List):对List集合元素进行随机排序
sort(List):根据元素的自然顺序对指定的List集合元素按照升序排序
sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
swap(List,int,int):将指定list集合中的i处元素和j处元素进行交换
void copy(List dest,List src)://将src中的内容复制到dest中
七、集合的遍历方法:四种
①使用Iterator迭代器
②增强型for循环
③普通for循环
④Iterator迭代器的"古老版本"Enumeration 接口
//Enumeration 接口是Iterator迭代器的"古老版本"
public class TestEnumeration {
public static void main(String[] args) {
Enumeration enu = new StringTokenizer("ab-c*-df-g", "-");
while(enu.hasMoreElements()) {
System.out.println(enu.nextElement());
}
}
}
//面试题
@Test
public void test5(){ //结果: 输出MM MM MM AA BB DD
String[]str=new String[]{"AA","BB","DD"};
//表示每次从str中取出一个元素赋给局部变量s,所以s值的修改,并不影响str中的值
for(String s:str){ //每循环一次, s都是一个新的局部变量
s="MM";
System.out.println(s);
}
for(int i=0;i<str.length;i++){
System.out.println(str[i]);
}
}
八、关于数组:
存储对象可以考虑:①数组,②集合
数组存储对象的特点:Student[] stu = new Student[20]; stu[0]=new Student();…
弊端:①一旦创建,其长度不可变. ②真实的数组存放的对象的个数是不可知的
九、总结:
①: 单类型: 一个TreeSet对象必须存储同一种数据类型,例如: 不能既存储Integer 又存储String类型, 而HashSet和LinkedHashSet可同时存多种数据类型.
②: 一致性: 使用TreeSet时: compareTo()与hashCode()以及equals()三者保持一致!
③: 执行流程: 向TreeSet中添加元素时,首先执行元素所属类的compareTo方法比较元素,一旦返回0(表示相同),虽然仅是两个对象的此属性组相同,但是程序会认为这两个对象相同,进而后一个对象不能添加进来 .只有当compareTo比较后得两个对象不相同时,再调用执行元素所属类的hashCode方法,最后调用equals方法
④: 顺序性: Set而言:元素在底层存放的位置无序(即存储无序),List而言: 元素存储在连续的地址空间(即存储有序)
Set而言: 遍历是分为有序和无序的 , 其中HashSet遍历是无序的,不是按照添加的顺序遍历, 而LinkedHashSet遍历是有序的,按照添加的顺序遍历.