目录
一、泛型
1.定义
顾名思义广泛的类型,在定义时候不确定之后要使用什么类型,所以使用泛型。在定义时候用一个字母去代替引用类型和包装类型,这样使用时可以使用泛型给形参赋值类型名
注意:泛型参数只能赋值引用类型和包装类型,不能赋值八大基本数据类型
2.用法
2.1 用在类上
一般用在类名后,用尖括号括起来,使用大写字母作为参数
import java.util.Date;
public class AClass<T>{
//定义
private T name;
public AClass(T t){
name = t;
}
//调用
public static void main(String[] args) {
//左边和右边的尖括号都要写
AClass<String> a = new AClass<String>("hello");
//右边尖括号的类型可以省略 传入的不是String类型也会报错
AClass<String> b = new AClass<>("world");
//泛型参数为long类型
AClass<Long> c = new AClass<>(1l);
//泛型参数为Date类型
Date date = new Date();
AClass<Date> d = new AClass(date);
}
}
特点:
1.左边和右边的尖括号都要写
2.左边的尖括号里必须写类型 否则编译器直接报错
3.右边尖括号的类型可以省略 传入的不是左边括号里的类型也会报错
下图为一些编译器报错案例
2.2 用在子类上
1.如果一个类继承了泛型类,那么在定义子类时候就给泛型参数赋值
public class Father<T> {
private T name;
public Father(T name) {
this.name = name;
}
}
class Son extends Father<String> {
public Son(String name) {
super(name);
}
}
2. 如果不赋值,默认是Object类型
public class Father<T> {
private T name;
public Father(T name) {
this.name = name;
}
}
class Daughter extends Father{
public Daughter(Object name) {
super(name);
}
}
3.子类的泛型参数可以赋值给父类的泛型参数
public class Father<T> {
private T name;
public Father(T name) {
this.name = name;
}
}
class Son<E> extends Father<E> {
public Son( E name) {
super(name);
}
}
2.3 用在方法上
位置:尖括号写在修饰符的后面
泛型方法在调用期间不需要指定具体类型,只需要传人具体对象
编译器会自动推断对象的类型 //泛型方法调用期间并没有给泛型参数赋值
下面是dog1给a, dog2给b赋值 没有给T赋值
import java.util.Objects;
public class MyTest {
public static void main(String[] args) {
Dog dog1 = new Dog("haha");
Dog dog2 = new Dog("heihei");
boolean result = MyTest.equals(dog1, dog2);
System.out.println(result);
}
public static<T> boolean equals(T a, T b){
return a.equals(b);
}
}
class Dog {
String name;
public Dog(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Dog dog = (Dog) o;
return Objects.equals(name, dog.name);
}
@Override
public int hashCode() {
return Objects.hashCode(name);
}
}
3.通配符
3.1 ?
不确定的类型,表示不关心传入的类型,可以是Long 也可以是Integer
public class MyTest {
// 通配符 ? 不关心调用时候的具体类型
public static void print(List<?> list){
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
}
public static void main(String[] args) {
print(new ArrayList<String>());
print(new ArrayList<Integer>());
}
}
3.3 上边界
<? extends 上边界类型>
可以是 上边界的任何子类型或者是本类型
public class MyTest {
//上边界 <? extends 具体类型>
public static void print2(List<?extends Number> list){
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
}
public static void main(String[] args) {
print2(new ArrayList<Long>());
print2(new ArrayList<Integer>());
print2(new ArrayList<Number>());
}
}
注意:不可以是其他不相关的类型
报错解析:因为Date类和Number 没有关系,只能是Number类的子类或者Number本类
3.3 下边界
<? super 下边界类型>
可以是本类型,也可以是本类型的父类
public class MyTest {
public static void print3(List<? super Number> list){
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
}
public static void main(String[] args) {
print3(new ArrayList<Number>());
print3(new ArrayList<Object>());
}
}
和上边界一样,不能是其他不相关的类型
二、集合
一、Collection(父接口)
接口List Set Queue都实现了Collection接口
ArrayList Vector LinkedList类都实现了List接口
hashSet 和 TreeSet 类都实现了Set接口,LinkedHashSet继承了HashSet类
Deque接口实现了 Queue接口
linkedList类实现了Deque接口
1 .常用的方法
- E sdd(E e):添加元素到集合中
- addAll( collection cl ) : 将cl集合添加到这个集合中
- int size : 返回集合中元素的个数
public class CollectionTest {
public static void main(String[] args) {
Collection<Integer> c1 = new ArrayList<>();
c1.add(1);
System.out.println("c1:"+c1);
Collection<Integer> c2 = new ArrayList<>();
c2.add(2);
c2.add(3);
System.out.println("c2:"+c2);
c1.addAll(c2);
System.out.println("将c2添加到c1后:"+c1);
int sum = c1.size();
System.out.println("c1的大小为:"+sum);
}
}
- boolean isEmpty(): 判断集合是否为空
- boolean contains(Object o) :判断集合中是否有o
- boolean containsAll( Collection c) : 查看调用者是否包含集合c
- boolean equals (Collection c): 查看两个集合是否相等
public class CollectionTest02 {
public static void main(String[] args) {
Collection<String> c1 = new ArrayList<>();
c1.add("我爱");
c1.add("中国");
boolean b = c1.isEmpty();
System.out.println("c1是否为空:"+b);
b = c1.contains("中国");
System.out.println("c1中是否含有中国:"+b);
Collection<String> c2 = new ArrayList<>();
c2.add("我爱");
b = c1.containsAll(c2);
System.out.println("c1是否包含c2:"+b);
System.out.println(c1);
System.out.println(c2);
b = c1.equals(c2);
System.out.println("c1是否等于c2:"+b);
}
}
- boolean remove(Object o): 移除c1里面的元素 o ,只移除第一个o
- boolean removeAll(Collection c): 从集合中删除集合c中的所有元素
- boolean retainAll (Collection c) : 移除 调用集合中的 所有元素 除了集合c中的
- void clear(): 清空集合中的所有元素
- String toString() 打印集合中的所有元素,默认调用
public class CollectionTest03 {
public static void main(String[] args) {
Collection<Integer> c = new ArrayList<>();
c.add(1);c.add(2);c.add(3);c.add(1);
c.add(2);c.add(4);c.add(5);c.add(6);
System.out.println("原始c的集合:"+c);
c.remove(1);
System.out.println("c集合移除第一个1 后"+c);
Collection<Integer> c2 = new ArrayList<>();
c2.add(1);
c2.add(2);
System.out.println("c2:"+c2);
c.removeAll(c2);
System.out.println("c删除c2集合中的所有元素后"+c);
Collection<Integer> c3 = new ArrayList<>();
c3.add(3);
c3.add(4);
System.out.println("c3中的元素:"+c3);
c.retainAll(c3);
System.out.println("c保留c3集合中的元素后"+c);
c.clear();
System.out.println("c清空后"+c);
}
}
2. 集合的遍历
1. 增强for循环
public class Test {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("A");
c.add("B");
c.add("C");
for(String s : c){
System.out.println(s);
}
}
}
2. 迭代器遍历
public class Test {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();
c.add("A");
c.add("B");
c.add("C");
Iterator it = c.iterator();
while(it.hasNext()){
String s = (String)it.next();
System.out.println(s);
}
}
}
注意: 迭代器遍历过程中不允许对集合进行修改长度
也就是说不能使用集合的方法删除元素,但是可以用迭代器的remove()删除
这涉及到底层源码
源迭代器码解析:
三个成员变量
cursor : 记录下一次要返回的元素的下标
lastret : 记录上一次刚刚返回的元素的下标
expectedModCount :预计的修改次数 默认值为集合的长度 与modCount值息息相关
注意: 集合在调用add()方法添加元素是 modCount++
hasNext(): return cursor != size: 当光标的值为集合长度时候,说明没有下一个元素
next():
1.检查预计修改次数和modCount是否一致,如果不一致,抛出 ConcurrentModificationException 异常
2. 光标的值先赋值给lastRet,相当于指针后移,光标的值+1,为下一次hasNext()做准备
新的lastRet的值就是指针指向的元素下标,也就是刚刚取出来的元素
remove():
1. expectedModCount 和modCount 是否一致,如果不一致,抛出异常
2. 调用ArrayList的E remove(int index)做真正的删除操作
而E remove(int index) 里面调用System.arrcopy()方法,
从指定的index+1处,向前移动一位,以此形式做删除工作
然后将最后一个元素置为null
index的值是lastRet赋值的
因为后续的元素向前移动了,因此cursor也要向前移动一次,即cursor = lastRet,
如果不向前移动会漏掉元素,也就是index+1处的元素会被漏掉
最重要的是remove()里 进行了modCount++操作
但是迭代器的remove里进行了expectedModCount=modCount; 而集合的remove没有
(一)List子接口
1.ArrayList : 底层是动态数组,对象存储在连续的位置上
2. LinkedList底层时双链表的数据结构,对象不存储在连续的空间上,
比较(前提是数据量很大的情况下):
随机访问 ArrayList 高于 LinkedList ,因为LinkedList要移动指针
插入和删除 LinkedList高于ArrayList 因为ArrayList要移动数据
ArrayList 和 LinkedList 两个实现类的常用方法基本相同
1. 常用方法
1. 添加元素
-
boolean add(E e)作用:向列表末尾添加指定的元素
-
void add(int index, E element)作用:在列表的指定位置添加集合
-
boolean addAll(Collection c ) 作用:将集合c中的所有元素都添加到列表的结尾
-
boolean addAll(int index, Collection c) 作用:将集合c中的所有元素添加到列表的指定位置
public class ArrayLiatTest {
public static void main(String[] args) {
ArrayList<Integer> a = new ArrayList<>();
a.add(1);
a.add(2);
System.out.println("集合a"+a);
//在下标为1处添加索引
a.add(1,3);
System.out.println("在下标为1处添加3:"+a);
ArrayList<Integer> b = new ArrayList<>();
b.add(4);
b.add(5);
System.out.println("集合b"+b);
a.addAll(b);
System.out.println("将集合b加到a中:"+a);
a.addAll(0,b);
System.out.println("将集合b加到a的下标为0处:"+a);
}
}
2.获取元素
-
E get(int index)作用:返回列表指定位置的元素
public class GetArrayList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
System.out.println(list);
String element = list.get(2);
System.out.println("得到下标为2的元素为:"+element);
}
}
3.查找元素
-
int indexOf(Object obj) 作用:返回列表中指定元素第一次出现的位置,如果没有该元素,返回-1
-
int lastIndexOf(Object obj) 作用:返回列表中指定元素最后一次出现的位置,如果没有该元素,返回-1
public class findArrayList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
list.add("A");
System.out.println(list);
int first = list.indexOf("A");
System.out.println("A第一次出现的位置:"+first);
int last = list.lastIndexOf("A");
System.out.println("A最后一次出现的位置:"+last);
first = list.indexOf("D");
System.out.println("D第一次出现的位置:"+first);
last = list.lastIndexOf("D");
System.out.println("D最后一次出现的位置:"+last);
}
}
4. 移除元素
-
E remove(int index) 作用:移除集合中指定(位置)的元素,返回被移除掉的元素对象
-
boolean remove(Object o) 作用:移除集合中 指定元素返回的是 移除元素是否成功
-
boolean isRemove(Object o) 作用:移除集合中指定(位置)的元素,返回移除是否成功
public class RemoveArrayList {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
System.out.println("最开始的元素"+list);
boolean a =list.remove("A");
System.out.println("删除A元素后"+list);
System.out.println("移除A是否成功:"+a);
String s = list.remove(1);
System.out.println("删除下标为1的元素后"+list);
System.out.println("移除的元素为:"+s);
}
}
5.修改元素
-
E set(int index, E element)
作用:用指定元素替换指定位置上的元素,返回被替换出来的元素对象
public class SetElement {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("orange");
list.add("apple");
System.out.println(list);
String s = list.set(1, "grape");
System.out.println("修改下标为1的元素后"+list);
System.out.println("修改后得到的元素为:"+s);
}
}
6. 截取子集
-
List subList(int fromIndex, int toIndex)
作用:截取子集,返回集合中指定的fromIndex 到 toIndex之间部分视图,包前不包后
就是指如果将截取的子集位置上的元素改变,那么原来的集合该位置上的元素也会改变
public class SetElement {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hi1");list.add("hi2");
list.add("hi3");list.add("hi4");
System.out.println(list);
String s = list.set(1, "hi5");
System.out.println("修改下标为1的元素后"+list);
System.out.println("修改后得到的元素为:"+s);
List<String> subList = list.subList(1,3);
System.out.println("截取下标为1到3的子集合:"+subList);
subList.set(0, "pear");
System.out.println("截取的集合为:"+subList);
System.out.println("原来的集合:"+list);
}
}
2. 遍历
3种方法
普通for循环
因为ArrayList 和 LInkedList 都有序 ,存在下标,所以可以用普通for循环遍历。
public class ListTraverse {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");
System.out.println(list);
for(int i = 0;i<list.size();i++){
System.out.println(list.get(i));
}
}
}
增强for循环
for(String s : list){
System.out.println(s);
}
迭代器
Iterator<String> it = list.iterator();
while(it.hasNext()){
String element = it.next();
System.out.println(element);
}
(二)Queue 子接口
底层数据结构:队列(从一端添加(offer)元素,从另一端取出(poll)元素)
1. 常用方法
- boolean offer(E e):作用:将一个对象添加到队尾,如果添加成功返回true
- String poll() 作用:从队首删除并返回这个元素
- E peek()作用:查看队首的元素
public class QueueTest {
public static void main(String[] args) {
Queue<Integer> q = new LinkedList<Integer>();
q.offer(1);
q.offer(2);
q.offer(3);
System.out.println("集合q: " + q);
q.poll();
System.out.println("删除队首元素后:"+q);
int s = q.peek();
System.out.println("查看队首元素:"+s);
}
}
2. 子接口 Deque
Deque是Queue的子接口,定义了所谓的”双端队列”,即从队列的两端分别可以入队(offer)和出队(poll)。同样,LinkedList实现了该接口
- boolean offerFirst(Element e):从队首入队
- boolean offerLast(ELement e):从队尾入队
- boolean pollirst():boolean poll() :从队首出队
- boolean pollLast():从队尾出队
public class DequeTest {
public static void main(String[] args) {
Deque<Integer> deque = new LinkedList<>();
deque.addFirst(1);
deque.addFirst(2);
System.out.println(deque);
deque.addLast(3);
deque.addLast(4);
System.out.println(deque);
deque.poll();
System.out.println(deque);
deque.pollFirst();
System.out.println(deque);
deque.pollLast();
System.out.println(deque);
}
}
如果将Deque限制为只能一端入队和出队,则可以实现“栈”(Stack)的数据结构,对于栈而言,入栈被称为push,出栈被称为pop。遵循先进后出(FILO)原则
常用方法:
- push( Element e ) 作用:把元素e放进集合中
- String pop(); 作用 返回被弹出的元素 先入后出
public class QueueDemo03 {
public static void main(String[] args) {
Deque<String> stack = new LinkedList<>();
//从栈的出口进入,对应的方法push,表示把元素推进去
stack.push("michael");
stack.push("lucy");
stack.push("lily");
stack.push("tom");
System.out.println(stack);
//出栈(弹出) 对应的方法pop() 将元素弹出栈结构
while (stack.size() > 0) {
String el = stack.pop();
System.out.println(el);
}
}
}
打印也是先进去的最后打印
先进去的是michael 先出来的是tom
(三)Set接口
Set集合中的元素是无序的(取出的顺序与存入的顺序无关
Set集合中的元素不能重复
------即不能把同一个东西或者相似的东西两次添加到同一个Set容器中,每次放入时都会进行判断是否存在,如果存在,就不添加。--即不能把同一个东西或者相似的东西两次添加到同一个Set容器中,每次放入时都会进行判断是否存在,如果存在,就不添加。
- 设计初衷: 用来存储不重复的元素,元素的顺序是无序(取出的顺序和存入的顺序无关)的 (一旦存入,在存储结构 里的顺序固定了 和存入先后顺序无关 也就是打印的顺序是一样的) - set接口里的方法都是Collection接口的方法 - HashSet: 是实现了Set接口里的最经典的子类型 -底层的存储方式使用的是Hash算法(哈希表)
去重原理:每添加一个元素,会计算它的哈希值,判断哈希表上的该位置是否有元素
如果有元素,那么调用equals调用它们的属性是否一样。如果一样那么就不能添加,如果不一样就添加进来
(一)HashSet类
遍历
两种方式:因为没有下标,所以不能用普通for循环遍历
增强for循环
迭代器
LinkedHashSet类
是HashSet的子类
LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
LinkedHashSet 性能插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
LinkedHashSet 不允许集合元素重复。
(二)TreeSet
TreeSet 是 SortedSet 接口的实现类,TreeSet集合的元素是有序的,即内部维护一个二叉树算数的排序方式
TreeSet集合是用来对元素进行排序的,同样他也可以保证元素的唯一。
TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。可以自定义一个比较器
public class SetDemo04 {
public static void main(String[] args) {
Set<String> set = new TreeSet<>();// 创建一个空的TreeSet集合
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("bob");
set.add("bab");
System.out.println(set);
Comparator c1 = new Comparator<Integer>() {
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
};
Set<Integer> nums = new TreeSet<>(c1);
nums.add(1);
nums.add(20);
nums.add(4);
nums.add(3);
System.out.println(nums);
}
}
常用方法都是从Collection中继承过来的
二、Map
Map是集合框架中的另一个父接口,它用来保存具有映射(一对一)关系的数据,这样的数据称之为键值对(Key-Value-Pair)。key可以看成是value的索引。特点如下:
key和value必须是引用类型的数据
作为key,在Map集合中不允许重复
key可以为null
key和value之间存在单向一对一关系,通过指定的key总能找到唯一,确定的value
HashMap和TreeMap类实现了Map接口
LinkedHashMap继承了HashMap类
常用方法:
- V put(); 向集合中添加一个键值对,如果已经存在会用新的值覆盖
- putIfAbsent() 如果不存在才会增,存在不会覆盖,没有任何效果
public class Method {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
System.out.println(map);
//覆盖
map.put("a", 3);
System.out.println(map);
//存在不变,不存在覆盖
map.putIfAbsent("a", 4);
System.out.println(map);
}
}
- remove(K key) 按照键删除键值对
- remove(K key ,V value) 按照键值对删除 只有当键和值都能够匹配上的时候才删除
- clear() 清空所有的键值对
- boolean isEmpty() 判断是否为空
- boolean containKey(Object key) 判断是否包含key
- boolean containsValue() 判断是否包含Value
- int size() 返回集合中键值对的个数
public class MapDemo02 {
public static void main(String[] args) {
HashMap<String,String> course = new HashMap<>();
course.put("王老师","语文");
course.put("李老师","数学");
course.put("张老师","化学");
course.put("赵老师","生物");
System.out.println(course);
/**
* 1. boolean isEmtpy():判断map是否为空
*/
System.out.println("course是否为空:" + course.isEmpty());
// 2. containsKey()
System.out.println("是否包含张老师" + course.containsKey("张老师"));
//3. containsValue()
System.out.println("是否包含语文" + course.containsValue("语文"));
//4. remove()
course.remove("张老师");
System.out.println("移除张老师后:"+course);
//remove(K,V)
course.remove("赵老师","生物");
System.out.println("移除赵老师生物后:"+course);
//5. size()
System.out.println("course的大小:" + course.size());
//6. clear() :清空所有的键值对
course.clear();
System.out.println("清空后:"+course);
System.out.println("集合的大小"+course.size());
}
}
遍历
三种方式
1. 得到ketSet存到Set集合中,然后遍历key,通过get()方法得到value值
2. 使用entrySet 方法 ,返回entry对象的set集合
Set<Map.Entry<K,V>> set = map.entrysSet;
for(Map.Entry<K,V> entry: set){
System.out.println( entry);
entry.getKey(); //Entry类提供的getKey()方法获取键
entry.getValue(); //Entry类提供的getValue()方法获取值
}
3. 使用values()方法返回所有的 values的集合
public class mapfor {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("apple", 10);
map.put("banana", 20);
map.put("orange", 30);
map.put("grape", 40);
//得到key的set集合,然后通过get方法拿到value的值
Set<String> keys = map.keySet();
for (String key : keys) {
System.out.println(key + ":" + map.get(key));
}
Set<Map.Entry<String, Integer>> set = map.entrySet();
for (Map.Entry<String, Integer> entry : set) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
for(Integer value:map.values()){
System.out.println(value);
}
}
}
三、排序(Comparable and Comparable)
只有有序的集合才能进行排序,即插入顺序和取出打印顺序一样的集合
1. 实现Comparable接口
2. 定义一个comparator比较器
如果不想修改源码,可以定义一个比较器,指定临时的比较规则
List 案例
package com.se.compare;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import static java.util.Collections.sort;
public class Sort {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
Person p =new Person("Alice", 25);
Person p2 =new Person("Bob", 30);
Person p3 =new Person("Charlie", 20);
list.add(p);
list.add(p2);
list.add(p3);
Collections.sort(list);
System.out.println(list);
//如果此时想升序排序 就可以定义一个比较器
Comparator<Person> c = new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
};
Collections.sort(list, c);
System.out.println(list);
}
}
class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String toString(){
return
"name='" + name + '\'' +
", age=" + age +
'}';
}
//按照年龄降序排序`
@Override
public int compareTo(Person o) {
return -(this.age - o.getAge());
}
}
TreeSet案例
package com.se.compare;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
//年龄降序,年龄相同,工资升序,工资相同 工龄降序
public class mapSort {
public static void main(String[] args) {
Set<Employee> set = new TreeSet<>();
Employee e1 = new Employee("Tom", 25, 5000, 5);
Employee e2 = new Employee("Jerry", 25, 6000, 4);
Employee e3 = new Employee("Mike", 20, 4000, 2);
Employee e4 = new Employee("Lily", 25, 5000, 1);
set.add(e1);
set.add(e2);
set.add(e3);
set.add(e4);
for (Employee e : set) {
System.out.println(e);
}
}
}
class Employee implements Comparable<Employee> {
private String name;
private int age;
private double salary;
private int workAge;
public Employee(String name, int age, double salary, int workAge) {
this.name = name;
this.age = age;
this.salary = salary;
this.workAge = workAge;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public double getSalary() {
return salary;
}
public int getWorkAge() {
return workAge;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age && Double.compare(salary, employee.salary) == 0 && workAge == employee.workAge && Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary, workAge);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", workAge=" + workAge +
'}';
}
@Override
public int compareTo(Employee e) {
if (e.getAge() == this.getAge()) {
if (e.getSalary() == this.getSalary()) {
return e.getWorkAge() - this.getWorkAge();
}
return (int)(this.getSalary() - e.getSalary());
}
return e.getAge() - this.getAge();
}
}
如果在compareto 方法里面只写this.age-o.age
那么当年龄相同时,不会进入到集合中
package com.se.compare;
import java.util.Comparator;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
//年龄降序,年龄相同,工资升序,工资相同 工龄降序
public class mapSort {
public static void main(String[] args) {
Set<Employee> set = new TreeSet<>();
Employee e1 = new Employee("Tom", 25, 5000, 5);
Employee e2 = new Employee("Jerry", 25, 6000, 4);
Employee e3 = new Employee("Mike", 20, 4000, 2);
Employee e4 = new Employee("Lily", 25, 5000, 1);
set.add(e1);
set.add(e2);
set.add(e3);
set.add(e4);
for (Employee e : set) {
System.out.println(e);
}
Comparator<Employee> c = new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
if (o2.getAge() == o1.getAge()) {
if (o2.getSalary() == o1.getSalary()) {
return o2.getWorkAge() - o1.getWorkAge();
}
return (int) (o1.getSalary() - o2.getSalary());
}
return o2.getAge() - o1.getAge();
}
};
for (Employee e : set) {
System.out.println(e);
}
}
}
class Employee implements Comparable<Employee> {
private String name;
private int age;
private double salary;
private int workAge;
public Employee(String name, int age, double salary, int workAge) {
this.name = name;
this.age = age;
this.salary = salary;
this.workAge = workAge;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public double getSalary() {
return salary;
}
public int getWorkAge() {
return workAge;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age && Double.compare(salary, employee.salary) == 0 && workAge == employee.workAge && Objects.equals(name, employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, salary, workAge);
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", salary=" + salary +
", workAge=" + workAge +
'}';
}
@Override
public int compareTo(Employee e) {
return e.getAge() - this.getAge();
}
}
四、比较
1.底层
ArrayList : 动态数组+各种方法
LinkedList : 动态链表+各种方法
HashSet: 底层是HashMap 的put方法 只不过只用了HashMap的key
HashMap: 底层是数组+ 单向链表+红黑树
LinkedHashMap:底层是数组+双向链表+红黑树
2.有序or无序
List集合都是有序的
HashSet无序
LinkedHashSet 和 TreeSet有序
HashMap无序,LinkedHashMap和TreeMap有序
五、Collections类
Collections 是一个操作 Set、List 和 Map 等集合的工具类,提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
1. 排序操作(只能对实现List接口的类)
-
reverse(List):反转 List 中元素的顺序
-
shuffle(List):对 List 集合元素进行随机排序
-
sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
-
sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
-
swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
public class Sort {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(4);
list.add(2);
list.add(5);
System.out.println(list);
Collections.sort(list);
System.out.println("默认排序后"+list);
Collections.reverse(list);
System.out.println("反转后"+list);
Collections.shuffle(list);
System.out.println("洗牌后"+list);
Comparator<Integer> c = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
};
Collections.sort(list, c);
System.out.println("自定义排序后"+list);
Collections.swap(list, 0, 1);
System.out.println("交换后0位置和1位置后"+list);
}
}
2. 查找、替换
-
Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
-
Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大位置上的元素
-
Object min(Collection) 根据元素的自然顺序,返回给定集合中的最小元素
-
Object min(Collection,Comparator) 根据 Comparator 指定的顺序,返回给定集合中的最小位置上的元素
-
int frequency(Collection,Object):返回指定集合中指定元素的出现次数
-
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
public class Find {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(4);
list.add(2);
list.add(5);
list.add(5);
System.out.println(list);
int max = Collections.max(list);
System.out.println("集合中最大的元素: " + max);
Comparator<Integer> c = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
};
Collections.sort(list, c);
System.out.println(list);
max = Collections.max(list, c);
System.out.println("排序后最后一个位置上的元素" + max);
int min = Collections.min(list);
System.out.println("集合中最小的元素: " + min);
min = Collections.min(list, c);
System.out.println("排序后第一个位置上的元素" + min);
int frequency = Collections.frequency(list, 5);
System.out.println("集合中元素5出现的次数: " + frequency);
System.out.println(list);
boolean replaceAll = Collections.replaceAll(list,5,6);
System.out.println("替换是否成功: "+replaceAll);
System.out.println("替换后的集合: "+list);
}
}
3.集合转数组
集合转数组 Object[] toArray() 作用将集合转成Object数组,一旦想要使用数组中元素的子集的方法和属性,还需要强转 T[] toArray(T[] a) 作用:只需要传入一个元素类型的数组对象就可以返回元素类型的数组
public class CollectionDemo02 {
public static void main(String[] args) {
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Jane");
names.add("Bob");
//第一种 得到的是Object类型的数组
Object[] arr1 = names.toArray();
Object o = arr1[1];
if(o instanceof String){
String s = (String)o;
char c = s.charAt(1);
System.out.println(c);
}
//第二种 定义一个String 类型的数组传入
String[] arr = new String[0];
String[] array = names.toArray(arr);
System.out.println(array.length);
System.out.println(Arrays.toString(array));
String s1 = array[0];
System.out.println(s1);
boolean b =s1.endsWith("hn");
System.out.println("是否以hn结尾:"+b);
}
}
4.数组转集合
数组转集合 1. 数组转成的集合对象 不可以改变集合的长度 2. 如果想要进行增删操作,可以将转成的元素放入一个新的
public class CollectionDemo03 {
public static void main(String[] args) {
String[] names = new String[5];
names[0] = "Michael";
names[1] = "Jane";
names[2] = "Doe";
names[3] = "Mike";
names[4] = "John";
List<String> list = Arrays.asList(names);
System.out.println(list);
System.out.println(list.size());
list.set(1, "Jack");
System.out.println(list);
//添加和移除有异常,因为会修改长度,
// list.add("Tom");
// list.remove(2);
/**
* 向集合中添加新元素 “张三和李四”
*/
List<String> newList = new ArrayList<>();
newList.addAll(list);
System.out.println("新的集合: "+newList);
newList.add("张三");
newList.add("李四");
System.out.println("新的集合: "+newList);
String zhangsan = newList.get(newList.size()-2);
String str1 = newList.set(0, zhangsan);
newList.set(newList.size()-2, str1);
System.out.println("新的集合: "+newList);
}
}