讲到集合,大家可能不会很陌生,集合就是用来存放对象的引用,例如选课系统,你得
知道里面有什么可以选的课程,那么这些选的课程就被放在了一个集合当中,而每一个
对象又有各自的属性。。
在讲之前先看一张类图,更容易理解大体内容:
这是java集合类的体系图,很容易看出,Collection类和Map类一丁点关系都没有,很
多人在学的时候会混淆这两个之间有什么关系,要清楚这一点。
Collection类是存放单对象元素的祖先类,下面有Set和List两个接口,Set里面插入对象
不允许有重复元素,没有下标,没有顺序,List相反,可以有重复元素,有下标,有顺
序。
先来看看List,List有两个实现子类,ArrayList和LinkedList。
ArrayList中底层是数组形式,连续的存储空间,适合查询和遍历,速度优先。
涉及到集合存放元素,无非是添加,移除等操作,ArrayList中常用方法有这些:
.add()//用来添加对象
.add(int index, E element);//指定某个位置添加对应的对象。
.remove()//可以是删除的位置序号,可以是对象
// list.remove(new Integer(1));删除Integer为1的对象(Integer和int系统会自动转换)
//list.remove(1); 删除1号位置的对象(从0开始存放对象)
.size()//获得容器中的大小。(对象的个数)
.get()//获得某个位置上的元素(对象)
.clear()//清空该容器
.isEmpty()//判断该容器是否为空。
.set(int index, Object o)//替换index位置上的元素,用o这个对象代替。
.contains()//判断容器中是否包含某个对象。
LinkedList中底层是链表形式,存入对象本身和下一个对象的地址,存储空间不连续,
多适用于插入,移除,速度要优先。
LinkedList拥有ArrayList中的所有方法,还有属于自己的方法(因为是链表存储):
.addFirst()//在头号位置添加元素。
.addLast()//在尾部位置添加元素
.getFirst()//获得头号元素
.getLast()//获得末尾元素
.removeLast()//移除末尾元素
.removeFirst()//移除头号元素
List容器中存入元素,自然有遍历整个容器的方法,遍历就是访问每一个元素对象,List
中有4种遍历方式:
1、get方法
for (int i = 0; i < list.size(); i++) {
String str = (String) list.get(i);
System.out.println(str);
}
2、转化为数组形式
Object o[] = list.toArray();
for (int i = 0; i < o.length; i++) {
String str= (String) o[i];
System.out.println(str);
}
3、for-each
for(Object o : list)
{
String str = (String) o;
System.out.println(str);
}
遍历list中每一个元素对象。
4、游标法
for(Iterator it = list.iterator();it.hasNext(); )
{
Object o = it.next();//自动向下移动
String str = (String) o;
System.out.println(str);
}
这四种的比较:
1、 for需要知道集合或数组的大小,而且需要是有序的,不然无法遍历;
2、 foreach和iterator都不需要知道集合或数组的大小,他们都是得到集合内的每个元
素然后进行处理;
3、 for和foreach都需要先知道集合的类型,甚至是集合内元素的类型,即需要访问内
部的成员,不能实现态;
4、 iterator是一个接口类型,他不关心集合或者数组的类型,而且他还能随时修改和删
除集合的元素,
用法差别:
for循环一般用来处理比较简单的有序的,可预知大小的集合或数组
foreach可用于遍历任何集合或数组,而且操作简单易懂,他唯一的不好就是需要了解集
合内部类型
iterator是最强大的,他可以随时修改或者删除集合内部的元素,并且是在不需要知道元
素和集合的类 型的情况下进行的(原因可参考第三点:多态差别),当你需要对不同的
容器实现同样的遍历方式时,迭代器是最好的选择!
在List中,有Collections工具类的常用方法:
.sort()//Collections.sort(list);//升序排列
.swap()//Collections.swap(list, 0, list.size()-1);交换指定位置的数
.reverse()//Collections.reverse(list);反转
List结束,接下来是Set集合。
Set同样也是个接口,有两个实现类HashSet和TreeSet。
HashSet中的底层是散列值,根据hash算法得出,更多用于遍历。
常用方法:
.add()
.remove()
.size()
.contains()
.isEmpty()
.clear()
TreeSet中底层是二叉树,更多用于插入,移除。
TreeSet中存放元素对象比较苛刻,一般存入String,Integer对象,也可以存入自定义
的类型,必须实现Comparable接口和存入同一种类型。
存入要求:
1.必须实现Comparable 接口
2.容器中存放同一种类型
特点:
1、add存放进去的元素对象自动实现升序.按照自然顺序排列(Integer(int)类型是按
数字大小,String类型是按字典顺序排列)。
2、拥有更多强大的方法,实现一系列比较大小方法
常用方法:
.ceiling()//返回容器中比指定的元素对象大于或者等于的最小元素
.higher()//返回容器中比指定的元素对象大于的最小元素
.floor()//返回容器中比指定的元素对象小于或者等于的最大元素
.lower()//返回容器中比指定的元素对象小于的最大元素
.tailSet()//返回容器中大于指定元素的set元素集合
.subSet(E fromElement,boolean bo, E toElement,boolean bo1)
//返回容器中比指定元素大于等于fromElement,小于toElement中的set元素集合。
算头不算尾,若有4个参数的,是否包含头或尾,包含为true,不包含为false。
.first()//返回容器中最小的对象
.last()//返回容器中最大的对象
.descendingIterator()//容器中的元素逆序排列的游标对象。
由于是set集合中的方法,无序,无下标,自然没有get方法获得对应位置的元素。
Set集合的遍历方式有3种(无法通过get方法获得):
1、转化为数组
2、for-each结构
3、iterator游标
容器中 怎么判断两个元素一样?
调用了元素的hashcode和equals 共同判断:
1、对象的hashcode值相同
2、对象的equals返回true
两点相同则对象相同。
之前有说,Collection中都是单对象存储的,和它并排的Map是以两个对象,即Key–
Value键值对存储的。
Map是Key-Value以键值对的方式存入容器。
一个key对应的一个value,好比一个身份证对应一个名字。
Map同样有两个类HashMap和TreeMap,TreeMap工作几乎不会用到,这里只说
HashMap。
HashMap中存放的元素仍然是无序的,既然人们要用K–V键值对来对Map集合操作,那
么就不会通过顺序寻找对象了 ,而是通过Key来寻找对应的Value。
常用方法:
.put(K key, V value)//存放元素
.remove(key)//通过对应的key,连同Value一块移除。
.get(key)//根据key获得对应的value
.size()//获得容器大小
.containsKey()//判断该容器是否存在对应的key
.containsValue()//判断该容器是否存在对应的value
.keySet()//返回所有key的set集合
.values()//返回所有value的Collection集合
遍历方法有两种:
1、通过keySet集合找value
通过key集合找value
Set<String> s = hm.keySet();
for (String key : s)
{
String v = hm.get(key);
System.out.println(key+”=”+v);
}
2、调用entryset方法将key=value包裹成set集合
调用entryset方法将key=value包裹成set
Set s1= hm.entrySet();
for (Object o : s1)
{
System.out.println(o);
}
Map中的K,V实际上是泛型,那究竟什么是泛型呢?
看一个代码:
public class Person<K,T,E>()
{ private K name;
private T age;
private E addr;
public Person(K name,T age,E addr)
{
this.name = name;
this.sex = sex;
this.age = age;
}
}
Person p<String,Integer,String> p = new Person("zhangsan",12,"1haolou");
在实例化对象时候定义的是什么类型,之后的类型就是什么类型。
定义的name是String类型,age是Integer类型,addr是String。
泛型更多的是用于容器。
List<String> list=new ArrayList<>();
list只能放字符串对象,定义成什么类型,就只能存放哪种类型。后面的泛型可以省略不
写。