Java集合
1.Java集合概述
- java集合类存放在java.util中,是用来存放对象的容器
- 集合只能存放对象。比如你存放一个int型数据放入集合中,其实它是转换为Integer类后存入的,java中每一个基本类型都有对应的包装类
- 集合存放的是多个对象的引用,对象本身还是在堆内存中
- 集合可以存放不同类型,不限数量的数据类型
- java集合可以分为Set,List,Map三大体系
- Set:无序,不可重复的集合(一般是指HashSet集合)
- List:有序,可重复的集合
- Map:具有映射关系的集合
2.Set集合
HashSet集合(常用)
概述:HashSet按Hash算法来存储集合中元素,因此有很好的存取和查找性能,HashSet类实现了Set接口,Set接口继承了Collection接口
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-24sjk4bH-1593142186423)(/Volumes/磁盘/Study data/Java学习/java基础/集合/HashSet集合.png)]
特点:
- 不能保证元素的排序顺序(存在Set集合哪个位置由这个值的hashCode值来决定)
- 不可重复(不可重复指的是hashCode值不相等)
- HashSet不是线程安全的
- 集合元素可以使用Null
解释特点一:
当向HashSet集合中存入一个元素时,HashSet会调用对象的HashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定对象在HashSet集合中的存储位置。
eg:第一个值是a,第二个值是4,不保证a一定在集合的第一个位置
代码举例:
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("s");//添加元素
set.add("d");//添加元素
set.add("f");//添加元素
set.add("g");//添加元素
System.out.println(set);//集合元素的输出
set.remove("s");//移除元素
System.out.println(set);
System.out.println(set.contains("s"));//判断集合中是否存在元素返回为Bool值
//2种遍历集合的方法
//1.使用迭代器遍历Iterator
Iterator it = set.iterator();
while (it.hasNext())
System.out.println(it.next());
System.out.println("========");
//2.使用for each遍历
for (String s : set) { //将set中的值一个赋值给S,直到循环到set中的所有值
System.out.println(s);
}
set.clear();//清除集合中的元素
}
}
TreeSet集合
概述:TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
TreeSet支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet采用自然排序
自然排序方法
排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排序,也可以将实现Comparator接口中的方法进行重写来自定义排序。
- 如果this > obj,返回正数1
- 如果this < obj,返回正数-1
- 如果this = obj,返回正数0
注意:必须放入同样类的对象(默认会进行排序)否则可能会发生类型转换异常,我们可以通过泛型来进行限制
代码举例
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class Test1 {
public static void main(String[] args) {
Set<Person> set = new TreeSet<>(new Person());//括号里默认的是Comparable类,Comparable类需要强制类型转换为Person类才可以。
Person p1 = new Person(28,"张三");
Person p2 = new Person(20,"李四");
Person p3 = new Person(26,"王五");
set.add(p1);
set.add(p2);
set.add(p3);
for (Person person : set) {
System.out.println(person.getAge()+" "+person.getName());
}
}
}
class Person implements Comparator<Person> {
public Person() {
}
private int age;
private String name;
public Person(int age,String name) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public int compare(Person o1, Person o2) {//实现Comparator接口中compare方法
if (o1.getAge() > o2.getAge()) {
return 1;
} else if (o1.getAge() < o2.getAge()) {
return -1;
}else{
return 0;
}
}
}
3.List集合
ArrayList集合(常用)
- List表示一个元素有序(是添加元素的位置是固定的,和HashSet不同,HashSet是调用hashCode方法从而导致元素位置不确定),且可重复的集合,集合中的每个元素都有其对应的顺序索引
- List允许使用重复元素,可以通过索引来访问指定位置的集合元素
- List默认按元素的添加顺序设置元素的索引
- List集合里添加了一些根据索引来操作集合元素的方法
ArrayList和Vector
ArrayList和Vector是List接口的两个典型实现区别
- Vector是一个古老的集合,通常建议使用ArrayList
- ArrayList是线程不安全的,而Vector是线程安全的
- 即使为保证List集合线程安全,也不推荐使用Vector
代码示例
import java.util.ArrayList;
import java.util.List;
public class Test2 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("f");//第一个索引下标为0
list.add("b");//第二个索引下标为1
list.add("c");//第三个索引下标为2
list.add("d");//第四个索引下标为3
list.add("d");//第五个索引下标为4,允许重复
System.out.println(list.get(1));//通过索引来访问集合元素,有点像数组下标
System.out.println(list);
list.add(1, "a");//在指定索引下标插入元素
System.out.println(list);
List<String> list1 = new ArrayList<>();
list1.add("123");
list1.add("553");
list.addAll(1, list1);//在指定索引下标插入List集合addAll方法
System.out.println(list);
System.out.println(list.indexOf("d"));//获取指定元素在集合中第一次出现的索引下标,第一次
System.out.println(list.lastIndexOf("d"));//获取指定元素在集合中最后一次出现的下标,最后一次
list.remove(1);//根据索引移除集合中元素
System.out.println(list);
list.set(1, "fff");//根据指定索引下标修改元素
System.out.println(list);
//根据索引下标的起始位置截取一段元素形参赋值给新的集合,截取的时候,包含开始的索引不包含结束时的索引
List<String> sublist = list.subList(2,4);//取索引下标在大于等于2小于4的元素
System.out.println(sublist);
System.out.println(sublist.size());
}
}
4.Map集合
HashMap集合(常用)
- Map用于保存具有映射关系的数据(有点像函数),因此Map集合里保存着两组值,一组值用于保存Map里的Key,另外一组用于保存Map中的Value
- Map中的Key和Value都可以是任何引用类型的数据
- Map中的Key不允许重复,(就像函数中的X定义域),那么同一个Map对象的任意的两个Key通过equals方法返回的都是false
- Key和Value之间存在单向一对一关系,即通过指定的Key总能找到唯一的,确定的value
HashMap&Hashtable
代码示例:
import java.util.*;
public class Test3 {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("b", 1);//添加数据
map.put("c", 2);
map.put("e", 2);
System.out.println(map);
System.out.println(map.get("b"));//根据Key取Value
map.remove("c");//根据key移除键值对
System.out.println(map);
System.out.println(map.size());
// map.clear();//清空集合
Set<String> keys = map.keySet();//获取map集合中的key集合,用Set接口引用接收
Collection<Integer> list = map.values();//获取集合的所有Value值
System.out.println(list);
//两种遍历方法
//遍历map集合,通过map.keyset();遍历
for (String key : keys) {
System.out.println(("key:" + key + " Value:" + map.get(key)));
}
System.out.println("================");
//通过map.entrySet();遍历map集合
Set<Map.Entry<String, Integer>> entrys = map.entrySet();
for (Map.Entry<String, Integer> entry : entrys) {
System.out.println("Key:"+entry.getKey()+" Value"+entry.getValue());
}
}
}
TreeMap集合
TreeMap存储Key—Value对时,需要根据Key对key-value进行排序。TreeMap可以保证所有的Key-Value对处于有序状态
TreeMap的Key的排序
- 自然排序:TreeMap的所有的Key必须实现Comparable接口,而且所有的Key应该是同一个类的对象,否则将会被抛出ClassCastException
- 定制排序(了解):创建TreeMap时,传入Comparator对象,该对象负责对TreeMap中的所有Key进行排序。此时不需要Map的Key实现Comparable接口
(一般的使用Map集合,不会使用过于复杂对象做Key)
5.Collections工具类
概述:Collections是一个操作Set,List,Map等集合的工具类,Collections中提供了大量方法对集合元素进行排序,查询,修改等操作还提供对集合元素设置不可变,对集合对象实现同步控制等方法
排序操作:
- reverser(List):反转List中的元素的排序
- shuffle(List):对List集合元素进行随机排序
- sort(List):根据自然顺序对指定List集合元素按升序排序
- sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
- swap(List,int,int):将指定List集合中的i处元素和j处元素进行交换
查找和替换
代码示例:
import java.util.*;
public class Test4 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("b");//添加元素
list.add("bd");
list.add("bs");
list.add("ba");
System.out.println(list);
Collections.reverse(list);//反转list中的元素的排序
System.out.println(list);
Collections.shuffle(list);//对list集合元素进行随机排序
System.out.println(list);
Collections.sort(list);//对list集合进行升序
System.out.println(list);
Collections.swap(list,0,2);//交换list集合中索引为0和索引为2的元素
System.out.println(list);
//第二个Collections.sort()的使用
List<Student> set = new ArrayList<Student>();
Student p1 = new Student(28,"张三");
Student p2 = new Student(20,"李四");
Student p3 = new Student(26,"王五");
set.add(p1);
set.add(p2);
set.add(p3);
Collections.sort(set,new Student());//使用第二个参数是要排序的对象
for (Student student : set) {
System.out.println("name:"+student.getName()+" age"+student.getAge());
}
System.out.println("==================");
Student stu = Collections.max(set, new Student());//查找集合元素中最大的,方法返回Student型
System.out.println("name:"+stu.getName()+" age"+stu.getAge());
Student stu1 = Collections.min(set, new Student());//查找集合元素中最小的,方法返回Student型
System.out.println("name:"+stu1.getName()+" age"+stu1.getAge());
int i = Collections.frequency(set, stu);//为了查找元素在集合中出现的次数第一个参数是要查找的集合。第二个参数是集合中的元素
System.out.println(i);
}
}
class Student implements Comparator<Student> {
public Student() {
}
private int age;
private String name;
public Student(int age,String name) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public int compare(Student o1, Student o2) {//实现Comparator接口中compare方法
if (o1.getAge() > o2.getAge()) {
return 1;
} else if (o1.getAge() < o2.getAge()) {
return -1;
}else{
return 0;
}
}
}
6.泛型
泛型:只有指定类型才能添加到集合中,为了类型安全。java中的泛型,只有在编译阶段有效,在编译期发现错误,泛型的信息不会进入运行时阶段
泛型类
- 对象实例化时不指定泛型,默认为:Object
- 泛型不同的引用不能相互赋值
代码示例
public class Test5 {
public static void main(String[] args) {
A<String> a = new A<>();//在new A时指定泛型的类型为String类
a.setKey("111");
System.out.println(a.getKey());
A<Integer> b= new A<>();//在new A时指定泛型的类型为Integer类
b.setKey(11);
System.out.println(b.getKey());
A c = new A();//在new A时不指定泛型的类型默认为Object类
c.setKey(1111111);
System.out.println(c.getKey());
}
}
class A<T> {
private T key;
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
}
泛型接口
格式:interface 标识符{}
两种实现方式:
- 未传入泛型实参时,与泛型定义相同,在声明类的时候,需将泛型的声明也一起加到类中
new 对象的时候需要指定数据类型
- 如果实现接口时指定接口的泛型的具体数据类型这个类实现接口所有方法的位置都要泛型替换实际的具体数据类型
new 对象的时候不需要指定数据类型,默认String
public class Test6 {
public static void main(String[] args) {
B<String> b2 = new B<>();//第一种
B<Object> b = new B<>();
B1 b1 = new B1();//第二种
}
}
interface IB<T>{
T test(T t);
}
/**
* 未传入泛型实参时,与泛型定义相同,在声明类的时候,需将泛型的声明也一起加到类中
* new 对象的时候需要指定数据类型
*/
class B<T> implements IB<T> {
@Override
public T test(T t) {
return t;
}
}
/**
* 如果实现接口时指定接口的泛型的具体数据类型
* 这个类实现接口所有方法的位置都要泛型替换实际的具体数据类型
* new 对象的时候不需要指定数据类型,默认String
*/
class B1 implements IB<String> {
@Override
public String test(String s) {
return null;
}
}
泛型方法
-
静态类型的泛型方法
-
无返回值的泛型方法
-
有返回值的泛型方法
-
形参为可变参数的泛型方法
调用时:
-
泛型方法,在调用之前没有固定的数据类型
-
在调用时,传入的参数是什么类型,就会把泛型改成什么类型
-
也就是说,泛型方法会在调用时确定泛型的数据类型
public class Test7 {
public static void main(String[] args) {
C<Object> c = new C<>();
/**
* 泛型方法,在调用之前没有固定的数据类型
* 在调用时,传入的参数是什么类型,就会把泛型改成什么类型
* 也就是说,泛型方法会在调用时确定泛型的数据类型
*/
Integer i = c.test2(2);//传入的参数是Integer,泛型就固定成Integer,返回值就是Integer
String x = c.test2("xxx");//传入的参数是String,泛型就固定成String,返回值就是String
Boolean Bool = c.test2(true);//传入的参数是Boolean,泛型就固定成Boolean,返回值就是Boolean
}
}
class C<E>{
private E e;
/**
* 静态方法的泛型方法
*/
public static <T> void test(T t){
//在静态方法中,不能使用类定义泛型,如果要使用泛型,只能使用静态方法自己定义的泛型
System.out.println(t);
}
/**
* 无返回值得泛型方法
*/
public <T> void test1(T s) {
//在类中定义的泛型,可以在普通的方法中使用
System.out.println(this.e);
T t = s;
}
/**
* 有返回值的泛型方法
*/
public <T> T test2(T t) {
return t;
}
/**
* 形参为可变参数的泛型方法
*/
public <T> void test3(T... str) {
for (T t : str) {
System.out.println(t);
}
}
}
通配符
用途: 不确定集合中的元素具体的数据类型,使用?表示所有类型
格式:public void test(List<?> list){
System.out.println(list);}
有限制的通配符:
- <? extend Person> (无穷小,Person] - 只允许泛型为Person及Person子类的引用
- <? super Person> [Person, 无穷大] - 只允许泛型为Person及Person父类的引用
- <? extends 接口> - 只允许泛型为实现接口的实现类的引用调用
本次学习资源来自b站java基础学习
点击跳转学习资源