Java 集合概述
Java集合类存放在java.util包中,是一个用来存放对象的容器
- 集合只能存放对象,比如存一个int型数据1放入集合中,其实它时自动转换成Integer类后存入的,Java中每一种基本类型都有对应的引用类型
- 集合存放的是多对象的引用,对象本身还是放在堆内存中
- 集合可以存放不同类型,不限数量的数据类型
Java集合可分成Set、List和Map三大体系
- Set: 无序、不可重复的集合
- List:有序、可重复的集合
- Map:具有映射关系的集合
注:JDK5后,增加了泛型,Java集合可以记住容器中对象的数据类型
1.HashSet
Hashset是Set接口的典型实现,大多数时候使用Set集合时都使用这个实现类。大多时候说的Set集合指的就是HashSet
HashSet按照Hash算法来存储集合中的元素,具有很好的存取和查找性能
HashSet具有以下特点:
- 不能保证元素的排列顺序(存在set集合哪个位置由这个位置的hashcode决定)
- 不可重复(指的是hashCode不相同)
- HashSet不是线程安全的
- 集合元素可以存储null
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在HashSet的存储位置
如果两个元素的equals()方法返回true,但它们的hashCode()返回值不相等,hashSet将会把它们存储在不同的位置,依然可以添加成功
public class Test{
public static void main(String[] args){
Set set = new HashSet();
Set<String> set1 = new HashSet<String>();//指定为String类型的泛型
set.add(1);//添加元素
set.add("a");
set.remove(1);//移除元素
set.contains(1);//判断是否包含该元素
set.clear();//清空元素
set.add("a");
set.add("b");
set.add("c");
//使用迭代器遍历集合
Iterator it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//for each迭代集合
for(Object obj:set){//把set集合中的每一个值取出来,赋值给obj,直到循环set的所有值
System.out.println(obj);
}
}
}
/*HashSet集合判断两个元素相等的标准:两个对象通过equals()方法比较相等,
并且两个对象的hashCode()方法返回值也相等*/
2.TreeSet
TreeSet 是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态,TreeSet支持两种排序方式: 自然排序和定制排序。默认情况下,TreeSet采用自然排序
自然排序
排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列
- 若this>obj,return 1;
- 若this<obj,return -1;
- 若this==obj,return 0;认为这两个对象相等
- 必须放入同样类的对象(默认会进行排序)否则可能会发生类型转换异常,我们可以使用泛型来进行限制
定制排序
若需要实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator接口的实现类对象,由该Comparator对象负责集合元素的排列逻辑
public class Test{
public static void main(String[] args){
Person p1 = new Person("张山",22);
Person p2 = new Person("李四",20);
Person p3 = new Person("王五",27);
Person p4 = new Person("六一",23);
Set<Person> set = new TreeSet<Person>(new Person());
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
for(Person p:sset){
System.out.println(p.name+" "+p.age);
}
}
class Person implements Comparetor<Person>{
private String name;
private int age;
public Person(){}
public Person(String name,int age){
this.name = name;
this.age = age;
}
@Override
public int compare(Person o1,Person 02){//正序排列
if(o1.age>o2.age) return 1;
else if(o1.age>o2.age) return -1;
else return 0;
}
}
3.List与ArrayList
List代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
public class Test{
public static void main(String[] args){
List<String> list = new ArrayList<String>();
list.add("b");//第一个,索引下标为0
list.add("d");
list.add("c");
list.add("b");//允许使用重复元素
System.out.println(list.get(2));//通过索引来访问指定位置的集合元素
list.add(1,"f");//在指定索引下标的位置插入数据
List<String> s = new ArraayLlist<String>();
s.add("123");
s.add("345");
list.addAll(2,s);//在指定索引下标的位置插入s集合
System.out.println(list);
System.out.println(list.indexof("d"));//获取指定元素在集合中第一次出现的索引下标
System.out.println(list.lastIndexof("d"));//获取指定元素在集合中最后一次出现的索引下标
list.remove(2);//根据指定索引位置移除元素
list.set(1,"fff");//根据指定的索引下标修改元素
//根据索引下的起始位置截取一段元素形成一个新的集合,截取的时间,
//包含开始的索引不包含结束的索引
List<String> sublist = list.subList(2,4);//取索引下标在>=2,<4的元素
System.out.println(sublist);
}
}
4.Map与HashMap
Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的Key,另外一组用于保存Map里的Value
Map中的key和value都可以是任何引用类型的数据,Map中的Key不允许重复,即同一个Map对象的任何两个Key通过equals方法比较中返回false
Key和Value之间存在单向一对一关系,即通过指定的Key总能找到唯一的,确定的Value
public class Test{
public static void main(String[] args){
Map<String,Integer> map = new HashMap<String,Integet>();
map.put("b",1);//添加数据
map.put("c",4);
map.put("s",3);
System.out.println(map.get("b"));//输出1,根据key值取value值
map.remove("c");//根据key移除键值对
System.out.println(map.containsKey("a"));//判断当前map集合是否包含指定的key
System.out.println(map.containsValue(3));//判断当前map集合是否包含指定的value
Set<String> keys = map.keySet();//获取map集合的key的集合
Set<Integer> values = map.values();//获取map集合的所有value
//遍历map集合,通过map.keySet()
for(String key:keys){
System.out.println("key:"+key+","+"value:"+map.get(key));
}
//通过map.entrySet()
Set<Entry<String,Integer>> entrys = map.entrySet();
for(Entry<String,Integer> en:entrys){
System.out.println("key:"+en.getKey()+","+"value:"+en.getValue());
}
}
/*HashMap和Hashtable是map接口的两个典型实现类
Hashtable是线程安全的Map实现类,HashMap线程不安全
Hashtable不允许使用null作为key和value,而HashMap可以
Hashmap、Hashtable判断两个value相等的标准:
两个value通过equalHashMap判断两个values方法返回true
Hashmap、Hashtable判断两个key相等的标准:
两个key通过equals方法返回true,hashCode值也相等*/
}
5.TreeMap
TreeMap存储key-value对时,需要根据key对key-value对进行排序,TreeMap可以保证所有的key-value对处于有序状态
TreeMap对key的排序:
- 自然排序
TreeMap的所有的key必须实现comparable接口,而且所有的key应该是同一个类的对象 - 制定排序
创建TreeMap时,传入一个Comparator对象,该对象负责对TreeMap中的所有key进行排序,此时不需要Map的key实现Comparable接口
public class Test{
public static void main(String[] args){
Map<Integer,String> map = new TreeMap<Integer,String>();
map.put(1,"a");
map.put(4,"a");
map.put(2,"a");
map.put(3,"a");
System.out.println(map);//TreeMap的自然排序是字典排序
}
}
6.Collections[操作集合的工具类]
Collections是一个操作Set、List和Map等集合的工具类
public class Test{
public static void main(String[] args){
List<String> list = new ArrayList<String>();
list.add("b");
list.add("ddd");
list.add("av");
Collections.reverse(list);//反转list中元素的顺序
System.out.println(list);
Collections.shuffle(list);//对list集合元素进行随机排序
Collections.sort(list);//list集合字典升序排列
System.out.println(Collections.frequency(list,"x"));//返回指定集合中指定元素的出现次数
Collections.swap(list,0,2);//将指定list集合中的i[0]处元素和j[2]处元素进行交换
System.out.println(Collections.max(list));//输出list中的最大键值对
System.out.println(Collections.min(list));
Collections.replaceAll(list,"b","bb");//使用新值替换list对象的所有旧值
List<Student> stu = new ArrayList<Student>();
Student s1 = new Student(14,"张三");
Student s2 = new Student(11,"等等");
Student s3 = new Student(12,"画画");
stu.add(s1);
stu.add(s2);
stu.add(s3);
Student ss = Collections.max(stu,new Student());
COllections.sort(stu,new Student());
}
}
class Student implements Comparetor<Student>{
private int age;
private String name;
public Student(){}
public Student(int age,String name){
this.age = age;
this.name = name;
}
@Override
public int compare(Student o1,Student 02){//正序排列
if(o1.age>o2.age) return 1;
else if(o1.age>o2.age) return -1;
else return 0;
}
}
//synchronizedXxxx()方法可解决线程安全问题,eg:synchronizedList()
7.泛型
public class Test{
public static void main(String[] args){
A<String> a1 = new A<String>();//在new A的对象指定泛型的类型String
a1.setKey("xxx");//对象使用setKey(T key)方法,中的key形参就是String
String s = a1.getKey();//T getKey(),返回值就有new对象确定返回值是String
B1<Object> b1 = new B1<Object>();
B1<String> b2 = new B1<String>();
B2 b3 = new B2();
Cc<Object> c = new Cc<Object>();
c.test("xxxx");
//泛型方法,在调用之前没有固定的数据类型
//在调用时,传入的参数是什么类型,就会把泛型改成什么类型
Integer i = c.test4(2);//传递的参数为Integer
Boolean b = c.test4(true);
}
}
/**
*此处的泛型T可以任意取名,A,B,D
*一般使用T,意为type
*/
class A<T>{
private T key;
public void setKey(T key){
this.key = key;
}
public T getKey(){
return this.key;
}
}
//--------------------------------------------------
interface IB<T>{
T test(T t);
}
/* 为传入泛型实参时,与泛型类的定义相同,在声明类时,需将泛型的声明一起加到类中*/
class B1<T> implements IB<T>{
@Override
public T test(T t){
return t;
}
}
/* 如果实现接口时指定接口的泛型的具体数据类型
*这个类实现接口所有方法的位置都要泛型替换实际的具体数据类型
*/
class B2 implements IB<String>{
@Override
public String test1(String s){
return s;
}
}
class Cc<E>{
private E e;
//静态方法的泛型方法
public static <T> void test2(T t){
//在静态方法中不能使用类定义泛型,只能使用静态方法自己定义的泛型
}
//无返回值的泛型方法
public <T> void test3(T s){
//在类上定义的泛型,可以在普通方法里使用
T t = s;
}
//有返回值的泛型方法
public <T> T test4(T s){
return s;
}
//形参为可变参数的泛型方法
public <T> void test5(T... strs){
for(T s:strs){
System.out.println(s);
}
}
}
8.有限制的通配符
public class Test{
public static void main(String[] args){
Dd d = new Dd();
List<String> ls = new ArrayList<String>();
d.test(ll);
List<C1> lc = new ArrayList<C1>();
d.test1(lc);
List<D1> ld = new ArrayList<D1>();
List<A1> la = new ArrayList<A1>();
d.test1(ld);
d.test2(lc);
d.test2(la);
}
}
class Dd{
public void test(List<?> list){}//test方法需要一个list集合参数,不确定list集合存储的类型
public void test1<List<? extends C1> list){}//list参数的元素数据类型是C1及其子类
public void test2<List<? super C1> list){}//list参数的元素数据类型是C1及其父类
public void test3(List<? extends IA> list){}//list参数的元素类型是IA的实现类
}
class A1{}
class B1 extends A1{}
class C1 extends B1{}
class D1 extends C1{}
interface IA{}
class IAImpl implements IA{}
9.实现接口的枚举类
public class Test{
public static void main(String[] args){
//Season.SPRING,这段执行就是获取一个Season的对象
Season spring = Season.SPRING;
spring.shouInfo();
Season summer = Season.SUMMER;
summer.showInfo();
Season spring 1= Season.SPRING;
//枚举类是单例模式=
System.out.println(spring.equals(spring1));//true
}
}
enum Season{
SPRING("春天","春暖花开");//此处相当于在调用有参的私有构造
SUMMER("夏天","炎炎夏日");
AUTUMN("秋天","秋高气爽");
WINTER("冬天","寒风刺骨");
private final String name;
private final String desc;
private Season(String name,String desc){
this.name = name;
this.desc = desc;
}
public void shouInfo(){
System.out.println(this.name+":"+this.desc);
}
}