一、集合的概念
集合和数组一样可以用来存储一组类型相同的元素,但是集合中提供了很多种操作方法,这些操作方法可以非常方便地去实现元素的存储、查询、删除等操作。
集合中有三大要素:
(1)接口:通过接口约束了集合所能完成的操作
(2)实现:对于同一类集合而言,底层的实现有所不同,即接口可能有不同的实现类
(3)算法:不同的实现类中使用不同的算法来实现接口中的方法
二、集合框架图
Collection(接口)--单列集合
List(接口) Set(接口)
ArrayList(实现类) LinkedList Vector HashSet LinkedHashSet TreeSet
Map接口不是继承自Collection接口的,Map和Collction是平级的关系
Map(接口) -- 双列集合
HashMap LinkedHashMap TreeMap ConcurrentHashMap
Collection是所有单列集合的顶级父类接口,为所有的单列集合制定了共同的操作,根据其子接口的不同以及子接口实现类的不同,Collection中提供的方法可能会有不同的实现。
三、List接口
(一)特点
有序、可重复、可为null
(二)常用实现类
I、ArrayList
1.特点
ArrayList底层通过动态数组实现,由于数组本身访问其中的元素只需要通过下标进行访问,所以ArrayList更适合做随机访问操作,但是数组中对元素的增删,会涉及到大量元素的移动,所以ArrayList不适合对元素进行大量的增删。
2、ArrayList对象的创建
List<String> list=new ArrayList<String>();
- 泛型
泛型即参数化类型,可以用在类、方法形参、方法返回值中
在集合中使用泛型可以限制集合中存入的元素的类型,如果类型不匹配则无法通过编译
泛型参数一定必须是引用类型
对于基本类型而言,如果需要在集合中指定泛型,则需要使用该基本数据类型对应的包装类型。
/**
* ArrayList集合的创建
*/
public class Demo01 {
public static void main(String[] args) {
//只能放String类型
List<String> list1 = new ArrayList<String>();
List<String> list2 = new ArrayList<>();
//只能放int类型,泛型参数只能是引用类型
List<Integer> list3 = new ArrayList<>();
}
}
八种基本数据类型对应的包装类型
byte-Byte
short-Short
int-Integer
long-Long
double-Double
float-Float
boolean-Boolean
char-Character
装箱和拆箱
/**
* 基本类型和包装类型的互相转换
*/
public class Demo02 {
public static void main(String[] args) {
//装箱操作
Integer i = 1;
//拆箱操作
int ii = new Integer(3);
//如果在JDK1.5之前需要通过对应的API来实现装箱和拆箱
//但是在JDK1.5开始提供了自动装箱和拆箱操作,不需要通过方法来转换
// 包装->String:
// 包装类型.toString();
Integer i2 = 3;
String i2Str = i2.toString();
System.out.println(i2Str);
i2Str = String.valueOf(i2);
System.out.println(i2Str);
// String->基本类型
// 基本类型对应的包装类型.parse基本类型(String类型)
//注意:如果String表示不是数字,则不能转换为数字
String str3 = "123";
int i3 = Integer.parseInt(str3);
String str4 = "1.23";
double d4 = Double.parseDouble(str4);
System.out.println(i3);
System.out.println(d4);
}
}
包装类型的一些特性
public class Demo03 {
public static void main(String[] args) {
//如果Integer字面的值范围在-128~127之间,则写出的字面量会被缓存
//下一次再写出相同的字面量则不会创建新的对象而是直接从缓存中获取
//所以,有==比较比较的是地址,所以如果位于这个范围中的值,地址一定相同
// Integer a = 1;
// Integer b = 1;
// System.out.println(a == b);//true
// System.out.println(a.equals(b));//true
// Integer a = 128;
// Integer b = 128;
// System.out.println(a == b);//false
// System.out.println(a.equals(b));//true
//new出来的对象一定不会和其他对象是同一个对象,所以带new出来对象的==比较一定不会一样
// Integer a = new Integer(1);
// Integer b = new Integer(1);
// System.out.println(a == b);//false
// System.out.println(a.equals(b));//true
// Integer a = 1;
// Integer b = new Integer(1);
// System.out.println(a == b);//false
// System.out.println(a.equals(b));//true
//结论:对于包装类型值的比较应该使用equals进行比较,比较的是内容
}
}
Collection接口中的方法
import java.util.ArrayList;
import java.util.List;
/**
* Collection接口中的方法
*/
public class Demo04 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
// boolean add(E e)
// 用于向集合中添加新元素,该方法会将给定的元素添加进集合,若添加成功则返回true,否则返回false
boolean result = list.add("Java");
list.add("C#");
list.add("C++");
System.out.println(result);
System.out.println(list);
// boolean contains(Object o)
// 用于判断给定的元素是否被包含在集合中。若包含则返回true,否则返回false
//注意:在List集合中,判断是否存在的依据是equals比较是否一样 参考:Demo05
//在Set集合中,该方法的判断依据有所不同
System.out.println(list.contains("C#"));
// int size()
// 该方法用于返回当前集合中的元素总数
System.out.println(list.size());
// void clear()
// 用于清空当前集合
list.clear();
System.out.println(list);
// boolean isEmpty()
// 判断当前集合是否为空
System.out.println(list.isEmpty());
list.add("JavaScript");
System.out.println(list.isEmpty());
// boolean addAll(Collection <? Extends E>c)
// 该方法需要传入一个集合,并将该集合中的所有元素添加到当前集合中。
// 如果Collection因调用而发生改变,则返回true
List<String> list1 = new ArrayList<>();
list1.add("java");
list1.add("c");
List<String> list2 = new ArrayList<>();
list2.add("python");
list2.add("php");
System.out.println(list1.addAll(list2));
System.out.println(list1);
List<String> list3 = new ArrayList<>();
System.out.println(list1.addAll(list3));
// boolean containsAll(Collection<?> c)
// 该方法用于判断当前集合是否包含给定集合中的所有元素,若包含则返回true
List<String> list4 = new ArrayList<>();
list4.add("c");
list4.add("php");
//list4.add("ruby");
System.out.println(list1.containsAll(list4));
// boolean remove(Object o)
// 移除集合中的指定元素,根据equals()来判断
System.out.println(list1.remove("c"));
System.out.println(list1);
System.out.println(list1.remove("c"));
System.out.println(list1);
// boolean removeAll(Collection<?> c)
// 从集合中移除指定的子集合,如果操作改变了集合,就返回true
List<String> list5=new ArrayList<>();
list5.add("python");
list5.add("php");
System.out.println(list1.removeAll(list5));
System.out.println(list1);
System.out.println(list1.removeAll(list5));
System.out.println(list1);
}
}
List中的contains方法
如果要在List中判断元素是否存在,需要制定规则,具体的比较逻辑由泛型参数对应的数据类型的equals方法来决定
/**
* List中的contains方法
*/
public class Demo05 {
public static void main(String[] args){
List<String> list=new ArrayList<>();
list.add(new String("C#"));
list.add("C++");
System.out.println(list.contains("C#"));
System.out.println("===================");
List<Integer> list2=new ArrayList<>();
list2.add(new Integer(3));
list2.add(4);
list2.add(1);
System.out.println(list2.contains(3));
System.out.println("===================");
List<Emp> emps=new ArrayList<>();
emps.add(new Emp("Tom",21));
emps.add(new Emp("Jack",25));
emps.add(new Emp("Lucy",20));
Emp emp=new Emp("Tony",30);
emps.add(emp);
System.out.println(emps.contains(emp));
//如果要在List中判断元素是否存在,需要制定规则,具体的比较逻辑由泛型参数对应
//的数据类型的equals方法来决定
System.out.println(emps.contains(new Emp("Tom",21)));
}
}
import java.util.Objects;
public class Emp implements Comparable<Emp> {
private String name;
private int age;
public Emp() {
}
public Emp(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Emp emp = (Emp) o;
return age == emp.age &&
Objects.equals(name, emp.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
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;
}
/**
* 该方法可以实现排序规则
*
* @param o
* @return
*/
@Override
public int compareTo(Emp o) {
//this:当前对象
//o:被比较的对象
//this-o:升序
//o-this:降序
return o.age - this.age;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
List接口中的方法
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* List接口中的方法
*/
public class Demo06 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("c");
list.add("javascript");
// E get(int index)
// 获取集合中指定下标对应元素,下标从0开始(下标不存在报异常)
System.out.println(list.get(1));
// E set(int index,E element)
// 将给定的元素插入给定位置,并将原位置的元素返回
String oldEle = list.set(2, "JSP");
System.out.println(oldEle);
System.out.println(list);
// void add(int index,E element)
// 将给定元素插入到指定位置,原位置及后续元素都顺序向后移动
list.add(2, "python");
System.out.println(list);
// E remove(int index)
// 删除给定位置的元素,并将被删除的元素返回
String removeEle = list.remove(2);
System.out.println(removeEle);
System.out.println(list);
// List<E> subList(int fromIndex,int toIndex)
// 获取子集合,参数是截取子List的首尾下标(前包括,后不包括)
List<String> subList = list.subList(1, 3);
System.out.println(subList);
// subList获取的list与原list占有相同的存储空间,对子list操作会影响原list
subList.set(0, "C#");
System.out.println(list);
// <T> T[] toArray(T[] a)
// List转数组
String[] strs = list.toArray(new String[list.size()]);
System.out.println(Arrays.toString(strs));
// Arrays类静态方法:static <T> List<T> asList(T....a)
// 数组转换为List
Integer[] a = {1, 2, 3, 4, 5};
List<Integer> nums = Arrays.asList(a);
System.out.println(nums);
nums = Arrays.asList(2, 3, 4, 5);
System.out.println(nums);
//返回的集合不可对其进行增删元素,并且对集合元素的修改会影响数组对应的元素
// nums.add(100);
nums.set(1, 100);
System.out.println(nums);
}
/**
* 可变长参数,当参数个数不确定时,可以声明,1.5后的新特性
* 可变长参数必须是方法中的最后一个参数=>一个方法中只能有一个变长参数
*
* @param strs
*/
public void method(String... strs) {
}
public void method(int num, String... strs) {
//可变长参数可以理解为就是一个数组
System.out.println(strs[0]);
System.out.println(strs.length);
method();
method("1");
method("1","2");
method("1","2","3");
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 使用get方法进行集合遍历,并将每个字符串转换为大写并输出,
* 将索引为1的元素替换为javascript并输出集合,交换索引1,3上的元素
*/
public class Demo09 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("c");
list.add("python");
list.add("c#");
list.add("ruby");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).toUpperCase());
}
list.set(1, "javascript");
System.out.println(list);
String index1Val = list.get(1);
String index3Val = list.get(3);
list.set(1, index3Val);
list.set(3, index1Val);
System.out.println(list);
删除Arraylist操作
import java.util.ArrayList;
import java.util.List;
/**
* 删除一个ArrayList中的所有元素
*/
public class Demo07 {
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("c");
list.add("javascript");
//java、c++、c、javascript
for(int i=list.size()-1;i>=0;i--){
list.remove(i);
}
System.out.println(list);
}
}
import java.util.ArrayList;
import java.util.List;
/**
* 不使用循环,删除索引2-4的元素
*/
public class Demo08 {
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("c");
list.add("javascript");
list.add("c#");
list.add("ruby");
List<String> subList=list.subList(2, 5);
//1.
//list.removeAll(subList);
//2.
subList.clear();
System.out.println(list);
}
}
四、Iterator:迭代器
(一)Iterator接口的作用
Iterator是一个接口,集合在重写Collection的iterator()方法时利用内部类提供了迭代器的实现。
Iterator提供了统一的遍历集合元素的方式,其提供了遍历集合的两个相关方法。
(二)Iterator接口的使用
1、获取Iterator迭代器对象
通过 集合对象.iterator() 进行获取
2、
boolean hasNext()
判断集合是否还有元素可以访问。(初始位置在第一个元素之前)
E next()
返回迭代的下一个元素,并将指针向前移动一个元素
void remove()
在调用该方法前,必须通过迭代器的next()方法迭代过元素,那么删除的就是这个元素,
并且不能再次调用remove方法(异常),除非再次调用next()方可再次调用。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Iterator:迭代器
*/
public class Demo10 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("c");
list.add("python");
list.add("c#");
list.add("ruby");
//1.先获取迭代器对象
Iterator<String> it = list.iterator();
//2.判断有无后续元素可以访问
while (it.hasNext()) {
//3.如果有后续元素,就移动到后续元素上
//此时可以对该元素进行访问或删除
String ele = it.next();
//删除操作:一定要先通过next方法得到要删除的元素,才能进行删除
// it.remove();
System.out.println(ele);
}
System.out.println(list);
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
/**
* ListIterator
*/
public class Demo11 {
public static void main(String[] args){
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("c");
list.add("python");
list.add("c#");
list.add("ruby");
ListIterator<String> it=list.listIterator();
System.out.println("向后迭代...");
while(it.hasNext()){
String ele=it.next();
System.out.println(ele);
}
System.out.println("==================");
System.out.println("向前迭代...");
while(it.hasPrevious()){
String ele=it.previous();
System.out.println(ele);
}
}
}
- 增强for循环
Java5.0之后推出了一个新的特征,增强for循环(也叫新循环)。
该循环不通用于传统循环的工作,其只用于遍历集合或数组。
for(元素类型 数组中元素的别名:集合或数组){
//循环体
}
新循环并非新的语法,在编译过程中,编译器会将新循环转换为迭代器模式。所以新循环本质上是迭代器。
通过观察语法可以发现增强for循环不适用于遍历过程中需要考虑下标索引的情况!
import java.util.ArrayList;
import java.util.List;
/**
* 增强for循环(新循环、forEach循环)
* 在运行前先转换成迭代器,所以增强for的本质就是迭代器模式
*
*/
public class Demo12 {
public static void main(String[] args){
//可以用来遍历数组
//可以用来遍历集合
List<String> list = new ArrayList<>();
list.add("java");
list.add("c++");
list.add("c");
list.add("python");
list.add("c#");
list.add("ruby");
for(String str:list){
System.out.println(str);
}
}
}
List接口
(一)特点
有序、可重复、可为null
(二)常用实现类
1、ArrayList
ArrayList底层通过动态数组实现,由于数组本身访问其中的元素只需要通过下标进行访问,所以ArrayList更适合做随机访问操作,但是数组中对元素的增删,会涉及到大量元素的移动,所以ArrayList不适合对元素进行大量的增删。
2、LinkedList
LinkedList通过双向链表来实现,对于元素的增删,只需要修改某一个表项中前驱和后驱的指向,并不需要对元素进行大量的移动。但是如果要对元素进行随机访问,则需要从头开始往后进行查询,所以LinkedList不适合做随机访问。
import java.util.LinkedList;
import java.util.List;
/**
* LinkedList
*/
public class Demo13 {
public static void main(String[] args){
List<String> list=new LinkedList<>();
//用法同ArrayList
}
}
3.Vector(过时)
只需要注意和ArrayList的区别,实际开发尽量不要使用。
(三)List排序
- 自定义排序(冒泡排序)
- 通过Collections.sort进行排序
- Collection和Collections不要混淆
java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式。
java.util.Collections 是一个包装类。它包含有各种有关集合操作的静态多态方法。此类不能实例化,是一个工具类。
//如果要对自定义类型进行排序,则需要指定排序规则
//1.调用Collections.sort(list);方法并且在集合对应的元素类型中实现Comparable接口
//注意:一旦对自定类型指定了Comparable接口以后,其默认排序规则就确定了
Collections.sort(emps);
System.out.println(emps);
import java.util.Objects;
public class Emp implements Comparable<Emp> {
private String name;
private int age;
public Emp() {
}
public Emp(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Emp emp = (Emp) o;
return age == emp.age &&
Objects.equals(name, emp.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
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;
}
/**
* 该方法可以实现排序规则
*
* @param o
* @return
*/
@Override
public int compareTo(Emp o) {
//this:当前对象
//o:被比较的对象
//this-o:升序
//o-this:降序
return o.age - this.age;
}
@Override
public String toString() {
return "Emp{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
//2.也可以指定临时排序规则
//通过匿名内部类实现Comparator接口,并重写接口中的比较方法
//临时指定的排序规则,优先级更高,可以覆盖默认规则
Collections.sort(emps, new Comparator<Emp>() {
@Override
public int compare(Emp o1, Emp o2) {
//o1-o2:升序
//o2-o1:降序
return o1.getAge() - o2.getAge();
}
});
System.out.println(emps);
import com.sy.collection.demo.entity.Emp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* List集合的排序
*/
public class Demo14 {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>();
nums.add(3);
nums.add(1);
nums.add(5);
nums.add(4);
nums.add(2);
//数值按照自然数顺序排列
Collections.sort(nums);
System.out.println(nums);
System.out.println("==========================");
List<String> strs = new ArrayList<>();
strs.add("c");
strs.add("java");
strs.add("vb");
strs.add("e");
strs.add("c++");
strs.add("ruby");
strs.add("python");
//字符串按照字典顺序排列
Collections.sort(strs);
System.out.println(strs);
System.out.println("==========================");
List<Emp> emps = new ArrayList<>();
emps.add(new Emp("Tom", 23));
emps.add(new Emp("Jack", 21));
emps.add(new Emp("Tony", 25));
emps.add(new Emp("Smith", 20));
//如果要对自定义类型进行排序,则需要指定排序规则
//1.调用Collections.sort(list);方法并且在集合对应的元素类型中实现Comparable接口
//注意:一旦对自定类型指定了Comparable接口以后,其默认排序规则就确定了
Collections.sort(emps);
System.out.println(emps);
//2.也可以指定临时排序规则
//通过匿名内部类实现Comparator接口,并重写接口中的比较方法
//临时指定的排序规则,优先级更高,可以覆盖默认规则
Collections.sort(emps, new Comparator<Emp>() {
@Override
public int compare(Emp o1, Emp o2) {
//o1-o2:升序
//o2-o1:降序
return o1.getAge() - o2.getAge();
}
});
System.out.println(emps);
}
}
六、Set接口
(一)特点
无序且不重复集合
(二)实现类
1.HashSet
底层由哈希算法来决定,元素在存储过程中,通过哈希函数来决定要存储在什么地方,由于计算过程中,可能第一个元素计算出来的内存在下面,也有可能第二个元素计算出来的结果反而在前面,因此导致了HashSet中元素的无序。
对于HashSet中元素的不重复性:首先先去比较两个对象的hashCode值是否一样(默认就是两个对象的内存地址,所以new出来的对象,hashCode默认肯定不同)
当hashCode不相同的时候,直接认为两个对象就不是同一个对象
如果hashCode一样,则对equals进行判断(因为不同的对象hashCode方法在重写后可能得到相同的结果),所以进一步比较equals方法,如果此时equals方法相同,才说明两个对象是同一个对象。
注意:对于HashSet集合中的contains()以及containsAll()方法的判断依据也是如此!
import com.sy.collection.demo.entity.Emp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* HashSet
*/
public class Demo15 {
public static void main(String[] args){
Set<String> strs = new HashSet<>();
strs.add("c");
strs.add("c");
strs.add(new String("c"));
strs.add("java");
strs.add("vb");
strs.add("e");
strs.add("c++");
strs.add("ruby");
strs.add("python");
//结果:无序且不重复
System.out.println(strs);
Set<Emp> emps = new HashSet<>();
Emp e1=new Emp("Tom", 23);
Emp e2=new Emp("Tom", 23);
emps.add(e1);
emps.add(e2);
System.out.println(e1.hashCode());
System.out.println(e2.hashCode());
emps.add(new Emp("Jack", 21));
emps.add(new Emp("Tony", 25));
emps.add(new Emp("Smith", 20));
System.out.println(emps);
}
}
2.LinkedHashSet
LinkedHashSet继承自HashSet。
LinkedHashSet内部使用的是LinkedHashMap。
LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的。
尽管能够看到遍历序和存入序相同,但是其内部依然是无序的,内部通过LinkedHashMap保存了元素存入时的顺序。
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* LinkedHashSet
*/
public class Demo16 {
public static void main(String[] args){
Set<String> strs = new LinkedHashSet<>();
strs.add("c");
strs.add("c");
strs.add(new String("c"));
strs.add("java");
strs.add("vb");
strs.add("e");
strs.add("c++");
strs.add("ruby");
strs.add("python");
System.out.println(strs);
}
}
3.TreeSet
底层通过二叉树实现的Set集合,会根据排序规则对数组中的元素进行排序
//1.调用的是TreeSet的无参构造
//TreeSet中放入的元素需要具有排序规则,其中的元素,需要实现Comparable接口
//Set<Student> students = new TreeSet<>();
//2.调用TreeSet的有参构造方法
//可以在参数中通过Comparator接口临时指定排序规则
Set<Student> students=new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge()-o1.getAge();
}
});
students.add(new Student("Tom", 21));
students.add(new Student("Lucy", 23));
students.add(new Student("Jack", 25));
System.out.println(students);
import java.util.*;
/**
* TreeSet
*/
public class Demo17 {
public static void main(String[] args) {
Set<String> strs = new TreeSet<>();
strs.add("c");
strs.add("c");
strs.add("java");
strs.add("vb");
strs.add("e");
strs.add("c++");
strs.add("ruby");
strs.add("python");
System.out.println(strs);
System.out.println("=====================");
Set<Integer> nums = new TreeSet<>();
nums.add(3);
nums.add(1);
nums.add(5);
nums.add(4);
nums.add(2);
System.out.println(nums);
System.out.println("=====================");
//1.调用的是TreeSet的无参构造
//TreeSet中放入的元素需要具有排序规则,其中的元素,需要实现Comparable接口
//Set<Student> students = new TreeSet<>();
//2.调用TreeSet的有参构造方法
//可以在参数中通过Comparator接口临时指定排序规则
Set<Student> students=new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getAge()-o1.getAge();
}
});
students.add(new Student("Tom", 21));
students.add(new Student("Lucy", 23));
students.add(new Student("Jack", 25));
System.out.println(students);
}
}
class Student
// implements Comparable<Student>
{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
// @Override
// public int compareTo(Student o) {
// return this.age - o.age;
// }
}
List-->Set
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Demo18 {
public static void main(String[] args){
List<String> list=new ArrayList<>();
list.add("1");
list.add("2");
//List->Set
Set<String> set=new HashSet<>(list);
System.out.println(set);
}
}
七、Map接口
(一)定义
Map代表的是一种查找表数据结构,表中有两个列,一列表示key(键),另外一列表示value(值),在Map中可以根据键来查找值。对于Map中的键是不可以重复的。
(二)实现类
- HashMap
基于哈希算法实现,(可以结合HashSet一起记忆),HashMap中通过put添加元素,插入顺序,未必就是最后的遍历顺序,另外HashMap中判断键是否相等和存在的方式也是通过equals方法和hashCode方法一同来判断的。
HashMap中容量、加载因子以及两者之间的关系(了解!)
import java.util.HashMap;
import java.util.Map;
/**
* HashMap
*/
public class Demo01 {
public static void main(String[] args) {
//Map集合需要指定两个泛型参数
//第一个参数表示键的类型,第二个参数表示值的类型
Map<Integer, String> map = new HashMap<>();
// V put(K key,V value)
// Map集合中定义了向Map集合中存放元素的put方法
map.put(1, "Tom");
map.put(2, "Jack");
System.out.println(map);
//Map中的key不能重复,如果添加相同的key,则会将已经存在key后面的value替换掉
//Map中比较key是否相同的依据和Set中是几乎一致的
//HashMap中通过key对应类型的equals方法和hashCode方法来进行比较
map.put(2, "Lucy");
System.out.println(map);
//put方法本身具有返回值,其返回值为原来该key后面对应的value值,如果该key原来不存在,则返回null
System.out.println(map.put(2, "Tony"));
System.out.println(map.put(3, "Simth"));
// V get(Object key)
// Map集合定义了从Map中获取元素的get方法
// 返回参数key所对应的Value对象,如果不存在则返回null
System.out.println(map.get(3));
System.out.println(map.get(4));
// containsKey()方法
// boolean containsKey(Object key)——Map中定义了判断某个key是否存在的方法
// 若map中含给定key就返回true,否则返回false,
System.out.println(map.containsKey(3));
System.out.println(map.containsKey(6));
}
}
import java.util.*;
/**
* Map集合的遍历
*/
public class Demo02 {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "Tom");
map.put(2, "Jack");
map.put(3, "Tony");
//1.遍历所有的key
//Set<K> keySet
//该方法会将map中所有key存入一个Set集合后返回
Set<Integer> keys = map.keySet();
for (Integer key : keys) {
System.out.println(key + "=" + map.get(key));
}
//2.遍历所有的key-value对
//Set<Entry<K,V>> entrySet()
//将map中的每一个对象封装为一个Entry对象存入Set集合中返回
Set<Map.Entry<Integer, String>> entries = map.entrySet();
for (Map.Entry<Integer, String> ele : entries) {
System.out.println(ele.getKey() + "=" + ele.getValue());
}
//3.遍历所有的value(不常用!!)
//Collection<V> values()
//将map中的每一个value放入Collection集合
Collection<String> values = map.values();
System.out.println(values);
}
}
2.TreeMap
//TreeMap中可以根据key来进行排序,其排序规则和TreeSet中是一致的
//key要具有排序规则
// (1)直接在key对应的类型中实现Comparable接口
// (2)在TreeMap的构造其中为key临时指定比较规则
- LinkedHashMap
和HashMap基本一样,继承自HashMap,但是可以保证其中元素的存入顺序和取出顺序一致
/**
* 现有字符串“good good study,day day up”,统计各个字符出现的次数。
*/
public class Demo03 {
public static void main(String[] args) {
String str = "good good study,day day up";
//Map中的key为字符
//Map中的value为次数
//HashMap中存入序和迭代序不一定相同
Map<Character, Integer> map = new HashMap<>();
//LinkedHashMap中可以保证存入序和迭代序一致
map = new LinkedHashMap<>();
//TreeMap中可以根据key来进行排序,其排序规则和TreeSet中是一致的
//key要具有排序规则
// (1)直接在key对应的类型中实现Comparable接口
// (2)在TreeMap的构造其中为key临时指定比较规则
map=new TreeMap<>();
//依次遍历字符串中的每个字符
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
//如果Map中没有这个字符,则其为第一次出现
if (!map.containsKey(c)) {
map.put(c, 1);
}
//如果Map中有这个字符了,则对原来该字符对应的次数加1
else {
map.put(c, map.get(c) + 1);
}
}
for (Map.Entry<Character, Integer> ele : map.entrySet()) {
System.out.println(ele.getKey() + "出现了" + ele.getValue() + "次");
}
}
}
- ConcurrentHashMap(了解)
提高写入的性能
Hashtable和HashMap的区别?
八、队列和栈
(一)队列
将线性表限制为一端进去,一端出来,其中先进去的元素一定会先出来,即先进先出原则。
双端队列
两端都能进行进出的队列
import java.util.LinkedList;
import java.util.Queue;
/**
* 队列
*/
public class Demo01 {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
//入队
queue.offer("Tom");
System.out.println(queue);
queue.offer("Jack");
System.out.println(queue);
//peek操作
System.out.println(queue.peek());
System.out.println(queue.peek());
//出队
while (queue.size() != 0) {
System.out.println(queue.poll());
}
System.out.println(queue);
}
}
(二)栈
将双端队列限制为只能从一端进出,则此时先进去的元素后后出来,即先进后出(后进先出)
import java.util.Stack;
/**
* Stack:栈
*/
public class Demo01 {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
//入栈
stack.push("Tom");
stack.push("Jack");
stack.push("Tony");
System.out.println(stack);
//出栈
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
System.out.println(stack);
}
}
练习:自己去实现栈数据结构,提供入栈,出栈,判断栈为空或为满的方法。
底层数据结构采用数组来实现(不是集合!)