集合
集合概述
-
集合类存放于java.util包中,是一个用来存放对象的容器
- 集合只能存放对象
- 几个存放的是多个对象的引用,对象本身还是放在堆内存中。
- 集合可以存放不同类型,不限数量的数据类型
-
Java集合可以分为Set、List、Map三种体系
- Set:无序、不可重复的集合
- List:有序,可重复的集合
- Map:无序,具有映射关系的集合
Set
1. HashSet
1. HashSet是Set接口的典型实现,大多数时候使用Set集合时都是用这个实现类。我们大多数时候说的set集合指的都是HashSet
2. HashSet按Hash算法来存储集合中的元素,因此具有很好的存取和查找性能。
-
特点:
- 不能保证元素的排列顺序(所以是无序的)
- 不可重复
- Hash不是线程安全的
- 集合元素可以是null
-
HashSet集合判断两个元素相等的标准:两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法返回值也相等。
如果两个对象通过equals()方法返回true,这两个对象的hashCode值也应该相同
-
泛型:
- 如果想要集合只能存同样类型的对象,只需要给集合加上泛型即可
package HashSetDemo;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test1 {
public static void main(String[] args){
Set set=new HashSet();
//set.add(1);
//set.add("a");
//System.out.println(set);
//set.remove(1);//移除元素1
//System.out.println(set);
//System.out.println(set.contains(1));//判断是否包含元素
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("d");//不能被存进去,证明不可重复
set.add(null);
System.out.println(set);
Iterator it=set.iterator();
//使用迭代器遍历集合
while (it.hasNext()){
System.out.println(it.next());
}
//使用foreach迭代集合
for(Object obj:set){//把set的每一个值,取出来,赋值给obj,知道循环set的所有值
System.out.println(obj);
}
System.out.println(set.size());//获取集合的元素个数
}
}
2. TreeSet
TreeSet是SortSet接口的实现类,TreeSet可以保证集合元素处于排序状态。
TreeSet支持两种排序的方法:自然排序(默认的)和定制排序
1. 自然排序:
2. 定制排序:如果需要实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator接口的实现类对象。由该Comparator对象负责集合元素的排序逻辑
package TreeSetDemo;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class Test2 {
public static void main(String[] args){
// Person p1=new Person();
//Set<Person> set=new TreeSet<Person>(p1);//创建对象时,传递一个针对性的比较器进去。
Set<Person> set=new TreeSet<Person>(new Person());
set.add(new Person("张一",14));
set.add(new Person("张二",15));
set.add(new Person("张三",25));
set.add(new Person("张四",6));
for(Person p:set){//把set的每一个值,取出来,赋值给obj,知道循环set的所有值
System.out.println(p.name+"..."+p.age);
}
}
}
class Person implements Comparator<Person>{
String name;
int age;
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;
}
}
}
TreeSet必须保证放入同样类的对象(默认会进行排序),否者可能会发生类型转换异常,我们可以使用泛型来进行限制。
List
List代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
List允许使用重复元素,可以通过索引来访问指定位置的集合元素。
List默认按元素的添加顺序设置元素的索引。
List集合里添加了一些根据索引来操作集合元素的方法。
ArrayList和Vector
区别:
- Vector是一个古老的集合,通常建议使用ArrayList
- ArrayList是线程不安全的,而Vector是线程安全的
- 即使为保证List集合线程安全,也不推荐使用Vector
package ListDemo;
import java.util.ArrayList;
import java.util.List;
public class Test1 {
public static void main(String[] args){
List<String> list=new ArrayList<>();
list.add("b");//第一个,索引下标为0
list.add("c");//索引下标为1
list.add("a");//索引下标为2
list.add("a");//索引下标为3,允许使用重复元素
System.out.println(list);
System.out.println(list.get(2));//可以通过索引来访问指定位置的集合元素
list.add(1,"f");//在指定索引的位置下标插入元素
System.out.println(list);
//在指定索引的位置下标插入集合
List<String> list1=new ArrayList<>();
list1.add("123");
list1.add("456");
list.addAll(2,list1);//在指定索引的位置下标插入集合
System.out.println(list);
System.out.println(list.indexOf("a"));//获取指定元素在集合中第一次出现的所引下标
System.out.println(list.lastIndexOf("a"));//获取指定元素在集合中最后一次出现的所引下标
list.remove("123");//根据指定元素移除元素
System.out.println(list);
list.remove(2);//根据指定的索引下标移除元素
System.out.println(list);
list.set(1,"ff");//根据指定索引下标修改元素
System.out.println(list);
//根据索引下标的起始位置来截取一段元素形成一个新的集合,截取的时候,包含开始的索引,不包含结束时的索引
List<String> list2 = list.subList(2, 5);//取索引下标在大于等于2小于4的元素(左闭右开)
System.out.println(list2);
System.out.println(list.size());//集合的长度
}
}
linkList
对于频繁的插入、删除操作,使用此类效率会比ArrayList高;底层使用双链表存储
Map
Map用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的Key,另外一组用于保存Map里的Value
Map中的key和value都可以是任何引用类型的数据
Map中的key不允许重复,即同一个Map对象的任何两个Key通过equals方法比较中返回false
key和value之间存在单向一对关系,即通过指定的key总能找到唯一的,确定value
package MapDemo;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test1 {
public static void main(String[] args){
Map<String,Integer> map=new HashMap<String,Integer>();
map.put("b",1);//添加数据
map.put("c",2);
map.put("d",3);
System.out.println(map);
System.out.println(map.get("b"));//根据key取值
map.remove("b");
System.out.println(map);//根据key来移除value
System.out.println(map.size());//map集合的长度
System.out.println(map.containsKey("a"));//判断当前集合是否包含指定的key
System.out.println(map.containsValue(1));//判断当前集合是否包含指定的value
//map.clear();清空集合
Set<String> keys = map.keySet();//获取map集合的key的集合
map.values();//获取集合的所有value值
//遍历map集合,通过map.keySet();
for (String key:keys){
System.out.println("key:"+key+", value:"+map.get(key));
}
System.out.println("*********************************");
//通过map.entrySet()
Set<Map.Entry<String, Integer>> entries = map.entrySet();
for (Map.Entry<String,Integer> entry:entries) {
System.out.println("key:"+entry.getKey()+", value:"+entry.getValue());
}
}
}
HashMap和Hashtable
区别:
1. Hashtable是一个古老的Map实现类,不建议使用
2. Hashtable是一个线程安全的实现,但是hashMap是线程不安全的
3. Hashtable不允许使用null作为key和value,而HashMap可以
与HashSet集合不能保证元素的顺序一样,Hashtable、HashMap也不能保证其中key和value对的顺序
Hashtable、HashMap判断两个key相等的标准是:两个key通过equals方法返回true,hashCode值也相等
Hashtable、HashMap相等的判断标准是:两个Value通过equalHashMap判断两个Values方法返回true
TreeMap
TreeMap存储键值对时,需要根据key对键值对进行排序。TreeMap可以保证所有的键值对处于有序状态。
TreeMap的key的排序:
1. 自然排序:TreeMap的所有的可以、必须实现Comparable接口,而且所有的key用改是同一个类的对象,否则将会抛出ClassCastException。
2. 定制排序(了解):创建TreeMap时,传入一个Comparator对象,该对象负责TreeMap中的所有key进行排序。此时不需要map的key实现Comparable接口
package MapDemo;
import java.util.Map;
import java.util.TreeMap;
//TreeMap
public class Test2 {
public static void main(String[] args){
//TreeMap的自然排序是字典排序
Map<Integer,String> map=new TreeMap<Integer,String>();
map.put(4,"a");
map.put(2,"a");
map.put(3,"a");
map.put(1,"a");
System.out.println(map);
Map<String,String> map1=new TreeMap<String,String>();
map1.put("d","b");
map1.put("a","b");
map1.put("q","d");
map1.put("c","a");
map1.put("1","10");
System.out.println(map1);
}
}
Collections
Collections是一个操作Set、List 和Map等集合的工具类
Collections中提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
排序操作:
- reverse(List): 反转List元素的顺序
- shuffle(List): 对List集合元素进行随机排序
- sort(List): 根据元素的自然顺序对指定List集合元素按升序排
- sort(List, Comparator): 根据指定的Comparator产生的顺序对List集合元愫进行排序
- swap(List, int, int): 将指定list集合中的i处元素和j处元素进行交换
package CollectionsDemo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test1 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("a");
list.add("bc");
list.add("cae");
list.add("asd");
list.add("fra");
list.add("a");
list.add("a");
System.out.println(list);
Collections.reverse(list);//反转list集合元素的顺序
System.out.println(list);
Collections.shuffle(list);//对集合元素进行随机排序
System.out.println(list);
Collections.sort(list);//对集合元素进行字典升序排序
System.out.println(list);
//Collections.swap(list,0,4);//对集合内,指定下标位置交换
//.out.println(list);
System.out.println(Collections.max(list));//返回集合中最大的值
System.out.println(Collections.min(list));//返回集合中最小的值
System.out.println(Collections.frequency(list, "a"));//返回指定集合指定元素的出现次数
Collections.replaceAll(list,"a","aa");//使用新值替换掉集合中所有的旧值
System.out.println(list);
}
}
package ListDemo;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test2 {
public static void main(String[] args){
List<Student> list=new ArrayList<Student>();
list.add(new Student(14,"王五"));
list.add(new Student(18,"赵六"));
list.add(new Student(10,"李四"));
list.add(new Student(20,"张三"));
Student student = Collections.max(list, new Student());
System.out.println(student.name+","+student.age);
Student student1 = Collections.min(list, new Student());
System.out.println(student1.name+","+student1.age);
// for (Student student:list){
// System.out.println(student.name+","+student.age);
// }
// System.out.println("*************************");
// Collections.sort(list,new Student());
// for (Student student:list){
// 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;
}
}
}
泛型
泛型:解决数据类型的安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是具体的某个方法的返回值及参数类型。这样在类声明或实例化时只要指定好需要的具体的类型即可。
Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会发生ClassCastException异常。同时,代码更简洁、健壮。
==Java中的泛型,只在编译阶段有效。==泛型信息不会进入到运行时阶段。
泛型的使用:
1. 泛型类
2. 泛型方法
3. 泛型接口
泛型类
- 对象实例化不指定泛型,默认为:Object。
- 泛型不同的引用不能互相赋值。
package 泛型Demo;
public class Test1 {
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
A<Integer> a2=new A<Integer>();
a2.setKey(11);
Integer i = a2.getKey();
A a3=new A();//不指定泛型相当于指定了一个Object类型
//A<Object> a4=new A<Object>();
a3.setKey(new Object());
Object o = a3.getKey();
//同样的类,但是在new对象的时候泛型指定不同的数据类型,这些对象不能相互赋值
}
}
//此处的泛型T可以任意取名 A,B,C,V
//一般使用T,T为type类型
class A<T>{
private T key;
public void setKey(T key) {
this.key = key;
}
public T getKey() {
return key;
}
}
泛型接口
package 泛型接口;
public class Test1 {
public static void main(String[] args){
B1<String> b1=new B1<String>();
B1<Object> b2=new B1<Object>();
B2 b3=new B2();//不用指定泛型的数据类型
}
}
interface IB<T>{
T test(T t);
}
/**
* 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需要将泛型的声明也一起加到类中
* @param <T>
*/
class B1<T> implements IB<T>{
@Override
public T test(T t) {
return t;
}
}
/**
* 如果实现接口时指定接口的泛型的具体数据类型
* 这个类实现接口的所有方法的位置都要替换实际的具体数据类型
*/
class B2 implements IB<String>{
@Override
public String test(String s) {
return null;
}
}
泛型方法
方法也可以被泛型化,不管此时定义在其中的类是不是泛型的。在泛型方法中可以定义泛型参数,此时,参数的类型就是传入的类型
格式:
public class Dao{
public <E> void show(E e){
System.out.println(e.toString());
}
public <T>T show1(T t){
return t;
}
}
package 泛型方法;
public class Test1 {
public static void main(String[] args){
CC<Object> cc=new CC<Object>();
cc.test(1);
//泛型方法,在调用之前 没有固定的数据类型
//在调用时,传入的参数是什么类型。就会把泛型改成什么类型
//也就是说,泛型方法会在调用时确定泛型具体数据类型
cc.test1(2);//传递的参数是Integer,泛型固定为Integer,返回值就是Integer
cc.test1(true);//传递的参数是Boolean,泛型固定为Boolean,返回值就是Boolean
}
}
class CC<E>{
private E e;
public static <T> void test3(T t){
//在静态方法中,不能使用类定义泛型,如果 要使用泛型,只能使用静态方法自己定义泛型
// System.out.println(this.e);
System.out.println(t);
}
//有返回值的泛型方法
public <T>T test(T t){
return t;
}
//无返回值的泛型方法
public <T>void test1(T t){
T s=t;
}//有返回值的可变参的泛型方法
public <T>void test2(T... t){
for(T t1:t){
System.out.println(t1);
}
}
}