集合
概念
对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
和数组区别
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型
- 位置:java.util.*;
Collection集合
定义
Collection:该体系结构的根接口,代表一组对象,成为“集合”,多个⼦接⼝和实现类, 我们称之为Collection体系
Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。
分类
- List接口:有序、有下标、元素可以重复
- Queue 队列,:除优先级外, 保持先进先出的原则
- Set接口:无序、无下标、元素不能重复
使用
- 添加:add(“元素”);
- 删除:remove(“元素”);
- 遍历:foreach或者迭代器,集合在遍历时不可以删除元素,除非迭代器删除元素
for (Object object : collection) { - 迭代器:Iterator iterator = collection.iterator();
Iterator:hasNext()、next()、remove() - 判断:contains(“元素”)、isEmpty()
public class Test1 {
public static void main(String[] args) {
//创建ArrayList
Collection collection = new ArrayList();
//添加
collection.add("苹果");
collection.add("香蕉");
collection.add("西瓜");
/* //查看元素个数
System.out.println(collection.size());
//显示集合元素值
System.out.println(collection);
//删除
collection.remove("西瓜");
System.out.println(collection);
//清空
collection.clear();
System.out.println(collection.size());*/
//遍历
/* 第一种方案:foreach遍历
for (Object object : collection) {
System.out.println(object);
}*/
/*第二种方案:使用迭代器(迭代器专门用来遍历集合的一种方法)
* Iterator有三个方法:
* hasNext():如果仍有元素可以迭代,则返回 true。
* next(): 返回迭代的下一个元素。
* remove():删除当前元素
* */
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
String s = (String) iterator.next();
System.out.println(s);
//迭代器迭代期间集合不可以删除元素,除非迭代器删除
//collection.remove(s); 报错:java.util.ConcurrentModificationException
//iterator.remove(); //迭代器可以删除
}
//System.out.println(collection.size());
/* for (int i = 0; i < collection.size(); i++) {
System.out.println(iterator.next());
}*/
//判断某个元素是否存在
System.out.println(collection.contains("香蕉"));
//判断集合是否为空
System.out.println(collection.isEmpty());
}
}
示例
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test2 {
public static void main(String[] args) {
//创建Collection集合
Collection collection = new ArrayList();
//创建Student对象
Student student1 = new Student(21, "jack");
Student student2 = new Student(14, "mike");
Student student3 = new Student(19, "night");
//添加元素
collection.add(student1);
collection.add(student2);
collection.add(student3);
//System.out.println(collection.size());
//System.out.println(collection.toString());
//删除元素
//collection.remove(student1);
//System.out.println(collection.size());
//System.out.println(collection.toString());
//清空元素
//只是在集合中删除,但是student1依旧存在,删除的是student1在集合中的指针
//collection.clear();
//遍历元素
/* for (Object obj:collection) {
Student student=(Student)obj;
System.out.println(student);
}*/
Iterator iterator = collection.iterator();
while (iterator.hasNext()) {
Student str = (Student) iterator.next();
System.out.println(str);
}
}
}
class Student {
private int age;
private String name;
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public Student() {
}
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;
}
}
带All的⽅法
- boolean addAll(Collection c) 将指定 collection 中的所有元素都添加到此 collection 中
- boolean removeAll(Collection c) 移除此 collection 中那些也包含在指定 collection 中的所有元素
- boolean containsAll(Collection c) 如果此 collection 包含指定 collection 中的所有元素
- boolean retainAll(Collection c) 仅保留此 collection 中那些也包含在指定 collection 的元素
public static void main(String[] args) {
Collection<Student> collection = new ArrayList<>();
Student student1 = new Student("⼩红", 18);
Student student2 = new Student("⼩明", 19);
collection.add(student1); //添加⽅法
collection.add(student2);
Collection<Student> collection2 = new ArrayList<>();
Student student3 = new Student("⼩辉", 18);
collection2.add(student1);
collection2.add(student3);
//将collection2集合中的元素添加到collection集合中
collection.addAll(collection2);
System.out.println(collection.size());//结果: 4
//判断collection集合中是否包含collection2集合中的所有元素
boolean flg = collection.containsAll(collection2);
System.out.println(flg);//结果: true
//仅在collection中保留两个集合中相同的元素
collection.retainAll(collection2);
System.out.println(collection.size());//结果: 3
}
List接口
List
定义
List集合:有序、有下标、元素可以重复的
集合体系
- ArrayList底层使用数组(线程不安全)
- LinkedList底层使用链表
- Vector底层使用数组(线程安全,不推荐使用)
迭代器
定义
迭代(遍历)集合中存储的元素
遍历形式
- 获取迭代器
- 调式hasNext()方法判断下一个元素是否存在
- 调用next()方法获取元素
public static void main(String[] args) {
Collection<Student> collection = new ArrayList<>();
Student student1 = new Student("⼩红", 18);
Student student2 = new Student("⼩明", 19);
Student student3 = new Student("⼩辉", 18);
collection.add(student1); //添加⽅法
collection.add(student2);
collection.add(student3);
//for循环的形式
for(Iterator<Student> it = collection.iterator();it.hasNext();){
Student student = it.next();
System.out.println(student);
}
//while循环的形式
Iterator<Student> it = collection.iterator();
while(it.hasNext()){
Student student = it.next();
System.out.println(student);
}
}
方法
-
创建集合:
List list = new ArrayList();
-
添加元素:
添加:list.add(“小米”);
指定下标位置添加:list.add(0, “华为”); -
删除、清空
根据下标删除,会出现数组越界报错,否则转成Object类型\包装类
删除(元素下标):list.remove(2);
根据下标删除,会出现数组越界报错,否则转成Object类型\包装类list.remove((Object)20); list.remove(new Integer(20));
删除(元素值)list.remove(“苹果”);
-
清空:list.clear();
-
遍历
-
for循环遍历:
for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}
-
增强for遍历:
for (Object obj : list) {System.out.println(obj); }
-
迭代器遍历:
Iterator iterator=list.iterator(); while (iterator.hasNext()){System.out.println(iterator.next());}
-
列表迭代器遍历:
正向遍历:ListIterator listIterator=list.listIterator(); while (listIterator.hasNext(){System.out.println(listIterator.nextIndex(+":"+listIterator.next());}
反向遍历:
while (listIterator.hasPrevious()){System.out.println(listIterator.previousIndex()+":"+listIterator.previous());}
-
-
判断
判断元素:list.contains(“小米”)
判断是否为空:list.isEmpty() -
获取元素值下标位置:list.indexOf(“小米”)
-
返回子集合(前闭后开):List subList=list.subList(1,2);
示例:
package util;
import java.util.*;
/**
* List:有序、有下标、可以重复
*/
public class Test3 {
public static void main(String[] args) {
//创建List集合
List list = new ArrayList();
//添加元素
list.add("小米");
//在指定下标位置添加元素
list.add(0, "华为");
list.add("苹果");
//System.out.println(list.size());
//System.out.println(list.toString());
//删除
//list.remove(2); //元素下标
//list.remove("苹果"); //元素值
//System.out.println(list.toString());
//清空
//list.clear();
//遍历
//使用for循环遍历
/*for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}*/
//使用增强for
/*for (Object obj : list) {
System.out.println(obj);
}*/
//使用迭代器遍历
/* Iterator iterator=list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}*/
//使用列表迭代器遍历str
//可以正向、反向遍历、添加、修改、删除元素
ListIterator listIterator=list.listIterator();
//正向遍历
while (listIterator.hasNext()){
System.out.println(listIterator.nextIndex()
+":"+listIterator.next());
}
//反向遍历
while (listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex()
+":"+listIterator.previous());
}
//判断
System.out.println(list.contains("小米"));
System.out.println(list.isEmpty());
//获取位置
System.out.println(list.indexOf("小米"));
}
}
List实现类
ArrayList
数组结构实现,查询快、增删慢
JDK1.2版本后,运行效率快,线程不安全
1、创建对象:ArrayList arrayList = new ArrayList();
2、添加、删除、清空元素
添加:arrayList.add(30);
删除:arrayList.remove(new Integer(20));
清空:arrayList.clear();
3、遍历:fori、foreach、Iterator、ListIterator
源码分析
默认容量:DEFAULT_CAPACITY = 10;如果没有添加元素,容量是0
集合创建是默认容量为0,添加元素扩容到10,再次扩容是之前的1.5倍
存放元素的数组:elementData
实际的元素个数:size
add()添加元素代码流程:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
Vector
数组结构实现,查询快、增删慢
JDK1.0版本,运行效率慢,线程安全
1、创建对象:Vector vector = new Vector<>();
2、添加、删除、清空元素
添加:vector.add(“草莓”);
删除:vector.remove(“香蕉”);
清空:vector.clear();
3、遍历:fori、foreach、Iterator、ListIterator、Enumeration
Enumeration enumeration=vector.elements();
while (enumeration.hasMoreElements()){
System.out.println(enumeration.nextElement());}
LinkedList
特点
链表结构实现,增删快,查询慢
双向链表:每一个节点既记录上一个节点位置,也记录下一个节点位置
与ArrayList数组区别
-
ArrayList --数组结构,一片连续的空间
增删慢,查询快
- 现有数组长度足够,末尾增加 --不存在快慢问题
- 现有数组长度不够,末尾增加 --需要创建新数组,复制原来数组的数据,增加新元素
- 现有长度足够,中间增加 --将指定位置之后的元素每一个向后挪动一位
- 现有数组长度不足,中间增加 --数组扩容+挪动数组中数组的位置
-
LinkedList --链表结构
增删快,查改询慢
- 增删:只需要改动前后两个节点的指向就可以将元素插入、删除
- 查改:只有找到前一个元素,才能找到下一个元素。必须从头开始
使用
-
创建对象:
LinkedList linkedList = new LinkedList();
-
添加、删除、清空元素
-
添加
list.add("first"); list.add("second"); list.add(0, "zera");
-
删除
//头部移除 System.out.println(list.remove()); System.out.println(list.poll()); System.out.println(list.peekFirst()); //尾部移除 System.out.println(list.pollLast()); //仅仅查看,不移除 System.out.println(list.peek()); System.out.println(list.peekFirst()); System.out.println(list.pollLast());
-
清空
list.clear();
-
-
遍历:fori、foreach、Iterator、ListIterator
源码
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
ArrayList、Vector、LinkedList的使用演示
package util;
import java.util.*;
public class Demo1 {
public static void main(String[] args) {
//ArrayListTest();
//VectorTest();
//LinkedListTest();
}
/**
* ArrayList的使用
* 数组存储结构,遍历快,增删慢
*/
public static void ArrayListTest() {
//创建对象
ArrayList arrayList = new ArrayList();
//添加元素
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(40);
//System.out.println(arrayList.size());
//System.out.println(arrayList.toString());
//删除元素
//arrayList.remove(new Integer(20));
//System.out.println(arrayList.toString());
//清空元素
//arrayList.clear();
//遍历元素
/*for (int i = 0; i < arrayList.size(); i++) {
System.out.println(arrayList.get(i));
}*/
/*for (Object obj:arrayList) {
System.out.println(obj);
}*/
/* Iterator iterator=arrayList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}*/
//正向遍历
ListIterator listIterator = arrayList.listIterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
//反向遍历
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
//判断元素
System.out.println(arrayList.contains(10));
System.out.println(arrayList.isEmpty());
//查找
System.out.println(arrayList.indexOf(30));
}
/**
* Vector的使用
* 数组结构
*/
public static void VectorTest() {
//创建对象
Vector vector = new Vector<>();
//添加元素
vector.add("草莓");
vector.add("香蕉");
vector.add("西瓜");
//System.out.println(vector.size());
//System.out.println(vector.toString());
//删除元素
//vector.remove("香蕉");
//vector.remove(1);
//清空元素
//vector.clear();
//遍历元素
/* for (int i = 0; i <vector.size() ; i++) {
System.out.println(vector.get(i));
}*/
/*for (Object obj : vector) {
System.out.println(obj);
}*/
/* Iterator iterator=vector.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}*/
/* ListIterator listIterator = vector.listIterator();
while (listIterator.hasNext()) {
System.out.println(listIterator.next());
}
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}*/
//使用枚举器遍历
Enumeration enumeration = vector.elements();
while (enumeration.hasMoreElements()) {
System.out.println(enumeration.nextElement());
}
//判断
System.out.println(vector.contains("西瓜"));
System.out.println(vector.isEmpty());
}
/**
* LinkedList集合使用
* 双向链接结构
*/
public static void LinkedListTest() {
//创建对象
LinkedList linkedList = new LinkedList<>();
//添加元素
linkedList.add("西瓜");
linkedList.add("草莓");
linkedList.add("苹果");
linkedList.add(0, "哈密瓜");
//System.out.println(linkedList.size()+" "+linkedList.toString());
//删除元素
//linkedList.remove("苹果");
//System.out.println(linkedList.size()+" "+linkedList.toString());
//清空元素
//linkedList.clear();
//System.out.println(linkedList.size()+" "+linkedList.toString());
//遍历元素
/*for (int i = 0; i <linkedList.size() ; i++) {
System.out.println(linkedList.get(i));
}*/
/*for (Object o : linkedList) {
System.out.println(o);
}*/
/* Iterator iterator=linkedList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
ListIterator listIterator=linkedList.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}*/
//判断元素
System.out.println(linkedList.contains("南瓜"));
System.out.println(linkedList.isEmpty());
}
}
ArrayList和LinkedList的区别
Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
常见形式有泛型类、泛型接口、泛型方法。
语法:
·<T...>T称为类型占位符,表示一种引用类型。
好处:
·(1)提高代码的重用性
·(2)防止类型转换异常,提高代码的安全性
泛型
泛型类
好处
- 提⾼安全性(将运⾏期的错误转换到编译期)
- 省去强转的麻烦
- 在其作⽤域内可以统⼀参数类型
使用
语法:类名
T代表类型占位符,表示一种引用类型,如果使用多个以逗号隔开 MyGeneric<T,W,F>
- 使用泛型T创建变量:T t;
- 添加方法,使用泛型T作为方法的参数:public void show(T t) {}
- 使用泛型作为方法的返回值:public T getT() {return t;}
注意
- 泛型只能使用引用类型
- 不同泛型对象不能相互赋值
由来
- 类型通过Object 转型问题引⼊
- 早期的Object类型可以接收任意的对象类型,但是在实际的使⽤中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。
public class Generic {
private Object object;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}
示例:
package util;
/**
* 泛型类
* 语法:类名<T>
* T代表类型占位符,表示一种引用类型,如果使用多个以逗号隔开 MyGeneric<T,W,F>
*
* @param <T>
*/
public class MyGeneric<T> {
//1、使用泛型T创建变量
T t;
//2、添加方法,使用泛型T作为方法的参数
public void show(T t) {
System.out.println(t);
}
//3、使用泛型作为方法的返回值
public T getT() {
return t;
}
}
class TestMyGeneric {
public static void main(String[] args) {
MyGeneric<String> myGeneric = new MyGeneric<String>();
myGeneric.t = "hello";
System.out.println(myGeneric.t);
myGeneric.show("大家好");
String str = myGeneric.getT();
MyGeneric<Integer> myGeneric1 = new MyGeneric<Integer>();
myGeneric1.t = 10;
System.out.println(myGeneric1.t);
myGeneric1.show(200);
Integer integer = myGeneric1.getT();
}
}
通配符
泛型通配符<?>,也称为钻石通配符
-
任意类型,如果没有明确,就是Object以及任意的Java类
public static void main(String[] args) { ArrayList<String> arrayList1 = new ArrayList<>(); ArrayList<Integer> arrayList2 = new ArrayList<>(); List<?> list = arrayList1; list = arrayList2; }
-
?extend E
向下限定E及E的子类
-
?super E
向上限定E及其父类
泛型接口
格式
语法:接口名<T>
注意:不能创建泛型静态常量
接口的实现类
- 在创建实现类时确定实现类的类型:class Test implements MyInterfece {}
- 在创建实现类时不确定实现类的类型,在实例化时确定类型:class Test1 implements MyInterfece {}
/**
* 泛型接口
* 语法:接口名<T>
* 不能创建泛型静态常量
*/
public interface MyInterfece<T> {
String name = "张三";
T servrt(T t);
}
/**
* 接口的实现类,在创建实现类时确定实现类的类型
*/
class Test implements MyInterfece<String> {
@Override
public String servrt(String s) {
System.out.println(s);
return s;
}
}
/**
* 接口的实现类,在创建实现类时不确定实现类的类型,在实例化时确定类型
*
* @param <T>
*/
class Test1<T> implements MyInterfece<T> {
@Override
public T servrt(T t) {
System.out.println(t);
return t;
}
}
class MyInterfeceTest {
public static void main(String[] args) {
Test test = new Test();
test.servrt("zdand");
Test1<Integer> test1 = new Test1<>();
test1.servrt(1000);
}
}
泛型方法
格式
语法: 返回值类型
使用
public class MyGenericMethod {
public <T> void show(T t) {
System.out.println("泛型方法" + t);
}
}
class MyGenericMethodTest {
public static void main(String[] args) {
//T的类型由传入的数据决定
MyGenericMethod myGenericMethod = new MyGenericMethod();
myGenericMethod.show(1000);
myGenericMethod.show("中国");
}
}
泛型集合
概念
参数化类型、类型安全的集合,强制集合元素的类型必须一致。
特点
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
使用
package util;
import java.util.ArrayList;
import java.util.Iterator;
public class Demo {
public static void main(String[] args) {
/* ArrayList arrayList = new ArrayList();
//可以添加多种数据类型的数据
arrayList.add("123");
arrayList.add(100);
//当遍历数据,将全部数据转换从某一种数据类型时会报错:java.lang.ClassCastException
for (Object object : arrayList) {
String s = (String) object;
System.out.println(s);
}*/
ArrayList<String> arrayList = new ArrayList<String>();
arrayList.add("1231");
//无法添加String类型外的数据,因为在创建arrayList已经确定数据类型
//arrayList.add(1);
for (String s : arrayList) {
System.out.println(s);
}
Iterator<String> iterator = arrayList.iterator();
while (iterator.hasNext()) {
String str = iterator.next();
System.out.println(str);
}
}
}
泛型总结
Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
常见形式有泛型类、泛型接口、泛型方法。
语法:
·〈T,.>T称为类型占位符,表示一种引用类型。
好处:
·(1)提高代码的重用性
·(2)防止类型转换异常,提高代码的安全性
Set集合
特点:无序、无下标、元素不可重复。
方法:全部继承自Collection中的方法。
1、创建集合:Set set = new HashSet<>();
2、添加元素:
添加:set.add(“小米”);
3、删除、清空
删除:set.remove(“小米”);
清空:set.clear();
4、遍历
增强for遍历:for (String s : set)
迭代器遍历:Iterator iterator = set.iterator();
5、判断
判断元素:set.contains(“小米”)
判断是否为空:set.isEmpty()
package util;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class SetCollection {
public static void main(String[] args) {
//创建对象
Set<String> set = new HashSet<>();
//添加元素
//在添加时可以添加重复的数据,但是这个数据并未到集合里去
set.add("华为");
set.add("小米");
set.add("小米");
set.add("小米");
//System.out.println(set.size());
//System.out.println(set.toString());
//删除元素
//set.remove("小米");
//清空元素
//set.clear();
//遍历元素
//增强for
for (String s : set) {
System.out.println(s);
}
//迭代器遍历
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
//判断
System.out.println(set.isEmpty());
System.out.println(set.contains("小米"));
}
}
Set实现类
HashSet
基于HashCode计算元素存放位置。
当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
创建对象:HashSet<String> set = new HashSet<>();
(备注:其他的与set一致)
存储过程
1、根据hashcode计算保存的位置,如果此位置为空,直接保存,如果不为空执行第二步
2、执行equals(),如果equals()为true,则认为重复,否则形成链表
equals()和hashcode()重写
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
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;
}
/**
* 重写hashCode
*
* @return
*/
@Override
public int hashCode() {
int n1 = this.name.hashCode();
int n2 = this.age;
return n1 + n2;
}
/**
* 重写equals
*
* @param o
* @return
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if (o instanceof Person) {
Person person = (Person) o;
if (this.name.equals(person.getName()) && this.age == person.getAge()) {
return true;
}
}
return false;
}
}
TreeSet
定义
-
实现了SortedSet接口,对元素的大小进行排序,形成一个树状结构(红黑树),元素是不可以重复存在的
-
存入的元素必须实现Comparable接口,并且重写compareTo()
SortedSet()源码
public interface SortedSet<E> extends Set<E> { Comparator<? super E> comparator(); } public interface Comparator<T> { int compare(T o1, T o2); }
构造方法
- TreeSet() 构造⼀个新的空set, 该set根据其元素的⾃然顺序进⾏排序
- TreeSet(Comparator <? super E> comparator) 构建⼀个空的TreeSet, 他根据指定⽐较器进⾏排序
常用方法
-
add(E e) 将指定元素添加到此set
-
first() 返回此set中当前第⼀元素
-
last() 返回此set中当前最后⼀个元素
-
floor() 返回此set中⼩于等于给定元素的最⼤元素,不存在则返回null
-
higher() 返回此set中严格⼤于给定元素的最⼩元素,不存在则返回null
import java.util.SortedSet; import java.util.TreeSet; public class TreeSetDemo { public static void main(String[] args) { TreeSet<Integer> treeSet = new TreeSet<Integer>(); treeSet.add(1); treeSet.add(23); treeSet.add(423); treeSet.add(14); treeSet.add(67); for (Object o : treeSet) { System.out.print(o + "\t"); } //获取集合中小于给定数据的最大元素,如果无返回null System.out.println(treeSet.floor(54)); //获取集合中大于给定数据的最小元素,如果无返回null System.out.println(treeSet.higher(54)); System.out.println(treeSet.first());//首个元素 System.out.println(treeSet.last());//最后一个元素 System.out.println(treeSet.size());//长度 System.out.println(treeSet.pollFirst());//移除第一个元素 System.out.println(treeSet.pollLast());//移除最后一个元素 } }
添加原理
TreeSet会将第⼀个添加的元素作为中点, 以后添加的元素会先跟中点进⾏⽐较, 如果⼤于就接着跟所⽐较元素的右边的元素接着⽐较,如果⼩于就接着跟所⽐较元素左边的元素接着⽐较, 直到⽆法找到可⽐较的元素,就会将新添加的这个元素放到当前位置
注意事项
- TreeSet集合的存储原理限定了必须要对存入的元素进行比较
- 元素要么实现Comparable接口,要么实现Comparator接口,否则程序报错
Comparable
当TreeSet集合添加引用类型(不是int这些基础和String等,是个人写的某个类)数据时,会报:类型转换失败的错误,如下:
public class Person {
private int age;
private String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
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 "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class SetCollection {
public static void main(String[] args) {
//创建对象
TreeSet<Person> set = new TreeSet<>();
Person person1 = new Person(11, "jack");
Person person2 = new Person(12, "son");
Person person3 = new Person(20, "mkisq");
set.add(person1);
set.add(person2);
set.add(person3);
System.out.println(set.toString());
}
}
为什么:
因为TreeSet的存储结构时红黑树,数据需要比较,而Person数据无法比较,导致数据全部在一边,失去平衡。
当集合中的元素比较时,然后集合没有比较器,元素就会转成Comparator类型并调用comparaTo(),所以我们必须重写
compareTo
- 返回值小于0,表示当前元素小于被比较元素
- 返回值等于0,表示当前元素等于被比较元素
- 返回值大于0,表示当前元素大于被比较元素
处理方法:
Person实现Comparable接口,并且重写compareTo方法:比较数据大小
public class Person implements Comparable<Person> {
/**
* 重写compareTo方法
* 比较数据大小:先比name,后比age
*
* @param o
* @return
*/
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age - o.getAge();
return n1 == 0 ? n2 : n1;
}
}
Comparator
comparator是一个接口,需要重写compare()
public static void main(String[] args) {
//创建对象
TreeSet<Person> set = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge() - o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n2 == 0 ? n1 : n2;
}
});
}
Collections
Map集合
Map接口的特点
- 用于存储任意键值对(key-value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
Map父接口常用方法
-
V put(K key,,V value):将对象存入到集合中,关联键值。key重复则覆盖原值。
-
Object get(Object key):根据键获取对应的值。
-
Set:返回所有key。
-
Collectionvalues():返回包含所有值的Collection集合。
-
Set<Map.Entry<K,V>> :键值匹配的Set集合。
public class MapDemo { public static void main(String[] args) { //创建 Map<Integer, String> map = new HashMap<>(); //添加元素 K V map.put(1, null); map.put(null, "pear"); map.put(3, "new oranage"); map.put(3, "oranage");//替换某个位置的value值 System.out.println(map.get(122));//这里没有报错是数据没有进行处理 System.out.println(reData(map.get(122)));//对数据处理,提示空指针错误 //键与值是否相关联,如果没有返回null(只关心key是否有值,如果没有返回null) System.out.println(map.putIfAbsent(1, "111")); //判断键值是否存在 System.out.println("111".equals(map.getOrDefault(5, "111")) ? "无" : "111"); System.out.println(map.get(3));//获取某个key上的value,不存在返回null System.out.println(map.isEmpty());//判断map是否为空 System.out.println(map.containsKey(2));//判断map中是否有指定的key System.out.println(map.containsValue("xi"));//判断map中是否有指定的value System.out.println(map.entrySet());//查看所有数据 System.out.println(map.keySet());//查看所有的key map.putAll(map);//添加map集合 System.out.println(map.remove(3));//移除执行key和对应的value System.out.println(map.size());//返回长度 System.out.println(map.values());//查看所有的value map.clear(); //清空元素 HashMap<Integer,String> hashMap=(HashMap<Integer, String>) ((HashMap<Integer, String>) map).clone();//返回此 HashMap实例的浅拷贝:键和值本身不被克隆 } public static String reData(String s) { return s.toUpperCase().substring(0); } }
forEach、增强for
定义
- Iterator的简写形式
- 简化数组和Collection集合的遍历
格式
for(元素数据类型 变量 : 数组或Collection集合){
使用变量即可,变量就是元素
}
public static void main(String[] args) {
TreeSet<Student> set = new TreeSet<>(new MyComparator());
Student student1 = new Student("⼩红");
Student student2 = new Student("⼩明");
Student student3 = new Student("⼩李");
set.add(student1);
set.add(student2);
set.add(student3);
for (Student student : set) {
System.out.println(student);
}
}
迭代方式的删除
- 普通for循环,可以删除,但是需要角标
- 迭代器,可以删除,但是必须使用迭代器自身的remove(),否则会并发修改异常
ap.containsKey(2));//判断map中是否有指定的key
System.out.println(map.containsValue(“xi”));//判断map中是否有指定的value
System.out.println(map.entrySet());//查看所有数据
System.out.println(map.keySet());//查看所有的key
map.putAll(map);//添加map集合
System.out.println(map.remove(3));//移除执行key和对应的value
System.out.println(map.size());//返回长度
System.out.println(map.values());//查看所有的value
map.clear(); //清空元素HashMap<Integer,String> hashMap=(HashMap<Integer, String>) ((HashMap<Integer, String>) map).clone();//返回此 HashMap实例的浅拷贝:键和值本身不被克隆 } public static String reData(String s) { return s.toUpperCase().substring(0); } }
forEach、增强for
定义
- Iterator的简写形式
- 简化数组和Collection集合的遍历
格式
for(元素数据类型 变量 : 数组或Collection集合){
使用变量即可,变量就是元素
}
public static void main(String[] args) {
TreeSet<Student> set = new TreeSet<>(new MyComparator());
Student student1 = new Student("⼩红");
Student student2 = new Student("⼩明");
Student student3 = new Student("⼩李");
set.add(student1);
set.add(student2);
set.add(student3);
for (Student student : set) {
System.out.println(student);
}
}
迭代方式的删除
- 普通for循环,可以删除,但是需要角标
- 迭代器,可以删除,但是必须使用迭代器自身的remove(),否则会并发修改异常
- 超级for循环不能删除