Java集合框架
集合的概念
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
- 和数组的区别
- 数组长度固定(定义好之后就不能改变长度),集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能储存引用类型(要用集合储存基本类型,需要先把基本类型装箱转化成引用类型)
- 位置:java.util.*;
Collection接口
-
特点:代表一组任意类型的对象,无序,无下表,不能重复
-
方法:
-
boolean add(Object obj) 添加一个对象
-
boolean addAll(Collection c) 将一个集合中的所有对象添加到此集合中
-
void clear() 清空此集合中的所有对象
-
boolean contains(Object o) 判断此集合中是否包含o对象
-
boolean equals(Object o) 比较此集合是否与指定对象相等
-
booleanisEmpty() 判断此集合是否为空
-
boolean remove(Object o) 在此集合中移除指定对象
-
int size() 返回此集合中元素的个数
-
Object [] toArray() 将此集合转换成数组
-
iterator() 迭代器
-
迭代器中有三个方法:hasNext() 如果仍有元素可以迭代,返回true
next() 返回迭代的下一个元素
remove() 从迭代器指向的collection中移除迭代器返回的最后一个元素(可选操作)
迭代过程中要删除元素,不能用collection的remove,只能用迭代器iterator的remove
-
/* * Collection接口的使用 操作元素 * 1.添加元素 * 2.删除元素 * 3.遍历元素 * 4.判断 * */ public class Demo01 { public static void main(String[] args) { //创建集合 Collection collection=new ArrayList(); //* 1.添加元素 collection.add("苹果"); collection.add("西瓜"); collection.add("香蕉"); collection.add("梨子"); System.out.println("元素个数"+collection.size()); System.out.println(collection); //* 2.删除元素 collection.remove("西瓜"); System.out.println("元素个数"+collection.size()); System.out.println(collection); //* 3.判断 System.out.println("判断是否有香蕉"+collection.contains("香蕉")); System.out.println("判断是否为空"+collection.isEmpty()); //* 4.遍历元素 //增强for循环 for (Object o : collection) { System.out.println("增强for "+o); } // 迭代器Iterator Iterator it = collection.iterator(); while(it.hasNext()){ //hasNext() 判断是否有下一个元素 System.out.println("迭代器 "+it.next()); //next() 获取下一个元素 it.remove(); //迭代中删除;迭代完了也就删除完了 } System.out.println("元素个数"+collection.size()); } }
/** * Collection的使用:保存学生信息 操作对象 */ public class Demo02 { public static void main(String[] args) { //新建collection对象 Collection collection = new ArrayList(); Student s1 = new Student("果果",3); Student s2 = new Student("欢欢",2); Student s3 = new Student("小黑",4); //1.添加数据 collection.add(s1); collection.add(s2); collection.add(s3); System.out.println(collection.toString()); collection.remove(s1); System.out.println("删除之后"+collection.toString()); //collection.remove(new Student("小黑",4)); //System.out.println("再次删除之后"+collection.toString()); 之前小黑那条数据还在 //2.遍历 //增强for for (Object o : collection) { System.out.println("增强for "+o); } //迭代器 Iterator it = collection.iterator(); while (it.hasNext()){ System.out.println("迭代器 "+it.next()); } //3.判断 System.out.println(collection.contains(s1)); //判断是否包含对象s1 System.out.println(collection.isEmpty()); //判断集合是否为空 //4.清空 实际只是将对象从集合中移除;但对象实际还存在 collection.clear(); System.out.println(collection.size()); //0 System.out.println(s2.getName()); //欢欢 clear清空后集合长度已经变0了,但是另外操作对象s2依然可以操作 } }
-
List接口与实现类
-
特点:有序,有下标,元素可以重复
-
方法:
- 包含collection的所有方法
- void add(int index,Object o) 在指定角标处插入对象
- boolean addAll(int index ,Collection c) 将一个集合中的元素添加到次集合的index位置
- Object get(int index) 获取指定角标处元素
- List subList(int fromIndex,int toIndex) 返回fromIndex(含)和toIndex(不含)角标之间的集合元素
-
List遍历方法
- 增强for
- iterator
- 普通for:由于有角标,可以使用普通for遍历
- 列表迭代listIterator():可以指定迭代方向(前–>后 或者 后–>前 都行);类带过程中可使用的方法如下
- add() 将指定的元素插入列表
- hasNext() 正向遍历
- hasPrevious () 反向遍历 使用这个反向迭代需要与previous 配合;且需要先正向迭代把指针移动到最后面去才能开始反向迭代
- next() 返回下一个元素
- previous() 返回上一个元素
- nextIndex() 返回下一个元素的角标
- previousIndex() 返回上一个元素的角标
- remove() 在列表中移除由next或previous返回的最后一个元素
- set() 用指定元素替换next或previous返回的最后一个元素
/*
* List子接口的使用
* 特点1.有序,有角标 2.可以重复
* */
public class Demo03 {
public static void main(String[] args) {
//创建集合对象
List list = new ArrayList();
//1.添加元素
list.add("苹果");
list.add("香蕉");
list.add("橘子");
list.add(0,"西瓜"); //在0角标处添加
list.add("苹果"); //与前面的重复
System.out.println(list.size()); //5
System.out.println(list); //[西瓜, 苹果, 香蕉, 橘子, 苹果] 西瓜插到了前面;有两个苹果
//2.遍历
//支持增强for和迭代器
//由于有角标,还可以使用普通for----------
for (int i = 0; i <list.size() ; i++) { //get() 根据角标获取元素
System.out.println(list.get(i));
}
//增强for遍历------------------
for (Object o : list) {
System.out.println("增强for---"+o);
}
//迭代器-----------------------
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println("迭代器***"+it.next());
}
//列表迭代器--------------------可以指定迭代方向(前-->后 或者 后-->前 都行)
ListIterator lit = list.listIterator();
while(lit.hasNext()){
System.out.println("列表迭代器------"+lit.next());
}
while(lit.hasPrevious()){ //使用反向迭代,必须先正向迭代把迭代器指针移到最后面去
System.out.println("列表迭代器反向------"+lit.previousIndex()+"角标位:"+lit.previous());
}
//3.判断
System.out.println(list.contains("苹果")); //判断是否包含 苹果
System.out.println(list.isEmpty()); //判断列表是否为空
//获取位置
System.out.println(list.indexOf("苹果")); //返回 苹果 首次出现位置的角标
//5.删除元素
list.remove(1); //通过角标删除
System.out.println(list);
list.remove("香蕉"); //通过对象名删除
System.out.println(list);
}
}
/*
* List保存数字
* */
public class Demo04 {
public static void main(String[] args) {
//创建集合
List list=new ArrayList();
//添加数字数据 该操作隐含了自动装箱操作
list.add(20);
list.add(30);
list.add(40);
list.add(50);
list.add(60);
list.add(70);
list.add(80);
list.add(90);
System.out.println("元素个数"+list.size());
System.out.println(list); //[20, 30, 40, 50, 60, 70, 80, 90]
//删除操作
// list.remove(20); 此时是默认删除角标20的数据,而非删除数据20;会报数组角标越界异常
list.remove((Object)20); //将20转成Object类型以后可以删除
System.out.println(list); //[30, 40, 50, 60, 70, 80, 90]
list.remove((Integer)40); //或者将数字40转成包装类Integer类型以后也可以删除
System.out.println(list); //[30, 50, 60, 70, 80, 90]
//subList方法 返回子集合
List subList = list.subList(1, 4); //含头不含尾
System.out.println("子集合"+subList); //子集合[50, 60, 70]
}
}
List实现类
- ArrayList (重点)
- 数组结构实现,查询快,增删慢
- 源码分析
- DEFAULT_CAPACITY=10 默认容量大小 如果没有向集合中添加任何元素时,容量为0
- elementDatas 存放元素的数组
- size 实际的元素个数<=容量
- add() 添加元素
- 扩容时每次是原来1.5倍
- Vector:已过时
- 数组结构实现,查询快,增删慢
- JDK1.0版本出现,运行效率慢,线程安全
- 特有的遍历方式:枚举器 elements() 功能与迭代器类似
- LinkedList:
- 链表结构实现,增删快,查询慢
ArrayList的使用
/*
* ArrayList的使用
* 储存结构:数组,查找遍历较快,增删慢
* */
public class 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
//要实现通过new一个新对象来删除相同对象,需要重写equals方法
public boolean equals(Object obj) {
//1.判断是不是同一个对象
if(this==obj){
return true;
}
//2.判断是否为空
if(obj==null){
return false;
}
//3.判断是否是Student类
if(obj instanceof Student){
Student s=(Student)obj;
//4.比较属性,如果明知年龄一样,人为是同一个对象
if(this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
//5.不满足,返回false
return false;
}
}
//=============================================================================================
public class Demo05 {
public static void main(String[] args) {
//创建集合
ArrayList arrayList = new ArrayList();
//添加元素
Student s1 = new Student("果果",3);
Student s2 = new Student("欢欢",4);
Student s3 = new Student("乐乐",5);
Student s4 = new Student("小黑",6);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
arrayList.add(s4); //ArrayList 有序,可以添加重复的
System.out.println(arrayList.size());
System.out.println(arrayList);
//遍历 迭代器,列表迭代器,增强for,for都可以
//此处演示迭代器
Iterator it = arrayList.iterator();
while(it.hasNext()){
System.out.println("遍历----"+it.next());
}
//判断
System.out.println("判断=============");
System.out.println(arrayList.contains(s2)); //判断是否存在
//重写了实体类中equals方法,此处可用new对象的方式判断
System.out.println(arrayList.contains(new Student("果果",3)));
//查找
System.out.println("查找=============");
System.out.println(arrayList.indexOf(s1));
//删除
arrayList.remove(1); //通过下标删除元素
System.out.println(arrayList);
arrayList.remove(s4);
System.out.println(arrayList); //可以直接删除对象,但当指定对象有重复时,只会删除第一个
//=================================================================
要实现通过new一个新对象来删除相同对象,需要重写实体类中equals方法
arrayList.remove(new Student("乐乐",5)); //重写了equals方法好,此时可以通过new的方式删除对象
System.out.println(arrayList);
}
}
Vector的使用
/*
* 演示Vertor集合的使用
* 储存结构:数组
* */
public class VertorDemo {
public static void main(String[] args) {
//创建集合
Vector vector = new Vector();
//添加元素
vector.add("香蕉");
vector.add("黄瓜");
vector.add("茄子");
vector.add("胡萝卜");
System.out.println("元素个数"+vector.size());
//遍历元素 枚举器
Enumeration ele = vector.elements();
while (ele.hasMoreElements()){
System.out.println(ele.nextElement());
}
//判断
System.out.println(vector.contains("香蕉"));
System.out.println(vector.isEmpty());
//删除
vector.remove(0);
vector.remove("胡萝卜");
}
}
LinkedList的使用
/*
* LinkedList的使用
* 储存结构:双向链表
* */
public class LinkedListDemo {
public static void main(String[] args) {
//创建LinkedList
LinkedList linkedList = new LinkedList();
//添加元素
Student s1 = new Student("果果",3);
Student s2 = new Student("欢欢",4);
Student s3 = new Student("乐乐",5);
Student s4 = new Student("小黑",6);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
linkedList.add(s3); //有顺序,元素可重复
linkedList.add(s4);
System.out.println(linkedList.size());
System.out.println(linkedList);
//遍历元素 for,增强for,迭代,列表迭代都可以
for (Object o : linkedList) {
System.out.println("增强for遍历---"+o);
}
//判断
System.out.println(linkedList.contains(s4));
System.out.println(linkedList.isEmpty());
//删除
System.out.println("删除后=============================");
linkedList.remove(2);
linkedList.remove(s3);
linkedList.remove(new Student("小黑",6)); //因为前面重写了实体类的equals方法,
// 此处可用这种new对象的方式删除(具体方法重写见ArrayList实例中Student类)
System.out.println(linkedList);
}
}
ArrayList和LinkedList不同结构的实现方式
ArrayList:必须开辟连续的空间,查询快,增删慢
LinkedList:无须开辟连续的空间,查询慢,增删快
泛型
- 泛型是JDK1.5以后引入的新特性,本质是参数化类型,把类型作为参数传递
- 常见形式有泛型类,泛型方法,泛型接口
- 语法:
- <T,…> T称为类型占位符,表示一种引用类型
- 好处:
- 提高代码的复用性
- 防止类型转换异常,提高代码安全性
泛型类
/*
* 泛型类
* 语法:类名<T,T>
* T是占位符 代表一种引用数据类型,可以同时有多个T,使用逗号,隔开
* */
public class MyGeneric<T>{
//使用泛型T
//用法1.创建变量 泛型T作为一个类型,但具体什么类型不确定,所有可以用来创建变量,但不能nwe创建对象实例化
T t;
//用法2.作为方法的参数
public void show(T t){
System.out.println(t);
}
//用法3.使用泛型作为方法的返回值
public T getT(){
return t;
}
}
//==================================================================================================
public class TestGeneric {
public static void main(String[] args) {
//使用泛型类T创建对象(必须赋予T一种引用类型) 此时创建时给了它一个String类型
//注意点:1.使用泛型只能使用引用类型 2.不同泛型类型之间不能相互赋值
MyGeneric<String> myGeneric = new MyGeneric<String>();
myGeneric.t="sb"; //前面赋予了String类型,后面调用变量传字符串可以变异通过
//myGeneric.t=1; 此处传其他类型,如整数,会报红无法正常编译
myGeneric.show("hello");
String t = myGeneric.getT(); //调用前面写的getT方法,返回Sting类型
System.out.println(t);
System.out.println("===================================================");
MyGeneric<Integer> myGeneric2=new MyGeneric<Integer>(); //创建对象时赋予Integer类型
myGeneric2.t=10;
myGeneric2.show(35);
Integer t2 = myGeneric2.getT(); //调用前面写的getT方法,返回Integer类型
System.out.println(t2);
}
}
泛型接口
方式1 实现泛型接口的时候明确泛型类型
/*
* 泛型接口
* 语法:接口名<T>
* 接口中可以包含抽象方法和静态常量
* 注意:不能用泛型创建静态常量
* */
public interface MyInterface<T> {
String name="果果";
//t t=new T(); 常量要求创建的时候必须初始化;使用泛型接口前,T的类型不确定,所以不能用new的方式来创建对象初始化,进而不能创建常量
T service(T t); //方法service 参数是T,返回值类型也是T
}
//==========================================================================================
/*
* 实现类
* 实现泛型接口的时候明确泛型类型
* */
public class MyInterfaceImpl implements MyInterface<String>{
public String service(String t){
System.out.println(t);
return t;
}
}
//==========================================================================================
//测试类
public class GenericTest {
public static void main(String[] args) {
MyInterfaceImpl mi = new MyInterfaceImpl();
mi.service("guoguo");
}
}
方式2 实现泛型接口的时候不明确泛型类型
/*
* 泛型接口
* 语法:接口名<T>
* 接口中可以包含抽象方法和静态常量
* 注意:不能用泛型创建静态常量
* */
public interface MyInterface<T> {
String name="果果";
//t t=new T(); 常量要求创建的时候必须初始化;使用泛型接口前,T的类型不确定,所以不能用new的方式来创建对象初始化,进而不能创建常量
T service(T t); //方法service 参数是T,返回值类型也是T
}
//==========================================================================================
/*
* 实现类
* 实现泛型接口的时候没有明确泛型类型,之后使用该泛型类时传入了什么类型,泛型接着也就跟着什么类型
* */
public class MyInterfaceImpl2<T> implements MyInterface<T> {
public T service(T t){
System.out.println(t);
return t;
}
}
//==========================================================================================
/*
* 测试类
* 在使用这个类的时候必须明确泛型类型
* */
public class GenericTest {
public static void main(String[] args) {
MyInterfaceImpl2<Integer> mi2 = new MyInterfaceImpl2<Integer>();
mi2.service(3);
}
}
泛型方法
/*
* 泛型方法
* 语法:<T> 返回值类型 泛型放在方法返回值类型的前面
* */
public class MyGenericMethod {
public void haha(){
System.out.println("普通方法");
}
//添加一个泛型方法
public <T> void show1(T t){
System.out.println("泛型方法1"+t);
}
public <T> T show2(T t){
System.out.println("泛型方法2"+t);
return t;
}
}
//=====================================================================
public class GenericTest {
public static void main(String[] args) {
//泛型方法
MyGenericMethod mgm = new MyGenericMethod();
mgm.haha(); //调用普通方法
//下面是调用泛型方法,不用专门传类型,直接传参数,传什么类型的参数,泛型就自动变成什么类型。还能传不同类型的参数
mgm.show1("好傻"); //传String类型参数,泛型就是String类型
mgm.show1(3); //同一个方法,传其他类型也可以
mgm.show2("哟呵");
}
}
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须统一
- 特点
- 编译时即可检查,而非运行时再抛出异常
- 访问时,不必类型转换(拆箱)
- 不同泛型之间引用不能互相赋值,泛型不存在多态
public class GenericCollection {
public static void main(String[] args) {
ArrayList<String> arrayList = new ArrayList<String>();//定义集合的时候就明确了类型String
arrayList.add("xxx");
arrayList.add("yyy");
//arrayList.add(1); 传入其他类型会直接报红
//arrayList.add(3.14);
for (String s : arrayList) { //增强for遍历时(iter快捷键)直接带出来的就是String类型而不是Object了
System.out.println(s);
}
}
}
Set接口与实现类
-
特点:无序、无下标、元素不可重复
-
方法:全部继承自Collection中的方法,本身没有定义抽象
-
HsahSet【重点】
- 基于HashCode实现元素不可重复
- 当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后续存入
-
TreeSet
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过ComparaTo方法确定是否为重复元素
- TreeSet是红黑树的结构 (二叉树)
Set接口示例
public class Demo01 {
public static void main(String[] args) {
//创建集合
Set<String> set = new HashSet<String>();
set.add("香蕉");
set.add("茄子");
set.add("黄瓜");
set.add("胡萝卜");
set.add("胡萝卜");
System.out.println(set.size()); //4 无序,不可重复
System.out.println(set); //[香蕉, 胡萝卜, 黄瓜, 茄子] 重复的胡萝卜只添加进去一个;打印的顺序与添加的顺序不一样
//遍历 无序,支持增强for和迭代器iterator
for (String s : set) {
System.out.println("增强for---"+s);
}
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println("迭代器***"+it.next());
}
//判断
System.out.println(set.contains("香蕉"));
System.out.println(set.isEmpty());
//删除 因为无序,没有角标删除方法
set.remove("胡萝卜");
System.out.println(set);
}
}
HashSet示例
/*
* HashSet集合的使用
* 存储结构:哈希表(数组+链表+红黑树)
*
* */
public class Demo02 {
public static void main(String[] args) {
//新建集合
HashSet<String> hashSet = new HashSet<String>();
//添加元素
hashSet.add("香蕉");
hashSet.add("黄瓜");
hashSet.add("茄子");
hashSet.add("胡萝卜");
hashSet.add("胡萝卜");
System.out.println(hashSet.size());
System.out.println(hashSet); //[香蕉, 胡萝卜, 黄瓜, 茄子] 顺序与添加顺序不一致,无序;无重复数据
//遍历 增强for;iterator
for (String s : hashSet) {
System.out.println("增强for---"+s);
}
Iterator<String> it = hashSet.iterator();
while (it.hasNext()){
System.out.println("迭代器***"+it.next());
}
//判断
System.out.println(hashSet.contains("茄子"));
System.out.println(hashSet.isEmpty());
//删除
hashSet.remove("胡萝卜");
System.out.println(hashSet);
hashSet.clear(); //清空
System.out.println(hashSet);
}
}
//实体类
public class Person {
private String name;
private int age;
public Person() {
}
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) { //重写equals
if (this == obj){
return true;
}
if (obj == null){
return false;
}
if(obj instanceof Person){
Person p=(Person)obj;
if(this.name.equals(p.getName())&&this.age==p.getAge()){
return true;
}
}
return false;
}
@Override
public int hashCode() { //重写hashCode
final int prime=31; //使用31的原因:31是个质数,减少散列冲突;提高执行效率,i*31是将左移5位再减i 即31*i=(i<<5)-i
int result=1;
result=prime*result+age;
result=prime*result+((name==null) ? 0:name.hashCode());
return result;
}
}
//=============================================================
/*
* HashSet的使用,操作对象
* */
/*
* HashSet的使用
* HashSet存储过程分析:
* 1.根据hashCode计算保存的位置,如果此位置为空,则直接保存,如果不为空,执行下一步
* 2,。在执行equals方法,如果equals方法为true,则默认是重复,否则,形成链表
* */
public class Demo03 {
public static void main(String[] args) {
//创建集合
HashSet<Person> hashSet = new HashSet<Person>();
//添加数据
Person p1 = new Person("果果",3);
Person p2 = new Person("欢欢",2);
Person p3 = new Person("乐乐",1);
Person p4 = new Person("小黑",4);
hashSet.add(p1);
hashSet.add(p2);
hashSet.add(p3);
hashSet.add(p4);
hashSet.add(new Person("小白",5)); //可以直接添加new的对象
hashSet.add(new Person("小黑",4));
System.out.println(hashSet.size());
System.out.println(hashSet); //如果没有重写equals和hashcode方法,此处通过new对象可以添加重复数据
//遍历
for (Person person : hashSet) {
System.out.println("增强for---"+person);
}
Iterator<Person> it = hashSet.iterator();
while (it.hasNext()){
System.out.println("迭代器***"+it.next());
}
//判断
System.out.println(hashSet.contains(p2));
//删除
hashSet.remove(p2);
hashSet.remove(new Person("乐乐",1)) //重写equals和hashcode方法前,该操作无法删除;重写后会判断相同,能搞删除
}
}
重写equals()和hashCode()可以在实体类中通过右键Generate–equals()and hashCode()
TreeSet示例
/*
* TresSet的使用 简单类型
* 存储结构:红黑树
*
* */
public class Demo04 {
public static void main(String[] args) {
//创建集合
TreeSet<String> treeSet = new TreeSet<String>();
//添加
treeSet.add("zoo");
treeSet.add("hello");
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("xyz");
System.out.println(treeSet.size());
System.out.println(treeSet); //[abc, hello, xyz, zoo] 实际上是有排序的;重复的xyz没有添加进来
//遍历 增强for,迭代器
for (String s : treeSet) {
System.out.println("增强for---"+s);
}
Iterator<String> it = treeSet.iterator();
while (it.hasNext()){
System.out.println("迭代器***"+it.next());
}
//判断
System.out.println(treeSet.contains("abc"));
//删除
treeSet.remove("xyz");
System.out.println(treeSet);
}
}
/*
*TresSet的使用 复杂类型
*存储结构:红黑树
*要求:元素必须要实现Comparable接口
*如果实体类没有实现Comparable接口并重写compareTo方法,会报类型转换异常(无法比较进而排序)
* */
//================================实体类
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) { //重写equals
if (this == obj){
return true;
}
if (obj == null){
return false;
}
if(obj instanceof Person){
Person p=(Person)obj;
if(this.name.equals(p.getName())&&this.age==p.getAge()){
return true;
}
}
return false;
}
@Override
public int hashCode() { //重写hashCode
final int prime=31; //使用31的原因:31是个质数,减少散列冲突;提高执行效率,i*31是将左移5位再减i 即31*i=(i<<5)-i
int result=1;
result=prime*result+age;
result=prime*result+((name==null) ? 0:name.hashCode());
return result;
}
//重写后比较规则:先按姓名比,再按年龄比
public int compareTo(Person o) {
int n1=this.getName().compareTo(o.getName());
int n2=this.age-o.getAge();
return n1==0?n2:n1; //如果n1=0,即两个名字相等,那么返回n2,否则返回n1
}
}
//===================================================================
/*
* TresSet的使用 复制类型
*存储结构:红黑树
*要求:元素必须要实现Comparable接口
* */
public class Demo05 {
public static void main(String[] args) {
//创建集合
TreeSet<Person> people = new TreeSet<Person>();
Person p1 = new Person("angle",3);
Person p2 = new Person("jack",2);
Person p3 = new Person("marry",5);
Person p4 = new Person("marry",1);
Person p5 = new Person("jhon",4);
people.add(p1); //如果实体类没有实现Comparable接口并重写compareTo方法,会报类型转换异常(无法比较进而排序)
people.add(p2);
people.add(p3);
people.add(p4);
people.add(p5);
System.out.println(people);
//遍历 增强for和迭代iterator
for (Person person : people) {
System.out.println(people);
}
//判断
System.out.println(people.contains(p3));
//删除
people.remove(p1);
people.remove(new Person("jhon",4)); //重写过equals方法和hashCode方法,所以此处可以实现
System.out.println(people);
}
}
/*
* TreeSet集合的使用
* Comparator:实现定制比较(比较器) 在创建集合是指定比较规则,实体类可以不用实现Comparable接口
* Comparable:可比较的
* */
public class Demo06 {
public static void main(String[] args) {
//创建集合,并指定比较规则 通过接口实现类的匿名内部类方式
TreeSet<Person> people = new TreeSet<Person>(new Comparator<Person>() { //此时实体类可以不用实现Comparable接口
public int compare(Person o1, Person o2) {
int n1=o1.getAge()-o2.getAge();
int n2=o1.getName().compareTo(o2.getName());
return n1==n2?n2:n1;
}
});
Person p1 = new Person("angle",3);
Person p2 = new Person("jack",2);
Person p3 = new Person("marry",5);
people.add(p1);
people.add(p2);
people.add(p3);
System.out.println(people);
}
}
Map接口与实现类
**Map接口特点:**键值对,无序、无下标,键不可重复,值可重复
- 用于存储任意键值对(key- Value)
- 键:无序、无下标、不允许重复(唯一)
- 值:无序、无下标、允许重复
方法:
- V put(K key,V value) 将对象存入到集合中,关联键值。key重复则覆盖原value值
- Object get(Object key) 根据键获取对应的值
- Set 返回所有的key
- Collection values() 返回包含所有值的Collection集合
Map接口基本使用示例
/*
* Map接口的使用
* 特点:1.储存键值对 2.键不能重复,值可以重复 3.无序
* */
public class Demo01 {
public static void main(String[] args) {
//创建Map集合
Map<String,String> map=new HashMap<String, String>();
//添加元素 put方法
map.put("BJ","北京");
map.put("SH","上海");
map.put("WH","武汉");
map.put("SZ","深圳");
map.put("SZ","shenzhen"); //key重复,后面添加的 shenzhen 将前面添加的 深圳 替换掉了
map.put("首都","北京"); //key不重复,值重复,可以添加进来
System.out.println(map.size());
System.out.println(map); //{WH=武汉, SH=上海, SZ=深圳, BJ=北京} 无序
//遍历
//方法1.keySet(),返回值是所有key的Set集合,要获取值还需要调用map的get()方法 get()方法是通过key获取value
System.out.println("---keySet()方法遍历---");
for (String key : map.keySet()) {
System.out.println(key+"---"+map.get(key));
}
//方式2.entrySet(),返回值类型Entry是键值对 该方法可直接获取键与值
System.out.println("---entrySet()方法遍历---");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry);
}
//判断
System.out.println(map.containsKey("SZ")); //判断是否存在某个key
System.out.println(map.containsValue("上海")); //判断是否存在某个value
//删除
map.remove("首都");
System.out.println(map);
}
}
Map集合的实现类
- HashMap【重点】
- JDK1.2版本出现,线程不安全,运行效率快:允许null作为key或者value
- 默认初始容量是16,加载因子是0.75(超过总容量75%是开始扩容)
- 方法同Map集合
- HashTable
- 实现一个哈希表,该哈希表将键映射到相应的值
- JDK1.0出现,线程安全,运行效率慢;不允许null左右键或者值
- 现在几乎不用
- Properties是HashTable的子类(使用相对较多)
- 要求key和value都是String,常用于配置文件的读取
- 与流联系较多
- TreeMap
- 数据结构是红黑树
- 实现了SortedMap接口(是Map的子接口),可以对key进行自动排序
HashMap集合的使用
/*
* HashMap集合的使用
* 存储结构:哈希表(数组+链表+红黑树)
* */
//===============================================实体类
public class Student {
private String name;
private int id;
public Student() {
}
public Student(String name, int id) {
this.name = name;
this.id = id;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
//======================================================HashMap集合
public class Demo02 {
public static void main(String[] args) {
//创建集合
HashMap<Student, String> hashMap = new HashMap<Student, String>();
Student s1 = new Student("果果", 1);
Student s2 = new Student("欢欢", 2);
Student s3 = new Student("乐乐", 3);
Student s4 = new Student("小黑", 4);
hashMap.put(s1,"白色");
hashMap.put(s2,"棕色");
hashMap.put(s3,"花白");
hashMap.put(s4,"黑色");
hashMap.put(s4,"黄色"); //重复输入键值相同的,会将前面的旧数据覆盖
hashMap.put(new Student("小虎",5),"灰白色");
System.out.println(hashMap); //打印结果看是无序的
//遍历 keySet()方法 entrySet()方法
System.out.println("keySet()遍历-----");
for (Student student : hashMap.keySet()) {
System.out.println(student);
}
System.out.println("entrySet()遍历****");
for (Map.Entry<Student, String> stu : hashMap.entrySet()) {
System.out.println(stu);
}
//判断
System.out.println(hashMap.containsKey(s3));
System.out.println(hashMap.containsValue("黄色"));
//删除
hashMap.remove(s1);
}
}
HashMap小结:
-
- HsahMap刚创建时,table是null,是为了节省空间,当添加第一个元素时,table容量调整为16
- 当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍;目的是减少调整元素的个数
- jdk1.8 当每个链表长度大于8,并且数组元素大于等于64时,会调整为红黑树,目的是提高执行效率
- jdk1.8 当链表长度小于6时,调整成链表
- jdk1.8 以前,链表是头插入,jdk1.8 以后是尾插入
TreeMap集合使用
/*
*TreeMap集合的使用
*储存结构:红黑树
* */
//======================================================实体类
public class Student implements Comparable<Student>{
private String name;
private int id;
public Student() {
}
public Student(String name, int id) {
this.name = name;
this.id = id;
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
public int compareTo(Student o) { //重写compareTo方法
int n=this.id-o.getId();
return n;
}
}
//===================================================================
public class Demo3 {
public static void main(String[] args) {
//创建集合
TreeMap<Student, String> treeMap = new TreeMap<Student, String>();
Student s1 = new Student("果果", 1);
Student s2 = new Student("欢欢", 2);
Student s3 = new Student("乐乐", 3);
Student s4 = new Student("小黑", 4);
treeMap.put(s1,"白色");
treeMap.put(s2,"棕色");
treeMap.put(s3,"花白色");
treeMap.put(s4,"黑色");
System.out.println(treeMap); //直接将复杂对象Student类作为key传入,会导致类型转换异常
//需要Student类实现Comparable接口,并重写compareTo方法
//或者在创建集合的时候使用定制比较器,用用匿名内部类的方法
//遍历 keySet()方法 entrySet()方法
System.out.println("keySet()---");
for (Student student : treeMap.keySet()) {
System.out.println(student);
}
System.out.println("entrySet()***");
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry);
}
//判断
treeMap.containsKey(s4);
//删除
treeMap.remove(s3);
}
}
Collections工具类
- 概念:集合工具类,定义了除了存取意外的集合常用方法
- 方法:
- public static void reverse(List<?> list) 反转集合中元素的顺序
- public static void shuffle(List<?> list) 随机重置集合元素的顺序
- public static void sort(List list) 升序排序(元素必须实现Comparable接口)
public class Demo04 {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(20);
list.add(6);
list.add(25);
list.add(2);
list.add(44);
list.add(8);
System.out.println("排序前"+list); //排序前[20, 6, 25, 2, 44, 8]
//sort 排序
Collections.sort(list);
System.out.println("排序后"+list); //排序后[2, 6, 8, 20, 25, 44]
//reverse 反转
Collections.reverse(list);
System.out.println("反转后"+list); //反转后[44, 25, 20, 8, 6, 2]
}
}