1.之前集合没有整理完,接着整理,大家可以连起之前的一起参考
2.1 List排序
• Collections是集合的工具类,它提供了很多便于我们操作集合的方法,其中就有用于集合排序的sort方法。
• 该方法定义为: void sort(List list)
该方法的作用是对给定的集合元素进行自然排序。
Comparable:接口
• Collections的sort方法是对集合元素进行自然排序,那么两个元素对象之间就一定要有大小之分。这个大小之分是如何界定的?实际上,在使用Collections的sort排序的集合元素都必须是Comparable接口的实现类,该接口表示其子类是可比较的,因为实现该接口必须重写抽象方法:
– int compareTo(T t);
该方法用于使当前对象与给定对象进行比较。
– 若当前对象大于给定对象,那么返回值应为>0的整数。
– 若小于给定对象,那么返回值应为<0的整数。
– 若两个对象相等,则应返回0。
Comparable接口:内比较器
如果一个类实现了此接口,那么一定要重写compareTo(Object obj),在此方法中,将比较规则写出。
之后才可以调用Collections.sort(list)
Collections.sort(list)
案例:
一个集合中存放的是学生对象,现对集合进行排序,排序规则按照学生的学号排序
方式一:通过让student类实现Comparable接口
public class Student implements Comparable<Student> {
private int schooleId;
private int age;
private String name;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(int schooleId, int age, String name) {
super();
this.schooleId = schooleId;
this.age = age;
this.name = name;
}
public int getSchooleId() {
return schooleId;
}
public void setSchooleId(int schooleId) {
this.schooleId = schooleId;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student [schooleId=" + schooleId + ", age=" + age + ", name=" + name + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + schooleId;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (schooleId != other.schooleId)
return false;
return true;
}
@Override
public int compareTo(Student o) {
//比较两个学生的学号
// int schoolId1 = o.getSchooleId();
return this.schooleId - o.getSchooleId();
}
此排序默认升序,如果想默认降序,可以在前边加“-”或者调整一下两者的位置
}
public class StudentTest {
public static void main(String[] args) {
/*
* 创建一个集合用于保存学生对象
*/
List<Student> list =
new ArrayList<Student>();
//创建三个学生对
象
Student stu1 = new Student(1004, 23, "张三");
Student stu2 = new Student(1001, 23, "李四");
Student stu3 = new Student(1003, 23, "王五");
list.add(stu1);
list.add(stu2);
list.add(stu3);
System.out.println(list);
//要求对集合中的学生对象进行排序,规则是按照学号
Collections.sort(list);
System.out.println(list);
}
}
要求:
前提:以上题为前提
集合中保存学生对象,现要按照学生的年龄排序
Comparator:接口
• 一旦Java类实现了Comparable接口,其比较逻辑就已经确定;如果希望在排序的操作中临时指定比较规则,可以采用Comparator接口回调的方式。
• Comparator接口要求实现类必须重写其定义的方法:int compare(T o1,T o2)
Comparator:外比较器:
使用场景:
如果对一个集合中进行排序时,不想用集合中元素已有的排序规则,而是要用自定义规则,此时需要写一个类实现Comparator接口,重写其compare(T o1,T o2)。在主方法所在类的内部类中重写
在对集合排序时调用Collections.sort(List,Comparator)
/**
* 对集合中的学生对象按照年龄排序
* @author adminitartor
*
*/
public class StudentAgeTest {
public static void main(String[] args) {
/*
* 创建集合用于保存Student对象
*/
List<Student> list =
new ArrayList<Student>();
//创建三个学生对象
Student stu1 = new Student(1004, 28, "张三");
Student stu2 = new Student(1001, 23, "李四");
Student stu3 = new Student(1003, 24, "王五");
list.add(stu1);
list.add(stu2);
list.add(stu3);
System.out.println(list);
/*
* 对集合进行排序 ,按照年龄
*/
StudentAgeTest ageTest =
new StudentAgeTest();
Collections.sort(list, ageTest.new ByAge());
System.out.println(list);
}
//内部类
/*
* Comparator:外比较器
* 写了一个比较器,只不过这个比较器是写在Student
* 封装类的外部的
*/
private class ByAge implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
同样是默认升序,如果要降序的话,前边加“-”或者换一下位置
}
}
}
Comparabl与Comparator的区别
Comparable:接口,内比较器
使用:
1, 一个类实现此接口
2, 重写compareTo(T other)
3, 对集合进行排序
a) Collections.sort(List)
Comparator:接口 外比较器
使用:
- 一个类实现此接口
- 重写compare(T o1,T o2)
- 对集合进行排序
a) Collections.sort(List,Comparator)
如何对集合进行降序排列:
可以的,在表达式前+ -
2.2 队列和栈
LinkedList,此类实现了Deque接口,Deque接口又继承了Queue
Queue:
java.util.Queue:接口
* 队列,可以存储一组元素,但是存取元素必须
* 遵循先进先出原则(FIFO,First Input First Output)
队列(Queue)是常用的数据结构,可以将队列看成特殊的线性表,队列限制了对线性表的访问方式:
只能从线性表的一端添加(offer)元素,从另一端取出(poll)元素。
队列遵循先进先出(FIFO First Input First Output )的原则。
JDK中提供了Queue接口,同时使得LinkedList实现了该接口
(LinkedList实现Queue的原因在于Queue经常要进行添加和删除的操作,而LinkedList在这方面效率较高)。
Queue方法:
Offer(E e):将一个对象添加至队尾,如果添加成功则返回true。
poll(): 从队首删除并返回一个元素–string
peek():返回队首的元素(但并不删除)。–string
/**
- Queue:队列是一种数据结构,特点先进先出
- 只能从一端添加元素,从另一端取出元素
- @author adminitartor
*/
public class Demo01 {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<String>();
queue.offer("x");
queue.offer("b");
queue.offer("c");
String str = queue.poll();
System.out.println(str);
String str1 = queue.peek();
System.out.println(str1);
System.out.println(queue);
}
Queue的遍历
/*
* 队列的遍历
* foreach
*/
for(String s:queue){
System.out.println(s);
}
/*
* 队列自行遍历
*/
while(queue.size()>0){
String str =queue.poll();
System.out.println(str);
}
Deque:
Deque是接口,继承了Queue接口
• Deque是Queue的子接口,定义了所谓“双端队列”即从队列的两端分别可以入队(offer)和出队(poll),LinkedList实现了该接口。
• Deque:数据结构,双端队列
• 特点:可以从队列的两端分别入队和出队
Deque方法:
Offer(E e)
offerFirst(E e)
offerLast(E e)
poll()
pollFirst()
pollLast()
/**
- Deque是接口,继承了Queue接口
- 叫做双端队列
- 特点:可以从两端分别入队和出队
- @author adminitartor
*/
public class DequeDemo {
public static void main(String[] args) {
//创建Deque
Deque<String> deque =
new LinkedList<String>();
//向此队列中插入2个元素 - offer(E)
deque.offer("java");
deque.offer("c++");
System.out.println(deque);
//在队首插入元素
deque.offerFirst("php");
System.out.println(deque);
//在队尾插入元素
deque.offerLast("last");
System.out.println(deque);
//获取队列的队首的第一个元素并移除
String str = deque.poll();
System.out.println(str);
System.out.println(deque);
//获取并移除队尾的元素
String last = deque.pollLast();
System.out.println(last);
System.out.println(deque);
}
}
Stack:
先进后出
• 如果将Deque限制为只能从一端入队和出队,则可实现“栈”(Stack)的数据结构,对于栈而言,入栈称之为push,出栈称之为pop。
• 栈遵循先进后出(FILO First Input Last Output )的原则。
•
Stack方法
栈中的两个方法:
push(E) :将元素压入栈顶
pop():从栈顶取出元素,并从栈中移除
/**
- 如果对Deque进行限制,只允许从一端进行
- 入队和出队,此时就形成了Stack数据结构
- 特点:先进后出
*/
public class StackDemo {
public static void main(String[] args) {
//创建一个集合对象存放数据
Deque<String> stack =
new LinkedList<String>();
stack.push("a");
stack.push("s");
stack.push("x");
System.out.println(stack);
String str = stack.pop();
System.out.println(str);
System.out.println(stack);
}
- Set接口
Set集合:不可重复集
Collection接口:
List集合:是可重复集,有序的
Set集合:不可重复集
HashSet():无序的
元素不可重复
添加元素时,调用集合中元素的equals方法
实现类:HashSet()
Student类
Set<Student> set = new HashSet<Student>();
Student stu = new Student(1001,”aa”);
Student stu1 = new Student(1001,”aa”);
set.add(stu) true
set.add(stu1)
如果Student类中没重写equals,返回true
如果重写了equlas,返回false
/**
* List集合是可重复集
* Set集合是不可重复集
* @author adminitartor
*
*/
public class Demo01 {
public static void main(String[] args) {
// List<String> list =
// new ArrayList<String>();
//
// list.add("a");
// list.add("b");
// list.add("a");
//
// System.out.println(list);
/*
* set接口的实现类:HashSet()
*/
Set<String> set =
new HashSet<String>();
boolean flag = set.add("a");
set.add("b");
set.add("c");
// System.out.println(set);
// set.remove("a");
// System.out.println(set);
// boolean flag1 = set.add("a");
// System.out.println(flag);
// System.out.println(flag1);
/*
* set集合的遍历
* iterator
* foreach
*/
for(String s:set){
System.out.println(s);
}
}
4 查找表:map<k,v>
4.1Map接口
• 保存具有映射关系的数据 – Map集合
语文 - 90
数学 – 80
英语 – 20
key – value 键值对
key是唯一的 通过key来找元素的
Map<Key,Value>
Key,Value必须都是引用类型
• Map接口定义的集合又称查找表,用于存储所谓“Key-Value”映射对。Key可以看成是Value的索引,作为Key的对象在集合中不可以重复。
• 根据内部数据结构的不同,Map接口有多种实现类,其中常用的有内部为hash表实现的HashMap和内部为排序红黑树实现的TreeMap。
•
Map接口中定义的方法:
put(K key,V value):
向集合中存放元素。
如果存放的key值已经存在,会怎么样?
覆盖掉此key原来的value值
/**
- Map集合保存的是一组一组的键值对(具有映射关系的数据)
- 实现:
- HashMap()\
- 对象的创建,添加元素的方法
- @author adminitartor
*/
public class MapDemo01 {
public static void main(String[] args) {
//创建一个Map集合对象
Map<String, Integer> map =
new HashMap<String,Integer>();
//向集合中添加元素 - put(K,V)
/*
* put(K,V) - V - 将此Key原来对应的Value返回
* 如果此Key之前不存在,那么返回null
*/
map.put("语文",90);
Integer math = map.put("数学", 80);
map.put("英语", 90);
map.put("语文", 70);
System.out.println(math);
System.out.println(map);
}
}
get(K key) – V
containsKey(Object key):判读某个key是否在Map中存在
/*
* 根据key值取出对应的value值
* get(K key) - V
*/
int a = map.get("语文");
System.out.println(a);
/*
* 对某个键值进行判断,判断是否已经存在于集合中
* containsKey(K key) - boolean
*/
boolean flag = map.containsKey("语文");
System.out.println(flag);
练习:
Student放入map集合,通过学号来找学生对象
key – Integer
value – Student
4.2实现类 HashMap
HashCode()
Object类中的hashCode()方法:返回该对象所在内存地址的整数形式
hashCode()的稳定性:
同一个对象在一个程序中,多次调用hashCode()生成的整数一定是相同的
如果两个对象equals相等,那么得到的hashCode值(返回的是一个int值)一定相等,
但是如果两个对象的hashCode值相等,这两个对象不一定equals – 即hashCode值不是唯一的
Hash算法:
key的hashCode值 经过散列算法,得到散列下标,不同的hashcode值经过散列算法得到的散列下标可能相同,如果散列下标相同,那么出现链表
HashMap:查找性能是最高的。 - 由数据结构决定的
出现链表会降低查询性能,HashMap的查询性能是最好的。
为了降低链表出现的概率,需重写equals和hashcode方法,重写这两个方法可以降低链表出现概率,但不能避免
HashMap:
HashMap内部由数组实现,是当今查询速度最快的数据结构.
* HashMap根据key元素决定这组键值对应当存放在
* 数组的位置,并且也是根据key元素得到位置来检索
* 数组中的该组键值对以此省去了遍历数组的过程.
*
* 但是使用HashMap时应当尽量避免出现链表的情况.
* HashMap中链表的产生原因:
* HashMap是根据key元素的hashcode方法返回的数字
* 经过散列计算得到该组键值对应当存放在数组的哪个
* 位置,而根据key元素equals比较查看当前key是否
* 已经存在于Map中,若存在则直接替换该位置这个key
* 所对应的value,但是若数组该位置已经存在键值对,
* 并且key与当前准备存放的键值对中的key的equals
* 比较不同时,则会在数组当前位置产生链表.这样在
* 将来根据key检索时会出现遍历链表的情况,这样就
* 会降低HashMap查询性能.
* 总结:当key元素hashcode值相同,但是equals比较不同
* 时就会在HashMap中产生链表,影响查询性能.
如何尽可能的避免出现链表?
重写hashCode和equals方法
4.3 Map的遍历
KeySet():
得到一个key值的set集合
entrySet(): - Set<Entry<K,V>>
得到map集合中的所有键值对的set集合Map的遍历:
keySet() – key的set集合
entrySet() – Set<Entry<K,V>>
得到map集合中所有键值对的set集合
注意点:对此集合进行遍历,注意每个元素的类型是Entry<K,V>
案例
Map<String, Integer> map =
new HashMap<String, Integer>();
map.put("语文", 90);
map.put("数学", 90);
map.put("英语",90);
//获取到所有key值 - set集合
Set<String> keyset = map.keySet();
//遍历set集合
for(String s:keyset){
System.out.println(s);
}//输出的结果跟自己添加的顺序不一样,也就是无序的,内层根据字母顺序排序
/*
* entrySet():
* 得到map集合中所有元素的set集合
*/
Set<Entry<String, Integer>> set =
map.entrySet();
//对set集合进行遍历
for(Entry<String, Integer> e:set){
String key = e.getKey();
Integer it = e.getValue();
System.out.println(key +" - "+it);
取键值和value值
getKey()
getValue()
Map:接口,保存是键值对 key –value对
put(K,V)
get(K) – V
containsKey(K)-boolean
案例:
Map<String, Integer> map = new HashMap<String,Integer>();
//向集合中添加元素 - put(K,V)
/*
* put(K,V) - V - 将此Key原来对应的Value返回
* 如果此Key之前不存在,那么返回null
*/
map.put("语文",90);
Integer math = map.put("数学", 80);
map.put("英语", 90);
map.put("语文", 70);
System.out.println(math);
System.out.println(map);
/*
* 根据key值取出对应的value值
* get(K key) - V
*/
int a = map.get("语文");get得到value返回key
System.out.println(a);
/*
* 对某个键值进行判断,判断是否已经存在于集合中
* containsKey(K key) - boolean
*/
boolean flag = map.containsKey("语文");
System.out.println(flag);
实现类:
HashMap:数据结构,是查询性能最高的数据结构
为了尽可能的避免出现链表,重写equals和hashCode()
Map对象的创建
向map集合中放元素
取元素
4.4 有序的Map-- LinkedHashMap
• 使用Map接口的哈希表和链表实现,具有可预知的迭代顺序。此实现与 HashMap 的不同之处在于:
LinkedHashMap维护着一个双向循环链表。此链表定义了迭代顺序,该迭代顺序通常就是存放元素的顺序。
案例:
HashMap中元素取出顺序和Put的顺序不一定一样
LinkedHashMap中元素取出顺序和put的顺序一致
练习:
1.在控制台输入n个学生的信息,存放到List中。
学生信息包括:姓名(String),学号(int),分数(double)
2.一个集合存放的是商品对象,将此集合看成是购物车,
现将购物车中数量为0的商品移除掉 - iterator
public class HomeWork1 {
public static void main(String[] args) {
//创建一个集合当成购物车
List list = new ArrayList();
//创建商品对象
Good phone = new Good("iphonex", 1, 2);
Good tv = new Good("TV", 2, 1);
Good pc = new Good("PC", 3, 3);
pc.setCount(0);
//加入集合
list.add(phone);
list.add(tv);
list.add(pc);
System.out.println(list);
//对购物车中的商品进行检查,移除数量为0的商品
Iterator<Good> it = list.iterator();
while(it.hasNext()){
Good good = it.next();
//对数量进行判断
if(good.getCount()==0){
it.remove();
}
}
System.out.println(list);
public class Good {
private String name;
private int id;
private int count;
public Good() {
super();
// TODO Auto-generated constructor stub
}
public Good(String name, int id, int count) {
super();
this.name = name;
this.id = id;
this.count = count;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
@Override
public String toString() {
return “Good [name=” + name + “, id=” + id + “, count=” + count + “]”;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Good other = (Good) obj;
if (id != other.id)
return false;
return true;
}
3.判断指定学号的学生是否已经录入学校网站(集合表示 contains
//定义一个集合
List list =
new ArrayList();
Student student = new Student(1001, "aa");
list.add(student);
Student student2 = new Student(1001, "aa");
//对此学生是否已经存在进行判断
boolean flag = list.contains(student2);
if(!flag){
list.add(student2);
}
System.out.println(list);