Java集合概述
Java集合类存放于java.util包中,是一个用来存放对象的容器。
- 集合只能存放对象。比如你存一个int数据0放入集合中,其实它是自动转换成Integer类后存入的,java中每一种基本类型都有对应的引用类型(包装类)。
- 集合存放的是多个对象的引用,对象本身还是放在堆内存中。
- 集合可以存放不同类型,不限数量的数据类型。
Java集合可分为Set、List、Map三大体系
Set:无序、不可重复的集合
List:有序、可重复的集合
Map:具有映射关系的集合
在JDK5之后,增加了泛型,Java集合可以记住容器中对象的数据类型
HashSet
HashSet是Set接口的典型实现,大多数时候使用Set集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet
HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet具有以下特点:
不能保证元素的排列顺序
不可重复
HashSet不是线程安全(学线程时再说)的
集合元素可以使用null
当向HashSet集合中存入一个元素时HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值决定该对象在HashSet中的存储位置。
如果两个元素的equals()方法返回true,但它们的hashCode()返回值不相等,HashSet将会把它们存储在不同的位置,但依然可以添加成功。
HashSet类→(实现)Set接口(继承)→Collection接口(集合接口)
import java.util.HashSet;
import java.util.Set;
public class Test{
public static void main(String [] args){
Set set = new HashSet();
//Set<Object> set = new HashSet<Object>();//与上面的等价
set.add(0);
set.add(1);
set.add(“a”);
System.out.println(set);
set.remove(1);
System.out.println(set);
//判断Set中是否存在“a”这个值(判断是否包含元素)
System.out.println(set.contains(“a”));
System.out.println(set.contains(1));
//清空集合
set.clear();
System.out.println(set);
set.add(“a”);
set.add(“b”);
set.add(“c”);
set.add(“c”);//Set集合存的值是不重复的
set.add(1);
set.add(true);
set.add(null);
System.out.println(set);
//使用迭代器遍历集合
Iterator it = set.iterator();
while(it.hashNext()){
System.out.println(it.next());
}
//for each迭代集合,推荐使用这种
for(Object obj : set){//定义一个Object类的引用变量obj,把set的每一个值取出来赋值给obj,直到循环set的所有值
System.out.println(obj);
}
System.out.println(set.size());//获取集合的元素个数
//如果想要让集合只能存同样类型的对象,怎么做?
//使用泛型
Set<String> set1 = new HashSet<String>();//比如指定String为集合的泛型,那么这个集合就不能存String类型之外的数据
set1.add(“abc”);
//set1.add(1);//现在不能存整数类型了,当然了,非String类型的都不能存储了呦
}
}
使用Iterator接口遍历集合元素
Iterator接口主要用于遍历Collection集合中的元素,Iterator对象也被称为迭代器
Iterator接口隐藏了各种Collection实现类的底层细节,向应用程序提供了遍历Collection集合元素的统一编程接口
Iterator仅用于遍历集合,Iterator本身并不提供承转承载对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。
使用foreach循环遍历集合元素
Java5提供了foreach循环迭代访问Collection
for(Person person : persons){
System.out.println(person.getName());
}
hashCode()方法
HashSet集合判断两个元素相等的标准;两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。
如果两个对象通过equals()方法返回true,这两个对象的hashCode值也应该相同。
TreeSet
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet采用自然排序。
TreeSet类→(实现)NavigableSet接口(继承)→SortedSet接口(继承)→Set接口(继承)→Collection接口
import java.util.Set;
import java.util.TreeSet;
import java.util.Comparator;
public class Test2{
public static void main(String [] args){
Set<Integer>set = new TreeSet<Integer>();
//TreeSet自然排序
set.add(0);
set.add(1);
set.add(2);
System.out.println(set);
set.remove(0);
set.contains(1);
// set.clear();//清空集合
//使用迭代器遍历集合
Iterator<Integer> it = set.iterator();
while(it.hashNext()){
System.out.println(it.next());
}
//for each迭代集合,推荐使用这种
for(Integet i : set){
System.out.println(i);
}
Person p1 =new Person(“张三”,30);
Person p2 =new Person(“李四”,25);
Person p3 =new Person(“王五”,33);
Person p4 =new Person(“Lucy”,26);
Set<Person> set1 = new TreeSet<Person>(new Person());
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
for(Person p : set1){
System.out.println(p.name+” ”+p.age);
}
}
}
class Person implements Comparator< Person>{//把Person对象存到TreeSet中并且按照年龄排序
int age;
String name;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
@Override
public int compare(Person o1,Person o2){//年龄正序排列
if(o1.age>o2.age){
return 1;
}else if(o1.age<o2.age){
return -1;
}else{
return 0;
}
}
//@Override
//public int compare(Person o1,Person o2){//年龄倒序排列
// if(o1.age<o2.age){
// return 1;
//}else if(o1.age>o2.age){
// return -1;
//}else{
// return 0;
//}
//}
}
自然排序
排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列
如果this>obj,返回正数1
如果this<obj,返回负数-1
如果this=obj,返回0,则认为这两个对象相等
必须放入同样类型的对象(默认会进行排序),否则可能会发生类型转换异常,我们可以使用泛型来进行限制
定制排序
如果需要实现定制排序,则需要在创建TreeSet集合时,提供一个Comparator接口的实现类对象。由该Comparator对象负责集合元素的排序逻辑
List与ArrayList
List代表一个元素有序且可重复的集合,集合中的每个元素都有其对应的顺序索引
List允许使用重复元素,可以通过索引来访问指定位置的集合元素。
List默认按元素的添加顺序设置元素的索引。
List集合例添加了一些根据索引来操作集合元素的方法
ArrayList类→(实现)List接口(继承)→Collection接口
import java.util.List;
import java.util.ArrayList;
public class Test3{
public static void main(String [] args){
list<String> list = new ArrayList<String>();
list.add(“a”);//第一个,索引下标0
list.add(“c”);//索引下标1
list.add(“b”);//索引下标2
list.add(“b”);//允许使用重复元素,索引下标3
System.out.println(list);
System.out.println(list.get(2));// 通过索引来访问指定位置的集合元素
list.add(1,”f”);//在指定索引下标的位置插入数据
System.out.println(list);
list<String> list2 = new ArrayList<String>();
list2.add(“123”);
list2.add(“456”);
list.addAll(2,list2); //在指定索引下标的位置插入集合
System.out.println(list);
System.out.println(list.indexOf(“d”));//获取指定元素在集合中第一次出现的索引下标
System.out.println(list.lastindexOf(“d”));//获取指定元素在集合中最后一次出现的索引下标
list.remove(2);//根据指定的索引下标移除数据
System.out.println(list);
list.set(1,”ff”);//根据指定的下标修改元素
System.out.println(list);
//根据索引下标的起始位置截取一段元素形成一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
List<String>subList1 = list.subList(2,4);// 取索引下标大于等于2小于4的元素
System.out.println(subList1);
System.out.println(list.size());//集合的长度
}
}
ArrayList和Vector(古老的集合,以前的版本)
ArrayList和Vector是List接口的两个典型实现
区别:
Vector是一个古老的集合,通常建议使用ArrayList
ArrayList是线程不安全的,而Vector是线程安全的(写到线程时再说)
即使为保证List集合线程安全卷,也不推荐使用Vector
Map
Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的Key,另外一组用于保存Map里的Value
Map中的Key和value都可以是任何引用类型的数据
Map中的Key不允许重复,即同一个Map对象的任何两个Key通过equals方法比较中返回false
Key和Value之间存在单向一对一关系,即通过指定的Key总能找到唯一的,确定的Value
import java.util.Map;
import java.util.HashMap;
impor java.util.Set;
public class Test4{
public static void main(String [] args){
Map<String,Integer> map = new HashMap<String , Integer>();
map.put(“a”,1);//添加数据
map.put(“b”,2);
map.put(“c”,2);
System.out.println(map);
System.out.println(map.get(“b”));//根据key取值
map.remove(“c”);//根据key移除键值对
System.out.println(map);
System.out.println(map.size());//Map集合的长度
System.out.println(map.containsKey(“a”));//判断当前的Map集合是否包含指定的key
System.out.println(map.containsValue(10)); //判断当前的Map集合是否包含指定的value
//map.clear();//清空集合
Set<String> keys = map.KeySet();//获取Map集合的Key的集合
map.values();//获取集合的所有Value值
//遍历Map集合
for(String key : keys){
System.out.println(“key:”+key+”,value:”+map.get(key));
}
//通过map.entrySet();遍历Map集合
Set<Entry<String,Integer>> entrys = map.entrySet();
for(Entry<String,Integer> en : entry){
System.out.println(“key:”+en.getKey()+”,value:”+en.getMap());
}
//TreeMap的自然排序是字典排序
Map<Integer,String> map1 = new TreeMap<Integer,String>();
map.put(1,”a”);
map.put(4,”d”);
map.put(3,”c”);
map.put(2,”b”);
System.out.println(map1);
Map<String,String> map2 = new TreeMap<String,String>();
map2.put(“b”,”b”);
map2.put(“c”,”c”);
map2.put(“d”,”d”);
map2.put(“a”,”ab”);
map2.put(“1”,”ab”);
map2.put(“10”,”ab”);
System.out.println(map2);
}
}
HashMap&Hashtable
HashMap和Hashtable是Map接口的两个典型实现类
区别:
Hashtable是一个古老的Map实现类,不建议使用
Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的(线程安全以后再说)
Hashtable不允许使用null作为key和value,而HashMap可以
与HashSet集合不能保证元素的顺序一样,Hashtable、HashMap也不能保证其中key-valueK对的顺序
Hashtable、HashMap判断两个Key相等的标准是:两个Key通过equals方法返回true,hashCode值也相等。
Hashtable、HashMap判断两个Value相等的标准是:两个Value通过equals方法方法返回true,hashCode值也相等。
TreeMap
TreeMap存储Key-Value对时,需要根据Key对Key-Value对进行排序。TreeMap可以保证所有的Key-Value对处于有序状态。
TreeMap的Key的排序:
自然排序:TreeMap的所有Key必须实现Comparable接口,而且所有的Key应该是同一个类的对象,否则会抛出ClassCastException
定制排序(了解):创建TreeMap时,传入一个Comparator对象,该对象负责对TreeMap
中的所有Key进行排序。此时不需要Map的Key实现Comparable接口
操作集合的工具类:Collections
Collections是一个操作Set、List和Map等集合的工具类
Collections中提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
排序操作:
reverse(List):反转List中元素的顺序
shullfe(List):对List集合元素进行随机排序
sort(List):根据元素的自然顺序对指定Lsit集合元素按升序排序
sort(List,Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
swap(List,int,int):将指定List集合中的i元素和j元素进行交换
查找、替换
Object max(Collection):根据元素的自然排序,返回给定集合中的最大元素
Object max(Collection,Comparator):根据Comparator指定的顺序,返回给定集合中的最大元素
Object min(Collection)
Object min(Collection,Comparator)
int frequency(Collection,Comparator):返回指定集合中指定元素的出现次数
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换List对象的所有旧值
同步控制(到多线程再说)
Collections类中提供了多个synchronizedXxx()方法(例:synchronizedList(List<T> list)),该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class Test5{
public static void main(String [] args){
list<String> list = new ArrayList<String>();
list.add(“a”);
list.add(“b”);
list.add(“d”);
list.add(“c”);
list.add(“1”);
list.add(1);
list.add(“a”);
System.out.println(list);
Collections.reverse(list);//反转List中元素的顺序
System.out.println(list);
Collections.shullfe(list);//对List集合元素随机排序
System.out.println(list);
Collections.sort(list);//List集合字典升序排序
System.out.println(list);
System.out.println(Collections.frequency(list,”a”));//返回指定集合中元素的出现次数
System.out.println(Collections.frequency(list,”x”));//不存在的元素,返回值为0
Collections.replaceAll(list,”a”,”ka”);//使用新值替换List对象的所有旧值
System.out.println(list);
Collections.swap(list,0,4);//将指定List集合中的i与j处元素进行交换
System.out.println(list);
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
Student s1 = new Student(20,“小明”);
Student s2 = new Student(18,“小红”);
Student s3 = new Student(19,“小王”);
Student s4 = new Student(21,“Lucy”);
List<Student> students = new ArrayList<Student>();
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);
Student s = Collections.max(students,new Student());
System.out.println(s.name+”,”+s.age);
Student ss = Collections.min(students,new Student());
System.out.println(ss.name+”,”+ss.age);
for(Student student : students){
System.out.println(student.name+“,”+student.age);
}
Collections.sort(students , new Student());
System.out.println(“------------------------------”);
for(Student student : students){
System.out.println(student.name+“,”+student.age);
}
}
}
class Student implements Comparator<Student>{
int age;
String name;
public Student(){}
public Student(int age,String name){
this.age = age;
this.name = name;
}
@Override
public int compare(Student o1, Student o2){ //根据年龄升序排序对象
if(o1.age>o2.age){
return 1;
}else if(o1.age<o2.age){
return -1;
}else{
Return 0 ;
}
}
}