集合框架
- 数组、对象数组、集合框架的特点与区别
特点:
- 数组:用于存放同一基本数据类型元素的组合
- 对象数组:用于存放同一对象类型元素的组合
- 集合框架:动态的对象数组
区别:
数组不能动态扩张,定义时必须指定长度;集合则无需指定长度,可动态扩张
- 为什么需要集合框架
如果不知道程序运行多少时需要多少对象,或者需要更复杂方式存储对象,可以使用集合框架。Collection集合框架用来存储和操作不同类型的对象组。
- 集合框架体系
- Collection接口
Collection主要三个子接口
List----表示允许有重复元素的集合
Set----表示不允许有重复元素的集合
Queue——队列,JDK1.5新增,与上面两个集合类主要是的区分在于Queue主要用于存储数据,而不是处理数据。队列是一种特殊的线性表,先进后出。
Stack——继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。基本的push和pop方法,还有peek方法得到栈顶的元素,empty方法测试堆栈是否为空,search方法检测一个元素在堆栈中的位置。Stack刚创建后是空栈。
- List接口
List集合的特点:
- 和数组类似,但可以动态增长
- 有序,对象可以重复
- 查找元素效率高,增加删除元素效率低(会引起其他元素位置变化)
遍历方式
- for循环
- foreach
- 迭代器 Iterator
List集合下有三个子接口
- ArrayList:动态数组,线程不同步的,查询速度快,但是增删慢。
默认长度为0,初始容量为10,50%延长,增长方式:n*3/2+1
相对节约空间
- LinkedList:链表,队列,堆栈,查询慢,增删快
- Vector:是一种老态的动态数组,是线程同步的,安全但效率低,一般不赞成使用。
长度为10,当超过10时,100%延时,变为20个(浪费空间)
2.1 ArrayList使用
2.1.0 ArrayList优化
其实ArrayList也是一个对象数组,只不过是一个动态对象数组,在他方法里我们可以看到他是一个对象数组,而且他的长度为0
为什么需要优化
因为ArrayList在被创建的时候初始容量为10,但长度为0,所以当你第一次添加的时候ArrayList是不会添进去,他会在内部自己扩容(扩升容量,第一次是初始容量为10,往后就是 (当前容量+当前容量*0.5)或(n*3/2+1)),这会影响性能,所以需要对他进行优化
怎样优化
Java程序优化:
(java程序的意思,对java代码进行优化,还有数据库优化等等)
在创建ArrayList的时候指定一个合适的初始容量,在做分页查询的时候可以使用
2.1.1声明
ArrayList<E> al=new ArrayList<E>();
*******************************************
a. ArrayList 默认长度为0, 容量10;
b. <E> 泛型,泛型可以为任何类型的对象,但不包括基本类型。
作用:它的好处在于存储时可以自动检查存入类型的合法性
取出时(get)可以自动转型成对应的类型
c. 增长方式: *3/2+1 (记住,面试时可能问到)
2.1.2 追加
boolean add(E e); //将指定的元素添加到此列表的尾部
void add(int index, E element); //将指定的元素插入此列表中的指定位置
boolean addAll(Collection); //将集合中的数据追加到另一个集合后面
boolean addAll(int index, Collection); //将Collection指定追加到位置之后
2.1.3 移除
void clear(); //移除集合中所有的元素
E remove(int index); //移除此列表中指定位置上的元素。
boolean remove(Object o); //移除此列表中首次出现的指定元素(如果存在)。
void removeRange(int fromIndex, int toIndex); //移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。
2.1.4 修改(替换)
Object set(index, element); //将index位置的对象替换成element
2.1.5 获取:
E get(int index); //返回集合中指定位置的对象
List subList(fromIndex, toIndex); //截取子集合
2.1.6 判断:
boolean contains(Object o); //集合中是否包含该元素,需重写equals(比较整体)
boolean containsAll(Collection c); //比较的是集合中的值,是否包含子集合中的内容(比较内容)
boolean isEmpty(); //如果此列表中没有元素,则返回 true
int indexOf(Object o); //判断元素的索引位置,如果不包含元素,则返回-1
2.1.7 长度及调整大小:
int size(); //返回集合的长度
void trimToSize(); //调整当前的容量为实际size的大小(提高性能)
-
- LinkedList使用
2.2.1 声明
LinkedList<E> ll=new LinkedList<E>();
// LinkedList没有默认分配长度
2.2.2 添加
void addFirst(E e); //将指定元素插入此列表的开头。
void addLast(E e); //将指定元素添加到列表的结尾。
2.2.3 读取
E getFrist(); //返回此列表的第一个元素。
E getLast(); //返回此列表的最后一个元素。
2.2.4 移除
E removeFrist(); //移除并返回此列表的第一个元素。
E removeLast(); //移除并返回此列表的最后一个元素。
3.Set接口
‘特点:
- 无序的,对象不可以重复(eqauls—eqauls从Object继承,默认比较时间);
- 查找效率低,增删效率高(不会引起元素位置变动)
遍历方式
- foreach
- 迭代器
对应类有:HashSet、TreeSet。
(1)HashSet:以哈希表的形式存放元素,插入删除速度很快。
(2)TreeSet:根据某种(规则)对里面的元素进行排序。
规则1: java.lang.Comparable
规则2: java.util.Comparator
TreeSet类
是Set的一种变体——可以实现排序等功能的集合,它在讲对象元素添加到集合中时会自动按照某种比较规则将其插入到有序的对象序列中,并保证该集合元素组成的读uixiangxulie时刻按照“升序”排列。
-
- HashSet使用
3.1.1 声明:
HashSet st=new HashSet();
例:HashSet mys = new HashSet();
Set mys = new HashSet(); //里氏替换原则
Set<String> mys = new HashSet<String>();
注意:要调用import java.util.HashSet;包
3.1.2 增删查
(1) 增
boolean add(E e); //如果集合中未包含指定元素,则添加指定元素
************************************************
注意:
a. Set集合中包含的是一组唯一的、不连续的集合
b. Set集合中是不允许添加进重复数据
c. 往Set里添加数据是无序的(没有先后次序)。
************************************************
(2) 删
void clear(); //从集合中移除所有元素
boolean remove(Object o); //如果指定元素存在于集合中,则将其移除
************************************************
注意:Set集合中的HashSet因为是无序的,所以不像ArrayList那样用remove(index)指定下标的位置删除。
************************************************
(3) 查
Set集合中没有get();方法,因为它无序无编号的(不知道拿出来的是什么)。
解决办法 =============> 迭代器Iterator
迭代器Iterator作用:遍历Set集合或取Set集合中的值。
Iterator方法:
boolean hasNext(); //如果仍有元素可以迭代,则返回 true。
E next(); //返回迭代的下一个元素。
操作步骤:
第一: 声明迭代器(放到一个传送带上)
Iterator<String> 迭代名 = 集合名.iterator<String>();
例:Set ar = new HashSet();
ar.add("java01");
ar.add("java02");
ar.add("java03");
Iterator<String> it = ar.iterator<String>();
第二: 循环取出
while(it.hasNext()){
String str = it.next();
System.out.println(str);
}
3.1.3、TreeSet
按照一定的规则进行排序
在对对象排序的时候也是需要重写规则类的CompareTo()方法
经典案例:
1. 产生52个不同的字母
Random r=new Random();
//定义Set集合存储字母
Set<Character> set=new HashSet();
while(true){
//1产生数字再转字母
int num1=r.nextInt(26)+97; //产生小写字母
int num2=r.nextInt(26)+65; //产生大写字母
set.add((char)num1);
set.add((char)num2);
if(set.size()==52){ //如大小到了52个就停止
break;
}
}
Iterator<Character> it=set.iterator<Character>();
while(it.hasNext()){
System.out.println(it.next());
}
2. 如何证明Set集合中重复的数据是没有存进去还是替换了原来的?(面试)
Set<String> set = new HashSet<String>();
set.add("aaa");
set.add("aaa");
set.add("bbb");
set.add("bbb");
set.add("aaa");
解题思路:
只要证明存没存进去,就可以证明该题。
(没存进去,那就不存在替换;存进去了,那就是替换了原来的。)
那如何证明有没有存进去?
首先要先搞清java怎么判断2个对象是否相等
1. 先比较2个对象的身份证hashcode;
2. 再比较2个对象的equals是否相等。(是里和外比,还是外和里比?)
hashcode只是决定是否需要用equals来比较,真正决定对象是否相等的方法仍然是equals。
4.Map接口
特点:
无序、以键值对的形式存储添加元素,键不能重复,值可以重复
遍历方式:
- 先取出保存所有的键的Set,再遍历Set即可(2种)
- 先取出保存所有Entry的Set,再遍历此Set即可。
怎样快速遍历Map
快速遍历,Map,遍历保存Entry的Set
直接把Map集合的键值都取出来,不需要先保存键到Set,再遍历取出值了
for (Map.Entry<String, String> entry:m.entrySet()) {
System.out.println(entry.getKey()+"\t"+entry.getValue());
}
Map下有四个子接口
HashMap、TreeMap、Hashtable、LinkedHashMap
- HashMap:根据键的HashCode值存储数据,查询快,最多允许一个键为NULL,多个值为NULL。
线程不同步
- Hashtable:与HashMap类似,但它不允许键或值为NULL。支持线程的同步(即任一时刻只有一个线程能写Hashtable,因此也导致了Hashtale在写入时会比较慢)。
- TreeMap:根据键排序(默认升序),也可指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。
- LinkedHashMap:保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.在遍历 的时候会比HashMap慢。
Map并不是一个真正意义上的集合,但是这个接口提供了三种“集合视角”,使得可以像操作集合一样操作。
4.1、HashMap使用
1. 声明
Map mp=new HashMap();
2. 存储(以“键-值”的方式进行存储)
V put(K key, V value) //将指定的值与此映射中的指定键关联
例:mp.put("CN","中华人民共和国");
mp.put("RU","俄罗斯联邦");
mp.put("US","美利坚合众国");
3. 读取
V get(Object key) //返回指定键所映射的值,如没有值则返回null
例:mp.get("CN"); //键值,而不是下标
4. 删除
V remove(Object key) //如果存在一个键的映射关系,则移除
例:mp.remove("RU");
5. 集合大小
int size() //返回此映射中的键-值映射关系数
6. 包含
boolean containsKey(Object key);
boolean containsValue(Object value);
例:mp.containsKey("CN"); //是否包含CN键
7. 其他方法
mp.keySet(); //输出所有键的集合(注意不包括值)
mp.values(); //输出键所对应的值,比如“中华人民共和国”
mp.entrySet(); //返回此映射所包含的映射关系的 Set 视图
==========由键得到值=========================
Set my=mp.keySet(); //得到所有的键集合
Iterator mi=my.iterator(); //得到键集合对应的迭代器
while(my.hasNext()){
Object o=my.next();
System.out.println(mp.get(o));
}
- Collections类
CompareTo()的意思是我和他比
Collections类提供集合操作的方法:
1. 排序:对List集合中的元素进行排序(默认升序)
Collections.sort(List list);
********************************************
排序的类型:
1.1 如果是数值型的,排序简单;
1.2 如果是字符串集合呢?一样的,比ASCII码值 abc abb
1.3 如果是中文呢?一样,比ASCII码值
1.4 如果装的是对象呢?
Collections类不知道按对象的哪个属性来排序,
因此我们要写个对象排序的规则类,让这个类实现Comparator接口,并重写compare方法(对排序规则进行重写),然后在排序的时候应用这个规则类。
例:
public class DogSort implements Comparator{ //实现Comparator接口
//重写compareTo()方法,按年龄来排序
public int compareTo(Object o1, Object o2){ //比较两个对象
//强转Object对象
Dog d1=(Dog)o1;
Dog d2=(Dog)o2;
//如果d1对象的年龄 > d2对象的年龄
if(d1.getAge()>d2.getAge()){
return 1;
}
return -1;
}
}
调用时:Collections.sort(list, new DogSort()); //表示list集合按DogSort()的规则来排序。
4.1 如果按姓名来排呢?再写个规则类,比较姓名用compareTo()方法比较。
********************************************
4.2 反转:对List集合中的元素进行反转操作
Collections.reverse(List list);
4.3 交换:在指定列表的指定位置处交换元素
swap(List list, int i, int j);
例:Collections.swap(list, 0, list.size()-1); //把第1个与最后一个交换
4.4 取集合中最大或最小
max(List list);
min(List list);
4.5 复制:将src集合中的所有元素复制到desc集合中
void copy(List dest, List src);
//先声明一个List dest集合,再复制
//重点说明:
确保个数dest>=src,否则报错;dest存入的个数如果为0就报错.
dest个数多于src个数,src的覆盖dest靠前的元素。
ArrayList a1=new ArrayList();
a1.add(1);
a1.add(2);
a1.add(3);
ArrayList a2=new ArrayList();
a2.add("a");
a2.add("b");
a2.add("c");
Collections.copy(a2, a1); //将集合a1中的所有元素都复制到a2中
- 线程安全与不安全的概括(同步与不同步)
线程安全(同步):
做事情要一件一件的去做
案例:
回家烧水,烧水需要时间,而我一定要等水烧完才去看电视
线程不安全(不同步):
做事情可以不用一件一件的去做,可以在一件事时去做另外一件事
案例
回家烧水,烧水需要时间,我可以在这个时间段去看电视,不需要一定等待水烧开才去看