一、什么是集合
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可以实现数组的功能。
- 和数组区别:
- (1)数组长度固定,集合长度不固定
- (2)数组可以存储基本类型和引用类型,集合只能存储引用类型
- 位置:Java.util*
二、Collection体系集合
1、Collection父接口
- 特点:代表一组任意类型的对象,无序、无下标、不能重复。
- 方法:
- boolean add(Object obj) //添加一个对象。
- boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中。
- void clear() //清空此集合中的所有对象。
- boolean contains(Object o) //检查此集合中是否包含o对象
- boolean equals(Object o)//比较此集合是否与指定对象相等。
- boolean isEmpty) //判断此集合是否为空
- boolean remove(0bject o) //在此集合中移除o对象.
- int size() //返回此集合中的元素个数。
- Object[] toArray() //将此集合转换成数组。
package com.jjl.Collection;
/*
Collection接口的是使用
1、添加元素
2、删除记录
3、遍历元素
4、判断
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
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("香蕉");
//collection.clear();//清空
System.out.println("删除之后的个数"+collection.size());
//遍历元素
//遍历方法一:增强for
for (Object object : collection){
System.out.println(object);
}
//遍历方法二:迭代器(专门用来遍历集合的一种方法)
//迭代器iterator
//hasNext();有没有下一个元素
//Next();获取下一个元素
//remove();删除当前元素
Iterator it=collection.iterator();
while (it.hasNext()){
String object= (String)it.next();
System.out.println(object);
//it.remove();//删除
}
//System.out.println("迭代删除之后的个数"+collection.size());
//判断是否有某个元素
System.out.println(collection.contains("西瓜"));
//判断是否为空
System.out.println(collection.isEmpty());
}
}
输出:
元素个数4
[苹果, 西瓜, 榴莲, 香蕉]
删除之后的个数3
苹果
西瓜
榴莲
苹果
西瓜
榴莲
true
false
实际应用
package com.jjl.Collection;
public class Student {
private String name;
private int age;
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 +
'}';
}
}
主程序调用
package com.jjl.Collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
//新建Collection对象
Collection collection=new ArrayList();
Student s1=new Student("张三",23);
Student s2=new Student("张四",24);
Student s3=new Student("张五",25);
//1添加数据
collection.add(s1);
collection.add(s2);
collection.add(s3);
System.out.println("元素个数"+collection.size());
System.out.println(collection.toString());
//增强for循环
System.out.println("=========增强for循环遍历=========");
for (Object object : collection){
Student s=(Student) object;
System.out.println(s.toString());
}
//迭代器:hasNext() next(); remove(); 迭代器过程中不能使用collection的删除方法
System.out.println("=========迭代器Iterator遍历=========");
Iterator it = collection.iterator();
while (it.hasNext()){
Student s = (Student) it.next();
System.out.println(s);
}
}
}
输出:
元素个数3
[Student{name='张三', age=23}, Student{name='张四', age=24}, Student{name='张五', age=25}]
=========增强for循环遍历=========
Student{name='张三', age=23}
Student{name='张四', age=24}
Student{name='张五', age=25}
=========迭代器Iterator遍历=========
Student{name='张三', age=23}
Student{name='张四', age=24}
Student{name='张五', age=25}
2、List子接口
- 特点:有下标、有序、元素可以重复
- 方法
- void add (int,index,Object o) //在index位置插入对象o.
- boolean addAll(int index,Collection c) //将一个集合中的元素添加到此集合中的index位置。
- 0bject get(int index) //返回集合中指定位置的元素。
- List subList(int fromIndex,int toIndex) //返回fromIndex和toIndex之间的集合元素。
package com.jjl.Collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
List子接口的使用
*/
public class Demo03 {
public static void main(String[] args) {
//先创建一个集合
List list=new ArrayList<>();
//添加元素
list.add("苹果");
list.add("vivo");
list.add(0,"Lenovo");
System.out.println("元素个数"+list.size());
System.out.println(list.toString());
//删除元素
//list.remove(0);//删除一个元素
//遍历
//使用for
System.out.println("=========使用for遍历==========");
for (int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
//增强for
System.out.println("===============增强for遍历=============");
for (Object object:list){
System.out.println(object);
}
//使用迭代器
System.out.println("============使用迭代器遍历=============");
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//使用列表迭代器,ListIterator可以向前向后遍历,可以添加删除元素
System.out.println("============使用列表迭代器===========");
ListIterator lit=list.listIterator();
System.out.println("==========从前往后============");
while (lit.hasNext()){
System.out.println(lit.nextIndex()+":"+lit.next());//打印角标和属性
}
System.out.println("==========从后往前============");
while (lit.hasPrevious()){
System.out.println(lit.previousIndex()+":"+lit.previous());//打印角标和属性
}
//判断
System.out.println(list.contains("苹果"));
System.out.println(list.isEmpty());
//获取位置(下标)
System.out.println(list.indexOf("vivo"));
}
}
输出:
元素个数3
[Lenovo, 苹果, vivo]
=========使用for遍历==========
Lenovo
苹果
vivo
===============增强for遍历=============
Lenovo
苹果
vivo
============使用迭代器遍历=============
Lenovo
苹果
vivo
============使用列表迭代器===========
==========从前往后============
0:Lenovo
1:苹果
2:vivo
==========从后往前============
2:vivo
1:苹果
0:Lenovo
true
false
2
List接口使用2
package com.jjl.Collection;
import java.util.ArrayList;
import java.util.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);
System.out.println("元素个数:"+list.size());
System.out.println(list.toString());
//删除元素(默认使用脚本删除,不能之间使用元素删除)
//list.remove(0);
//如果要使用元素属性删除,需要将元素转成Integer
list.remove(new Integer(20));
System.out.println("删除后的元素个数:"+list.size());
System.out.println(list.toString());
//补充方法sublist,返回子集合
List subList=list.subList(1,3); //获取1到3的元素,包含1不包含3
System.out.println(subList.toString());
}
}
输出:
元素个数:5
[20, 30, 40, 50, 60]
删除后的元素个数:4
[30, 40, 50, 60]
[40, 50]
3、List实现类
- ArrayList
- 数组结构实现,查询块、增删慢;
- JDK1.2版本,运行效率块、线程不安全。
- 源码分析:
- 默认容量:DEFAULT_CAPACITY = 10;
- 如果没有向集合中添加任何元素时,容量就是:0
- 存放元素的数组:transient Object[] elementData
- 实际元素个数:size
- 默认容量:DEFAULT_CAPACITY = 10;
- Vector:
- 数组结构实现,查询快、增删慢;
- ·JDK1.0版本,运行效率慢、线程安全。
- LinkedList:
- 链表结构实现,增删快,查询慢。
3.1、ArrayList
package com.jjl.Collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
/*
ArrayList的使用
存储结构:数组,查找遍历速度快,增删慢
*/
public class Demo5 {
public static void main(String[] args) {
//创建集合
ArrayList arrayList=new ArrayList<>();
//1添加元素
Student s1=new Student("可可",18);
Student s2=new Student("爱爱",17);
Student s4=new Student("明明",25);
Student s3=new Student("小小",19);
Student s5=new Student("玲玲",20);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
arrayList.add(s4);
arrayList.add(s5);
System.out.println("============元素总个数===========");
System.out.println("元素个数"+arrayList.size());
System.out.println("\n========打印所有元素===========");
System.out.println(arrayList.toString());
//删除
//方法一:
System.out.println("\n=======使用下标或者元素属性名称删除元素===========");
arrayList.remove(1);//可以用下标,也可以用元素属性
System.out.println(arrayList.toString());
//方法二:
System.out.println("\n========使用元素源数据进行删除,需要重写object方法===========");
arrayList.remove(new Student("小小",19));//如果需要这种方法删除,则就要重写Student的obj方法
System.out.println(arrayList.toString());
//遍历(使用迭代器)
System.out.println("\n============迭代器遍历法===========");
Iterator it=arrayList.iterator();
while (it.hasNext()) {
Student s = (Student) it.next();
System.out.println(s.toString());
}
//遍历(列表迭代器)
System.out.println("\n============列表迭代器遍历法===========");
ListIterator lit= arrayList.listIterator();
while (lit.hasNext()) {
Student s = (Student) lit.next();
System.out.println(s.toString());
}
//判断
System.out.println("\n============判断元素是否存在===========");
System.out.println(arrayList.contains(new Student("玲玲",20)));//此方法只能在重写了equals方法之后才能使用
System.out.println(arrayList.isEmpty());//判断是否为空
//查找
System.out.println("\n============查找元素的下标===========");
System.out.println(arrayList.indexOf(s1));
}
}
输出:
============元素总个数===========
元素个数5
========打印所有元素===========
[Student{name='可可', age=18}, Student{name='爱爱', age=17}, Student{name='小小', age=19}, Student{name='明明', age=25}, Student{name='玲玲', age=20}]
=======使用下标或者元素属性名称删除元素===========
[Student{name='可可', age=18}, Student{name='小小', age=19}, Student{name='明明', age=25}, Student{name='玲玲', age=20}]
========使用元素源数据进行删除,需要重写equals方法===========
[Student{name='可可', age=18}, Student{name='明明', age=25}, Student{name='玲玲', age=20}]
============迭代器遍历法===========
Student{name='可可', age=18}
Student{name='明明', age=25}
Student{name='玲玲', age=20}
============列表迭代器遍历法===========
Student{name='可可', age=18}
Student{name='明明', age=25}
Student{name='玲玲', age=20}
============判断元素是否存在===========
true
false
============查找元素的下标===========
0
重写Student类的equals方法的比较方式
@Override
public boolean equals(Object obj) {
//判断是否为同一个对象
if(this==obj){
return true;
}
//是否为空
if(obj==null){
return false;
}
//判断是否为Student类型
if (obj instanceof Student){
Student s=(Student) obj;
//比较属性
if (this.name.equals(s.getName())&&this.age==s.getAge()){
return true;
}
}
return false;
}
3.2、Vector
package com.jjl.Collection;
import java.util.Enumeration;
import java.util.Vector;
/*
Vector集合的使用
*/
public class Demo06 {
public static void main(String[] args) {
Vector vector=new Vector<>();
vector.add("草莓");
vector.add("芒果");
vector.add("西瓜");
vector.add("香蕉");
System.out.println("元素个数"+vector.size());
//遍历
vector.remove(0);//可以根据角标和元素
//遍历,可以用for
//枚举器遍历
Enumeration en=vector.elements();
while (en.hasMoreElements()){
String o=(String) en.nextElement();
System.out.println(o);
}
//判断
System.out.println(vector.contains("西瓜"));
}
}
输出:
元素个数4
芒果
西瓜
香蕉
true
3.3、LinkedList
package com.jjl.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
/*
LinkedList的使用
*/
public class Demo07 {
public static void main(String[] args) {
//创建集合
LinkedList linkedList=new LinkedList<>();
//添加元素
Student s1=new Student("张三",23);
Student s2=new Student("张四",24);
Student s3=new Student("张五",25);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
linkedList.add(s3);
System.out.println("=====打印元素个数=======");
System.out.println("元素个数:"+linkedList.size());
System.out.println("\n======打印所有元素=======");
System.out.println(linkedList.toString());
//2、删除
linkedList.remove(new Student("张三",23));//由于重写过equals方法,所以可以使用元素内容删除
System.out.println("\n=========删除元素之后的元素个数:===========");
System.out.println(linkedList.size());
//3遍历
System.out.println("\n=====for遍历========");
for (int i=0;i<linkedList.size();i++){
System.out.println(linkedList.get(i));
}
System.out.println("\n=========增强for遍历========");
for(Object object:linkedList){
Student s=(Student) object;
System.out.println(s.toString());
}
System.out.println("\n======迭代器遍历========");
Iterator it=linkedList.iterator();
while (it.hasNext()){
Student s=(Student) it.next();
System.out.println(s.toString());
}
System.out.println("\n======列表迭代器遍历========");
ListIterator lit=linkedList.listIterator();
while (lit.hasNext()){
Student s=(Student) lit.next();
System.out.println(s.toString());
}
System.out.println("\n======判断========");
System.out.println(linkedList.contains(s2));//判断元素是否存在
System.out.println(linkedList.isEmpty());//判断是否为空
System.out.println("\n======查找========");
System.out.println(linkedList.indexOf(s3));
}
}
输出:
=====打印元素个数=======
元素个数:4
======打印所有元素=======
[Student{name='张三', age=23}, Student{name='张四', age=24}, Student{name='张五', age=25}, Student{name='张五', age=25}]
=========删除元素之后的元素个数:===========
3
=====for遍历========
Student{name='张四', age=24}
Student{name='张五', age=25}
Student{name='张五', age=25}
=========增强for遍历========
Student{name='张四', age=24}
Student{name='张五', age=25}
Student{name='张五', age=25}
======迭代器遍历========
Student{name='张四', age=24}
Student{name='张五', age=25}
Student{name='张五', age=25}
======列表迭代器遍历========
Student{name='张四', age=24}
Student{name='张五', age=25}
Student{name='张五', age=25}
======判断========
true
false
======查找========
1
三、泛型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法。
- 语法:
- <T…> T称为类型占位符,表示一种引用类型。
- 好处:
- (1)提高代码的重用性
- (2)防止类型转换异常,提高代码的安全性
1、泛型类
创建泛型类
package com.jjl.MyGeneric;
/*
泛型类
语法,类名
T是类型占位符,表示一种引用类型,如果编写多个使用,逗号隔开。
*/
public class Demo01<T> {
//使用泛型
//1创建变量
T t;
//作为方法的参数
public void show(T t){
System.out.println(t);
}
//3使用泛型作为方法的返回值
public T getT(){
return t;
}
}
主程序测试
package com.jjl.MyGeneric;
import com.jjl.Exception.Demo02.MyException;
public class TestGeneric {
public static void main(String[] args) {
//使用泛型类T对象
//注意:1泛型只能使用引用类型。
//2不同泛型之间不能相互复制
Demo01<String> demo01=new Demo01<String>();
//demo01.t="hello";
demo01.show("大家好");
String string=demo01.getT();
Demo01<Integer> demo011=new Demo01<Integer>();
//demo011.t=100;
demo011.show(200);
Integer integer= demo011.getT();
}
}
输出:
大家好
200
2、泛型接口
创建接口
package com.jjl.MyGeneric;
/*
泛型接口
语法,接口<T>
注意,不能使用泛型创建静态常量
*/
public interface MyInterface<T> {
//String name="张三";
T server(T t);
}
接口实现类:方法一
直接指定参数类型
package com.jjl.MyGeneric;
public class MyInterfaceMpl implements MyInterface<String>{
@Override
public String server(String s) {
System.out.println(s);
return s;
}
}
接口实现类:方法二
不指定参数类型,让调用实现类时指定
package com.jjl.MyGeneric;
public class MyInterfacemp2<T> implements MyInterface<T>{
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
主程序调用
//方法一
MyInterfaceMpl impl=new MyInterfaceMpl();
impl.server("xxxxxxxxxxxx");
//方法二
MyInterfacemp2<Integer> ipl2=new MyInterfacemp2<>();
ipl2.server(2000);
3、泛型方法
创建一个泛型方法
package com.jjl.MyGeneric;
/*
泛型方法
语法:<T>方法返回值
*/
public class MyGenericthod {
//泛型方法
//格式一:
public <T> void show(T t){
System.out.println("泛型方法"+t);
}
/*
格式二:
public <T> t show(T t){
System.out.println("泛型方法"+t);
return t;
}
*/
}
主程序调用
//调用泛型方法
MyGenericthod myGenericthod=new MyGenericthod();
//不用指定类型,会自动根据给的值确定类型
myGenericthod.show("字符串");
myGenericthod.show(200);
myGenericthod.show(1.14);
输出:
泛型方法字符串
泛型方法200
泛型方法1.14
4、泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
- 特点:
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
package com.jjl.MyGeneric;
import com.jjl.Collection.Student;
import java.util.ArrayList;
import java.util.Iterator;
public class Demo02 {
public static void main(String[] args) {
//通过泛型,指定集合里的数据类型
ArrayList<String> arrayList=new ArrayList<String>();
arrayList.add("xxxx");
arrayList.add("yyy");
for (String string:arrayList){
System.out.println(string);
}
ArrayList<Student> arrayList2=new ArrayList<Student>();
Student s1=new Student("张三",23);
Student s2=new Student("张四",24);
Student s3=new Student("张五",25);
arrayList2.add(s1);
arrayList2.add(s2);
arrayList2.add(s3);
Iterator<Student> it= arrayList2.iterator();
while (it.hasNext()){
Student s=it.next();//由于“Iterator<Student>”已经指定了迭代器的类型,所以不用再转成student类型了。
System.out.println(s.toString());
}
}
}
输出:
xxxx
yyy
Student{name='张三', age=23}
Student{name='张四', age=24}
Student{name='张五', age=25}
四、Set集合
- 特点:无须、无下标、元素不可重复。
- 方法:全部继承自Collection中的方法。
package com.jjl.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/*
Set接口的使用
特点:无序、没有下标,不能重复
*/
public class Demo01 {
public static void main(String[] args) {
//创建集合
Set<String> set=new HashSet<>();
//1、添加数据
set.add("xiaomi");
set.add("vivo");
set.add("oppo");
set.add("HUAWEI");
System.out.println("元素个数:"+set.size());
System.out.println(set.toString());
//2删除
set.remove("xiaomi");
//3遍历
//方法一:增强for
System.out.println("\n=========增强for遍历=========");
for (String string:set){
System.out.println(string);
}
//方法二:迭代器
System.out.println("\n=========使用迭代器遍历=========");
Iterator<String> it=set.iterator();
while (it.hasNext()){
String sting= it.next();
System.out.println(sting);
}
//判断
System.out.println("\n=========判断元素是否存在=========");
System.out.println(set.contains("HUAWEI"));
System.out.println("\n=========判断是否为空=========");
System.out.println(set.isEmpty());
}
}
输出:
元素个数:4
[xiaomi, oppo, vivo, HUAWEI]
=========增强for遍历=========
oppo
vivo
HUAWEI
=========使用迭代器遍历=========
oppo
vivo
HUAWEI
=========判断元素是否存在=========
true
=========判断是否为空=========
false
1、Set实现类
1.1HashSet 【重点】
- 基于HashCode计算元素存放位置。
- 当存入元素的哈希码相同时,会调用equals进行确认,如结果为true,则拒绝后者存入。
package com.jjl.Set;
import java.util.HashSet;
import java.util.Iterator;
/*
HashSet集合的使用
存储结构:哈希表(数组+链表+红黑树)
*/
public class Demo02 {
public static void main(String[] args) {
//新建集合
HashSet<String> hashSet=new HashSet<String>();
//1添加元素
hashSet.add("刘德华");
hashSet.add("成龙");
hashSet.add("杨幂");
hashSet.add("热巴");
System.out.println("元素个数:"+hashSet.size());
System.out.println(hashSet.toString());
//删除
System.out.println("\n=======删除后的元素个数========");
hashSet.remove("热巴");
System.out.println("元素个数:"+hashSet.size());
//遍历增强for
System.out.println("\n=======增强for遍历========");
for (String string:hashSet){
System.out.println(string);
}
System.out.println("\n=======迭代器遍历========");
Iterator<String> it=hashSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//判断
System.out.println("\n=======判断元素是否存在,判断元素是否为空========");
System.out.println(hashSet.contains("热巴"));
System.out.println(hashSet.isEmpty());
}
}
输出:
元素个数:4
[成龙, 杨幂, 热巴, 刘德华]
=======删除后的元素个数========
元素个数:3
=======增强for遍历========
成龙
杨幂
刘德华
=======迭代器遍历========
成龙
杨幂
刘德华
=======判断元素是否存在,判断元素是否为空========
false
false
重写hashcode和equlas用于排重的方法
新建set类
package com.jjl.Set;
import java.util.Objects;
public class Person {
private String name;
private int age;
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 +
'}';
}
//以下是通过快捷方式一键生成的hashcode和equals用于去重的方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
//手动写的hashcode和equals用于去重的方法
// @Override
// public int hashCode() {
// int n1=this.name.hashCode();
// int n2=this.age;
// return n1+n2;
// }
//
// @Override
// public boolean equals(Object obj) {
// 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;
// }
}
重写hashcode和equlas用于排重的方法的快捷方法:
主程序调用
package com.jjl.Set;
import java.util.HashSet;
/*
hashset使用
存储过程:
(1)根据hashcode计算保存的位置。如果此位置为空。则直接保存。如果不为空执行第二步。
(2)再执行equals方法。如果equals方法为true,则认为是重复,否则形成链表
*/
public class Demo03 {
public static void main(String[] args) {
HashSet<Person> person=new HashSet<>();
Person p1=new Person("刘德华",50);
Person p2=new Person("成龙",60);
Person p3=new Person("林志玲",20);
Person p4=new Person("宋小宝",10);
person.add(p1);
person.add(p2);
person.add(p3);
person.add(p4);
person.add(p4);//以这种方式,Java会认为是重复数据,不能加入Hashset
//以这种方式又可以加入重复的的数据,如果想让它加入不进去,就需要重写Person类的hashcode方法和equals方法
person.add(new Person("宋小宝",10));
System.out.println("打印元素个数:"+person.size());
System.out.println(person);
}
}
1.2、TreeSet:
- 基于排列顺序实现元素不重复。
- 实现了SortedSet接口,对集合元素自动排序。
- 元素对象的类型必须实现Comparable接口,指定排序规则。
- 通过CompareTo方法确定是否为重复元素。
简单使用
package com.jjl.Set;
import java.util.Iterator;
import java.util.TreeSet;
/*
TreeSet的使用
存储结构:红黑树
*/
public class Demo04 {
public static void main(String[] args) {
//1创建集合
TreeSet<String> treeSet=new TreeSet<>();
//1添加元素
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("hello");
System.out.println("打印元素个数:"+treeSet.size());
System.out.println(treeSet);//自动排序
treeSet.remove("hello");
System.out.println("\n删除后元素个数:"+treeSet.size());
System.out.println("\n=====增强for遍历=========");
for(String string:treeSet){
System.out.println(string);
}
System.out.println("\n=====迭代器遍历=========");
Iterator<String> it=treeSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("\n=====判断=========");
System.out.println(treeSet.contains("abc"));
}
}
打印:
打印元素个数:3
[abc, hello, xyz]
删除后元素个数:2
=====增强for遍历=========
abc
xyz
=====迭代器遍历=========
abc
xyz
=====判断=========
true
复杂参数
package com.jjl.Set;
import java.util.TreeSet;
/*
存储方式:红黑树
要求:元素必须要实现Comparable接口,compareTo()方法的返回值为0时,则意味着为重复的
*/
public class Demo05 {
public static void main(String[] args) {
//创建集合
TreeSet<Person> person=new TreeSet<>();
Person p1=new Person("刘德华",50);
Person p2=new Person("成龙",60);
Person p3=new Person("林志玲",20);
Person p4=new Person("宋小宝",10);
person.add(p1);
person.add(p2);
person.add(p3);
person.add(p4);
System.out.println("打印元素个数:"+ person.size());
System.out.println(person);
}
}
由于上面treeset的元素时Person类,所以就需要Person实现Comparable接口,compareTo()方法的返回值为0时,则意味着为重复的
package com.jjl.Set;
import java.util.Objects;
public class Person implements Comparable<Person>{
private String name;
private int age;
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 +
'}';
}
//以下是通过快捷方式一键生成的hashcode和equals用于去重的方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Person)) return false;
Person person = (Person) o;
if (age != person.age) return false;
return name != null ? name.equals(person.name) : person.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
/**
* @param o the object to be compared.
* @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;
}
//手动写的hashcode和equals用于去重的方法
// @Override
// public int hashCode() {
// int n1=this.name.hashCode();
// int n2=this.age;
// return n1+n2;
// }
//
// @Override
// public boolean equals(Object obj) {
// 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;
// }
}
定制比较,不用单独在Person类实现Comparable接口
package com.jjl.Set;
import java.util.Comparator;
import java.util.TreeSet;
/*
TreeSet集合的使用
Comparator:实现定制比较
*/
public class Demo06 {
public static void main(String[] args) {
//通过匿名内部类的方式,实现比较方式,就不用在Person类里面去实现实现Comparable接口了
TreeSet<Person> person=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 n1==0?n2:n1;
}
});
Person p1=new Person("刘德华",50);
Person p2=new Person("成龙",60);
Person p3=new Person("林志玲",20);
Person p4=new Person("宋小宝",10);
person.add(p1);
person.add(p2);
person.add(p3);
person.add(p4);
System.out.println("打印元素个数:"+ person.size());
System.out.println(person);
}
}
案例
使用Treeset集合实现字符串按照长度进行排序
package com.jjl.Set;
import java.util.Comparator;
import java.util.TreeSet;
/*
通过定制比较规则
使用Treeset集合实现字符串按照长度进行排序
*/
public class Demo07 {
public static void main(String[] args) {
TreeSet<String> treeSet=new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int n1=o1.length()-o2.length();
int n2=o1.compareTo(o2);
return n1==0?n2:n1;
}
});
//添加数据
treeSet.add("helloword");
treeSet.add("pingguo");
treeSet.add("lisi");
treeSet.add("zhangsan");
treeSet.add("beijing");
treeSet.add("cat");
treeSet.add("nanjing");
treeSet.add("xian");
System.out.println(treeSet.toString());
}
}
输出:
[cat, lisi, xian, beijing, nanjing, pingguo, zhangsan, helloword]
三、Map集合
1、Map父接口
- 特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复。
- 方法:
- V put(K key,V value)//将对象存入到集合中,关联键值。key重复则覆盖原值。
- Object get(Object key)//根据键获取对应的值。
- Set< K >//返回所有key。
- Collection < V > values() //返回包含所有值的Collection集合。
- Set<Map. Entry<K,V>>//键值匹配的Set集合。
基本使用
package com.jjl.Map;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
map接口使用
特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
*/
public class Demo01 {
public static void main(String[] args) {
//创建map集合
Map<String,String> map=new HashMap<>();
map.put("CN","中国");
map.put("UK","英国");
map.put("USA","美国");
map.put("JP","日本");
//map.put("JP","riben");//如果,添加重复的value,那么则会覆盖前面的value和key。
System.out.println("打印元素个数:"+map.size());
System.out.println(map);
System.out.println("\n=========删除之后的个数=========");
map.remove("JP");
System.out.println("打印元素个数:"+map.size());
//3遍历
//使用keySet();
System.out.println("\n========keyset()遍历===========");
Set<String> keyset=map.keySet();
for (String key:keyset){
System.out.println(key+":"+map.get(key));
}
//使用entryset()方法
System.out.println("\n========entrySet遍历===========");
//Set<Map.Entry<String,String>> entries=map.entrySet();
for(Map.Entry<String,String>entry: map.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
System.out.println("\n=====判断=====");
System.out.println(map.containsKey("CN"));
System.out.println(map.containsValue("俄罗斯"));
输出:
打印元素个数:4
{USA=美国, UK=英国, JP=日本, CN=中国}
=========删除之后的个数=========
打印元素个数:3
========keyset()遍历===========
USA:美国
UK:英国
CN:中国
========entrySet遍历===========
USA:美国
UK:英国
CN:中国
=====判断=====
true
false
}
}
2、Map集合的实现类
2.1、HashMap【重点】:
- JDK1.2版本,线程不安全,运行效率快;允许用null作为key或是value。
新增一个学生类
为了确保key的不可重复性,所以需要重写Hashcode和equls方法
package com.jjl.Map;
public class Student {
private String name;
private int stuNo;
public Student() {
}
public Student(String name, int stuNo) {
this.name = name;
this.stuNo = stuNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNo() {
return stuNo;
}
public void setStuNo(int stuNo) {
this.stuNo = stuNo;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNo=" + stuNo +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
if (stuNo != student.stuNo) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + stuNo;
return result;
}
}
主程序测试
package com.jjl.Map;
import com.jjl.Set.Person;
import java.util.HashMap;
import java.util.Map;
/*
HashMap集合使用
存储结构:哈希表(数组+链表+红黑树)
使用KEY的Hashcode和equals作为重复依据
*/
public class Demo02 {
public static void main(String[] args) {
//创建集合
HashMap<Student,String> student=new HashMap<Student,String>();
//添加元素
Student s1=new Student("张一",100);
Student s2=new Student("张二",200);
Student s3=new Student("张三",300);
student.put(s1,"北京");
student.put(s2,"成都");
student.put(s3,"重庆");
//通过new的方法可以实现元素重复添加,如果想要new也加不进去,就需要重写Hashcode和equals
student.put(new Student("张三",300),"杭州");
System.out.println("打印元素个数:"+student.size());
System.out.println(student);
System.out.println("\n==========删除之后的元素个数=======");
student.remove(s1);
System.out.println(student.size());
System.out.println("\n========keySet遍历===========");
for(Student key:student.keySet()){
System.out.println(key+":"+student.get(key));
}
System.out.println("\n========Entry遍历===========");
for(Map.Entry<Student,String> entry:student.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
//判断
System.out.println("\n========判断key或者value是否存在===========");
System.out.println(student.containsKey(s2));
System.out.println(student.containsValue("成都"));
}
}
输出:
打印元素个数:3
{Student{name='张二', stuNo=200}=成都, Student{name='张一', stuNo=100}=北京, Student{name='张三', stuNo=300}=杭州}
==========删除之后的元素个数=======
2
========keySet遍历===========
Student{name='张二', stuNo=200}:成都
Student{name='张三', stuNo=300}:杭州
========Entry遍历===========
Student{name='张二', stuNo=200}:成都
Student{name='张三', stuNo=300}:杭州
========判断key或者value是否存在===========
true
true
总结:
- (1 )HashMap刚创建时,table是null,为了节省空间,当添加第一个元素是,table容量调整为16
- (2)当元素个数大于阈值(16*8.75=12)时,会进行扩容,扩容后大小为原来的2倍。目的是减少调整元素的个数。
- (3)jdk1.8当每个链表长度大于8,并且数组元素个数大于等于64时,会调整为红黑树,目的提高执行效率
- (4)jdk1.8 当链表长度小于6时,调整成链表
- (5)jdk1.8以前,链表时头插入,jdk1.8以后时是尾插入
3、Hashtable:
- .JDK1.0版本,线程安全,运行效率慢;不允许null作为key或是value。
- Properties :
- Hashtable的子类,要求key和value都是String。通常用于配置文件的读取。
4、TreeMap :
- 实现了SortedMap接口(是Map的子接口),可以对key自动排序。
- 要求元素实现Comparable接口,重写比较器
让元素类实现Comparable接口
主程序测试
package com.jjl.Map;
/*
TreeMap的使用
*/
import java.util.Map;
import java.util.TreeMap;
public class Demo03 {
public static void main(String[] args) {
//新建集合
TreeMap<Student, String> treemap=new TreeMap<>();
Student s1=new Student("张一",100);
Student s2=new Student("张二",200);
Student s3=new Student("张三",300);
treemap.put(s1,"北京");
treemap.put(s2,"成都");
treemap.put(s3,"重庆");
System.out.println("打印元素个数:"+treemap.size());
System.out.println(treemap);
//遍历
System.out.println("\n======entryset()遍历====");
for (Student key : treemap.keySet()){
System.out.println(key+":"+treemap.get(key));
}
System.out.println("\n======entryset()遍历====");
for (Map.Entry<Student,String> entry:treemap.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
输出:
打印元素个数:3
{Student{name='张一', stuNo=100}=北京, Student{name='张二', stuNo=200}=成都, Student{name='张三', stuNo=300}=重庆}
======entryset()遍历====
Student{name='张一', stuNo=100}:北京
Student{name='张二', stuNo=200}:成都
Student{name='张三', stuNo=300}:重庆
======entryset()遍历====
Student{name='张一', stuNo=100}:北京
Student{name='张二', stuNo=200}:成都
Student{name='张三', stuNo=300}:重庆
当元素类不能实现Comparable接口时,可以使用定制比较
package com.jjl.Map;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class Demo04 {
public static void main(String[] args) {
//新建集合(定制比较)
TreeMap<Student, String> treemap=new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int n2= o1.getStuNo()-o2.getStuNo();
return n2;
}
});
Student s1=new Student("张一",100);
Student s2=new Student("张二",200);
Student s3=new Student("张三",300);
treemap.put(s1,"北京");
treemap.put(s2,"成都");
treemap.put(s3,"重庆");
System.out.println("打印元素个数:"+treemap.size());
System.out.println(treemap);
//遍历
System.out.println("\n======entryset()遍历====");
for (Student key : treemap.keySet()){
System.out.println(key+":"+treemap.get(key));
}
System.out.println("\n======entryset()遍历====");
for (Map.Entry<Student,String> entry:treemap.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
5、Colletions工具类
- 概念:集合工具类,定义了除了存取以外的集合常用方法。
- 方法:
- public static void reverse(List<?> list) //反转集合中元素的顺序
- public static void shuffle(List<?> list) //随机重置集合元素的顺序
- public static void sort(List< T > list) //升序排序(元素类型必须实现Comparable接口)
package com.jjl.Map;
import java.lang.reflect.Array;
import java.util.*;
/*
Colletions工具类的使用
*/
public class Demo05 {
public static void main(String[] args) {
List<Integer> list=new ArrayList<>();
list.add(20);
list.add(5);
list.add(12);
list.add(30);
list.add(6);
//sort排序
System.out.println("排序前:"+list.toString());
Collections.sort(list);
System.out.println("排序之后:"+list.toString());
System.out.println("\n======binarySearch,二分查找======");
//binarySearch,二分查找,如果找到了,则返回该元素的下标,如果没找到,则就返回一个负数
int i=Collections.binarySearch(list,6);
System.out.println(i);
//copy复制
//新建一个目标集合
System.out.println("\n===========copy复制=====");
List<Integer> dest=new ArrayList<>();
//如果直接用“Collections.copy(dest,list);”复制元素,会报错,因为dest里面没有元素,默认大小为0,而list里面已经有5个元素了。
//为了保证目标集合长度和源集合长的时一样的,则需要用for往目标集合里面添加一些占位元素。
for (int k=0;k<list.size();k++){
dest.add(0);
}
Collections.copy(dest,list);
System.out.println(dest);
//reverse反转
Collections.reverse(list);
System.out.println("\n反转之后:"+list);
//shuffle打乱
Collections.shuffle(list);
System.out.println("\n打乱之后:"+list);
//补充,list转成数组
System.out.println("\n=========list转成数组============");
Integer[] arr=list.toArray(new Integer[0]);
System.out.println(arr.length);
System.out.println(Arrays.toString(arr));
System.out.println("\n=========数组(每个元素都是字符串)转成集合============");
String[] name={"张一","张二","张三"};
//通过这种方式转成的集合,它是一个受限集合,不能添加和删除元素
List<String> list2=Arrays.asList(name);
System.out.println(list2);
System.out.println("\n=========数组(每个元素都是数字)转成集合============");
//将基本类型数组转换为集合,需要修改为包装类
Integer[] nums={100,200,300,400,500};
List<Integer> list3=Arrays.asList(nums);
System.out.println(list3);
}
}
输出:
排序前:[20, 5, 12, 30, 6]
排序之后:[5, 6, 12, 20, 30]
======binarySearch,二分查找======
1
===========copy复制=====
[5, 6, 12, 20, 30]
反转之后:[30, 20, 12, 6, 5]
打乱之后:[12, 5, 20, 30, 6]
=========list转成数组============
5
[12, 5, 20, 30, 6]
=========数组(每个元素都是字符串)转成集合============
[张一, 张二, 张三]
=========数组(每个元素都是数字)转成集合============
[100, 200, 300, 400, 500]
四、集合总结
- 集合的概念:
- 对象的容器,和数组类似,定义了对多个对象进行操作的常用方法。
- List集合:
- 有序、有下标、元素可以重复。(ArrayList、LinkedList、Vector>
- Set集合:
- 无序、无下标、元素不可重复。(HashSet、TreeSet)
- Map集合:
- 存储一对数据,无序、无下标,键不可重复,值可重复。(HashMap、HashTable、TreeMap)
- Collections:
- 集合工具类,定义了除了存取以外的集合常用方法。