(一)基础知识
1.集合中List,Set和Map都是接口,List和Set实现了Collection接口。
List接口下的实现类:ArrayList,LinkedList和Vector
Set接口下的实现类:HashSet和TreeSet
Map接口下的实现类:HashMap,TreeMap和Hashtable
2.数组必须是相同类型的,集合可以是不同类型的组合(泛型可以限制类型–只能是引用类型)基本数据类型对应的包装类(引用类型)如下:
3.ArrayList,LinkedList和Vector的区别:
ArrayList:底层数据结构是数组,查询快,增删改慢,线程不安全但效率高。
LinkedList:底层数据结构是链表,查询慢,增删改快,线程不安全但效率高。
Vector:底层数据结构是数组,查询快,增删改慢,线程安全但效率低。
4.HashSet和Treeset的区别:
HashSet:底层数据结构是哈希表,元素不排序。
Treeset:底层数据结构是二叉树,元素排序。----自定义类型通过实现接口Comparable中的compareTo()方法进行比较,可以重写compareTo()方法:
@Override
public int compareTo(Object obj) {
//this在前,升序排列:
return this.%-obj.%;//数值类型
//或者:
return this.%.compareTo(obj.%);//String类型
//this在后,降序排列:
return obj.%-this.%;//数值类型
//或者:
return obj.%.compareTo(this.%);//String类型
}
5.HashMap,Hashtable和TreeMap的区别:
HashMap:线程不安全但效率高,键和值都允许有null值存在。源码中public修饰的方法都是同步的(有 synchronized关键字)。父类是Dictionary。
Hashtable:线程安全但效率低,键和值都不允许有null值存在。源码中public修饰的方法都不是同步的(没有 synchronized关键字)。父类是AbstractMap。
TreeMap:实现了排序。TreeMap中默认的对key值的排序为升序,如果要改变其排序可以自己写一个Comparator。
比如下面的例子就实现了对整型key值的降序排序:
class Com implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;//降序
}
}
public class TreeMapTest {
public static void main(String[] args) {
Com com=new Com();
TreeMap<Integer,Integer> map=new TreeMap<Integer,Integer>(com);
map.put(1,2);
map.put(3,2);
map.put(4,2);
map.put(2,2);
System.out.println(map);
}
}
显示结果:
6.List,Set和Map的区别:
List:有序(进出顺序一致),可以有重复的元素。有一个泛型。add()方法添加元素。
Set:无序(进出顺序不一致),元素去重(唯一)----默认调用hashcode()和equals()方法比较是否重复(String类型已经改写过hashcode()和equals()方法,自定义类型需要自己重写hashcode()和equals()定义比较的参数)。有一个泛型。add()方法添加元素。
(补充:想要有序即进出顺序一致的话可以使用Set下的比较特殊的类
—>LinkedHashSet )
Map:无序(进出顺序不一致),键值对形式有两个泛型。put()方法添加键(key)值(value)。
(补充:想要有序即进出顺序一致的话可以使用Map下的比较特殊的类
—>LinkedHashMap )
List和Set是Collection的子接口,但Map不是。
7.Map的三种遍历方式:
(1)keySet():
例:
HashMap<String,String> map=new HashMap<String,String>();
map.put("001", "张三");
map.put("002", "李四");
Set<String> set=map.keySet();
Iterator<String> it=set.iterator();
while(it.hasNext()){
String key=it.next();
System.out.println(key+"----"+map.get(key));
}
(2)values():
例:
HashMap<String,String> map=new HashMap<String,String>();
map.put("001", "张三");
map.put("002", "李四");
Collection<String> c=map.values();
Iterator<String> it=c.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
(3)entrySet(),创建Entry对象:
例:
HashMap<String,String> map=new HashMap<String,String>();
map.put("001", "张三");
map.put("002", "李四");
Collection<Entry<String,String>> c=map.entrySet();
Iterator<Entry<String, String>> it=c.iterator();
while(it.hasNext()){
Entry<String, String> entry=it.next();
System.out.println(entry.getKey()+"----"+entry.getValue());
}
8.Collection和Collections的区别:
java.util.Collection: 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。
java.util.Collections: 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,就像一个工具类,服务于Java的Collection框架。
(二)练习
1.List典型题之List去重:
思路一:定义另一个新集合,如果不包含旧集合的元素则加到新集合里。(自定义类型重写equals())
思路二:将List中的元素放进Set中去重后再放回List中。(自定义类型重写hashCode()和equals())
例:
(1)整型List去重后输出List:
//思路一实现如下:
public static void nonDuplicate(ArrayList<Integer> list){
ArrayList<Integer> listNew=new ArrayList<Integer>();
for (Integer i:list) {
if(!listNew.contains(i)){
listNew.add(i);
}
}
System.out.println(listNew);
}
//思路二实现如下:
public static void nonDuplicate(ArrayList<Integer> list){
HashSet<Integer> set=new HashSet<Integer>();
set.addAll(list);
list.clear();
list.addAll(set);
}
(2)学生List去重后输出List:
//思路一实现如下:
(注:需要重写equals()方法–使其比较学号,姓名和年龄,才能用contains方法比较是否重复–因为List的contains()方法默认调用实体类的equals()方法)
class Student{
private String stuNo;
private String stuName;
private int age;
public Student() {
}
public Student(String stuNo, String stuName, int age) {
this.stuNo = stuNo;
this.stuName = stuName;
this.age = age;
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", stuName=" + stuName + ", age="
+ age + "]";
}
@Override
public boolean equals(Object obj) {
Student s = (Student) obj;
if(s.stuNo.equals(this.stuNo) && s.stuName.equals(this.stuName) && s.age==this.age){
return true;
}
return false;
}
}
public class ListTest {
public static void nonDuplicate(ArrayList<Student> list){
ArrayList<Student> listNew=new ArrayList<Student>();
for (int i=0;i<list.size();i++) {
if(!listNew.contains(list.get(i))){
listNew.add(list.get(i));
}
}
System.out.println(listNew);
}
public static void main(String[] args) {
ArrayList<Student> list=new ArrayList<Student>();
Student s1=new Student("001","张三",19);
Student s2=new Student("002","李四",20);
Student s3=new Student("001","张三",19);
list.add(s1);
list.add(s2);
list.add(s3);
nonDuplicate(list);
}
}
//思路二实现如下:
(注:同上需要先重写实体类学生类的equals()方法,另外在Set比较自定义类型是否相等时还要先比较hashcode是否相等,详述见下方Set去重方法)
class Student{
private String stuNo;
private String stuName;
private int age;
public Student() {
}
public Student(String stuNo, String stuName, int age) {
this.stuNo = stuNo;
this.stuName = stuName;
this.age = age;
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [stuNo=" + stuNo + ", stuName=" + stuName + ", age="
+ age + "]";
}
@Override
public int hashCode() {
return this.stuNo.hashCode()*11+this.stuName.hashCode()*13+this.age*17;
}
@Override
public boolean equals(Object obj) {
Student s = (Student) obj;
if(s.stuNo.equals(this.stuNo) && s.stuName.equals(this.stuName) && s.age==this.age){
return true;
}
return false;
}
}
public class ListTest {
public static void nonDuplicate(ArrayList<Student> list){
HashSet<Student> set=new HashSet<Student>();
set.addAll(list);
list.clear();
list.addAll(set);
System.out.println(list);
}
public static void main(String[] args) {
ArrayList<Student> list=new ArrayList<Student>();
Student s1=new Student("001","张三",19);
Student s2=new Student("002","李四",20);
Student s3=new Student("001","张三",19);
list.add(s1);
list.add(s2);
list.add(s3);
nonDuplicate(list);
}
}
2.(1)Set典型题之自定义类型Set去重:
Set去重比较是否相等的原则:先hashCode()后equals()原则。
即先运行实体类的hashCode()方法来比较hascode是否相等,如果相等则直接认为元素重复,hascode不相等才会需要运行实体类的equals()方法比较是否相等。
重写hashCode()方法原则:尽量乘奇数值如11,13,17等来减少equals()运行的概率—因为先hashcode比较是否相等,不相等的话才会运行equals()方法,hashcode相等的话就不会运行equals()方法了。
(2)Set典型题之自定义类型TreeSet排序:
TreeSet排序的比较原则:通过实现接口Comparable中的compareTo()方法进行比较后排序。
例:
(1)创建一个HashSet集合,在Set中增加4个工人,基本信息如下:
姓名 年龄 工资
zhang 18 3000.2
li 25 500.3
li 25 500.3
zhang 18 3000.2
要求:将三个对象去重,去重条件为:姓名,年龄,工资都一样的对象,认为“相等”,即重复了。
class Worker implements Comparable<Worker>{
private String name;
private int age;
private double salary;
public Worker() {
}
public Worker(String name, int age, double salary) {
super();
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Worker [name=" + name + ", age=" + age + ", salary=" + salary
+ "]";
}
@Override
public int hashCode() {
return this.name.hashCode()*11+this.age*13+String.valueOf(this.salary).hashCode()*17;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Worker){
Worker w=(Worker)obj;
if(this.name.equals(w.name) && this.age==w.age && this.salary==w.salary){
return true;
}
}
return false;
}
@Override
public int compareTo(Worker w) {
return w.salary==this.salary?w.name.compareTo(this.name):(int)(w.salary-this.salary);
}
}
public class HashSetTest {
public static void main(String[] args) {
Worker w1=new Worker("zhang",18,3000.2);
Worker w2=new Worker("li",25,500.3);
Worker w3=new Worker("zhang",18,3000.2);
Worker w4=new Worker("li",25,500.3);
HashSet<Worker> set=new HashSet<Worker>();
set.add(w1);
set.add(w2);
set.add(w3);
set.add(w4);
Iterator<Worker> it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
(2)创建一个TreeSet集合,在Set中增加4个工人,基本信息如下:
姓名 年龄 工资
Zhang1 18 3000.2
li 1 28 500.3
li2 66 500.3
zhang2 45 3000.2
要求:按照工资降序排序,工资一样的,按照姓名降序排序。
class Worker implements Comparable<Worker>{
private String name;
private int age;
private double salary;
public Worker() {
}
public Worker(String name, int age, double salary) {
super();
this.name = name;
this.age = age;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Worker [name=" + name + ", age=" + age + ", salary=" + salary
+ "]";
}
@Override
public int hashCode() {
return this.name.hashCode()*11+this.age*13+String.valueOf(this.salary).hashCode()*17;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Worker){
Worker w=(Worker)obj;
if(this.name.equals(w.name) && this.age==w.age && this.salary==w.salary){
return true;
}
}
return false;
}
@Override
public int compareTo(Worker w) {
return w.salary==this.salary?w.name.compareTo(this.name):(int)(w.salary-this.salary);
}
}
public class TreeSetTest {
public static void main(String[] args) {
Worker w1=new Worker("zhang1",18,3000.2);
Worker w2=new Worker("li1",25,500.3);
Worker w3=new Worker("zhang2",45,3000.2);
Worker w4=new Worker("li2",66,500.3);
TreeSet<Worker> set=new TreeSet<Worker>();
set.add(w1);
set.add(w2);
set.add(w3);
set.add(w4);
Iterator<Worker> it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
3.(1)Map典型题之统计数组中每个数字出现的次数:
思路:Map中的key值放数组中的数字,value值放这个数字出现的次数。
并利用Map具有的特性:如果key值相同,那么后放入的键值对中的value值会冲刷掉之前放的值。
(2)Map典型题之利用TreeMap对key值,value值排序:
思路:自定义一个类实现Comparator并重写它的compare()方法,单对key值排序可以直接传key值,如果要实现对value值排序需要传Entry类对象。
例:
(1)现有一个数组int[] a=new int[]{1,2,3,22,3,4,2,4};请统计出每个数字出现的次数,输出格式如下:数字1出现1次,数字2出现2次,数字……
//思路:数组元素放在map的key值里,出现的次数放在value值里。
public class HashMapTest {
public static void main(String[] args) {
int[] a=new int[]{1,2,3,22,3,4,2,4};
HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<a.length;i++){
if(map.containsKey(a[i])){
map.put(a[i],map.get(a[i])+1);
}else{
map.put(a[i],1);
}
}
Set<Integer> set=map.keySet();
Iterator<Integer> it=set.iterator();
while(it.hasNext()){
Integer key=it.next();
System.out.println(key+"出现了"+map.get(key)+"次");
}
}
}
(2)写一个方法,传入一个int数组,返回一个结果,结果内包含每个数字出现的次数,并按照数字进行降序排序
例如:int[] numbers=new int[]{49,8,49,59,1,30,1,49};
统计完结果为:数字59 次数2,数字49 次数3,数字30 次数1,数字8次数1
class Com implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}
public class TreeMapTest {
public static void sort(int[] numbers){
Com com=new Com();
TreeMap<Integer,Integer> map=new TreeMap<Integer,Integer>(com);
for(int i=0;i<numbers.length;i++){
if(map.containsKey(numbers[i])){
map.put(numbers[i],map.get(numbers[i])+1);
}else{
map.put(numbers[i],1);
}
}
Set<Integer> set=map.keySet();
Iterator<Integer> it=set.iterator();
while(it.hasNext()){
int key=it.next();
System.out.println("数字"+key+" 次数"+map.get(key)+",");
}
}
public static void main(String[] args) {
int[] numbers=new int[]{49,8,49,59,1,30,1,49};
sort(numbers);
}
}
(3)写一个方法,传入一个int数组,返回一个结果,结果内包含每个数字出现的次数,并按照出现的次数降序,如果次数相同则按照数字进行降序排序
例如:int[] numbers=new int[]{49,8,49,59,1,30,1,49};
统计完结果为:数字49 次数3,数字59 次数2,数字30 次数1,数字8次数1
class Comp1 implements Comparator<Map.Entry<Integer,Integer>>{
@Override
public int compare(Entry<Integer, Integer> o1, Entry<Integer, Integer> o2) {
// value降序,value一样按照 key降序
return o2.getValue()-o1.getValue()==0?o2.getKey()-o1.getKey():o2.getValue()-o1.getValue();
}
}
public class TreeMapTest {
public static void sort(int[] numbers){
Comp1 comp1=new Comp1();
TreeMap<Integer,Integer> map=new TreeMap<Integer,Integer>();
for(int i=0;i<numbers.length;i++){
if(map.containsKey(numbers[i])){
map.put(numbers[i],map.get(numbers[i])+1);
}else{
map.put(numbers[i],1);
}
}
List<Map.Entry<Integer, Integer>> list=new ArrayList<>(map.entrySet());
Collections.sort(list,comp1);
for(int i=0;i<list.size();i++){
System.out.println("数字"+list.get(i).getKey()+"出现了"+list.get(i).getValue()+"次");
}
}
public static void main(String[] args) {
int[] numbers=new int[]{49,8,49,59,1,30,1,49};
sort(numbers);
}
}