1.集合框架的概念
集合:对象的容器,定义了多个对象进行操作的方法,类似数组的功能。可实现数组的功能。
与数组的区别:
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型。
位置:java.util.*
Collection体系集合:
- Collection是该体系结构的根接口,代表一组对象,称为集合。
- List接口的特点:有序(添加顺序和遍历顺序一致)、有下标(可以像数组一样来访问)、元素可重复。
- Set接口的特点:无序、无下标、元素不能重复。
- 泛型和工具类:泛型和工具类是jdk1.5之后的特性,参数化类型,将类型作为参数进行传递。
2.Collection接口:父接口(根接口)
特点:代表一组任意类型的对象,总体来讲是无序、无下标、不能重复的。但是由于List接口存在,部分是有序有下标和元素可重复的。
常用的方法由代码作为示例:
//Collection集合的使用
public class Test{
public static void main(String[] args) {
//创建集合;但是注意,由于Collection是接口,因此不能直接用new Collection创建,而需要到下层的类创建
Collection collection = new ArrayList();
//1.add:添加元素
collection.add("西瓜");
collection.add("草莓");
collection.add("芒果");
//输出元素个数和元素内容。注意元素个数不是length而是size。
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
//2.遍历集合
//2.1 增强for,由于Collection集合整体而言是无序的所以不可以使用普通的for循环
for (Object o : collection) {
System.out.println(o);
}
System.out.println("------迭代器------");
//2.2 使用迭代器Iterator
Iterator it = collection.iterator();
while (it.hasNext()){
//这里我们是以字符串的方式输出每个元素,但是输出结果是Object类,所以我们需要进行强转。
String s = (String) it.next();
System.out.println(s);
//由于迭代器中子带remove方法所以不可以直接使用colletion.remove来删除元素,直接通过Itrator对象调用remove方法即可
it.remove();
}
System.out.println("元素个数"+collection.size());//输出结果为“元素个数0”
//3.判断
//判断一个集合是否包含某个元素
System.out.println(collection.contains("西瓜"));
//判端一个集合是否为空
System.out.println(collection.isEmpty());
//4.删除元素与清空元素
//collection.remove("西瓜");
//collection.clear();
}
}
3.List接口与实现类
Collection的子接口,有序、有下标、元素可以重复,遍历可以使用普通for循环(因为有序,因此有下标)。
实现类:ArrayList、Linkedlist、Vector
List接口的使用
public class Test{
public static void main(String[] args) {
//创建集合对象
List list = new ArrayList();
//1.添加元素。
//由于集合的元素是引用类型,此处的数字其实是已经进行自动装箱的
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
System.out.println("元素个数:"+list.size());
System.out.println(list);
//2.删除操作
//2.1通过角标删除
list.remove(1);//2会被删除
//2.2通过元素删除
list.remove(new Integer(1));//数字1会被删除,若不是包装类则直接删除内容就可以不需要new。
System.out.println(list);
//3遍历元素
//3.1 for遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
//3.2 增强for遍历
for (Object o : list) {
System.out.println(o);
}
//3.3 迭代器Iterator
Iterator iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//3.4 列表迭代器
ListIterator lit = list.listIterator();
//从前往后
while (lit.hasNext()){
System.out.println(lit.nextIndex()+":"+lit.next());
}
//从后往前
while(lit.hasPrevious()){
System.out.println(lit.previousIndex()+":"+lit.previous());
}
//4.判断
System.out.println(list.contains(5));
System.out.println(list.isEmpty());
}
}
List实现类(1):Arraylist
Arraylist的使用和List基本一致,其存储结构为数组,查找和遍历速度较快,增删速度慢一些。添加元素、删除元素、遍历元素、与判断和List使用方式重合性较高,则代码主要演示其查找功能。
public class Test{
public static void main(String[] args) {
//创建集合
ArrayList arrayList = new ArrayList();
//创建学生类并创建对象,然后在集合中添加元素
Student s1 = new Student("张三",15);
Student s2 = new Student("赵四",18);
Student s3 = new Student("王五",20);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
//查找元素
System.out.println(arrayList.indexOf(s2));
//正常情况下这种方法是没办法得到和这个属性相同的元素的位置的,但是如果重写equals方法就可以。
System.out.println(arrayList.indexOf(new Student("张三",15)));
//重写后,删除也可以通过此方法进行删除
arrayList.remove(new Student("赵四",18));
System.out.println(arrayList);
}
}
注意:重写equals方法时候,由于重写此方法使用很频繁,所以可以通过快捷键直接在我们创建类中进行重写。在Idea中Alt+inset会有选择equals和hashcode方法重写,选择则会直接出来。然后在主方法中则可以使用上述方法进行查找或者删除了。另外,由于我们是的元素是学生类,当遍历时候,主要要将元素类型强转为Student类。
List实现类(2):Vector
jdk1.0版本提供,运行效率慢,线程安全,数组结构,查询快,增删慢。(现在使用的较少,但是面试可能会考)不多说,直接上代码。
public class Test{
public static void main(String[] args) {
//创建集合
Vector vector = new Vector();
//添加元素
vector.add("草莓");
vector.add("荔枝");
vector.add("西瓜");
System.out.println(vector);
//遍历。是List的实现类,因此是有序的依然可以使用for循环和增强for循环。
//但是Vector有独特的遍历方式:枚举器
Enumeration elements = vector.elements();
while (elements.hasMoreElements()){
Object o = elements.nextElement();//或者使用String强转成字符串类型输出字符串
System.out.println(o);
}
//判断和前面的方式一样,有contains、isEmpty
//其他方法
System.out.println(vector.firstElement());//输出第一个元素
System.out.println(vector.lastElement());//输出最后一个元素
System.out.println(vector.elementAt(2));//输出该坐标元素
}
}
List实现类(3):LInkedList
LinkedList的使用方法和List完全一样,所以此处不多赘述,特别示范一个获取方法。
System.out.println(LinkedList.indexOf(1))//indexOf可以获取输入坐标的元素
4.泛型
Java泛型是jdk1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
常见形式:泛型类、泛型接口、泛型方法。
语法:<T,…>T称为类型占位符,表示一种引用类型。
好处:
- 提高代码的重用性
- 防止类型转换异常,提高代码的安全性。
泛型类::泛型只能是引用类型,不同的泛型对象不能相互赋值。
格式:类型<泛型占位符,…>
public class Test {
public static void main(String[] args) {
//使用泛型类创建对象
//由于是实例化,占位符要使用引用类型代替。此处将类型定为字符串类型
MyGeneric<String> a = new MyGeneric<>();
//由于对象是字符串类型,所以泛型类需要传入的内容是字符串类型
//创建一个变量
a.t = "Hello";
//调用方法
a.show("大家好");
//调用方法,将t作为返回值并输出
String str = a.getT();
System.out.println(str);
}
}
class MyGeneric<T>{
//1.创建变量
T t;
//可以用于创建变量,但是不可以用于实例化,因为无法保证传过来泛型类的构造方法一定能用。
//2.泛型作为方法的参数
public void show(T t){
System.out.println(t);
}
//3.泛型作为方法的返回值
public T getT(){
return t;
}
}
泛型接口:不能使用泛型创建静态常量。使用方式有两种:1.实现接口是确定类型。2.使用泛型类实现接口,然后在实例化对象的时候在确定类型。
- 首先创建一个接口:
interface MyInterface<T>{
T server (T t);
//在没有使用T之前我们无法知道T是什么类型,因此不可以进行实例化
}
- 方法1:在实现类阶段将实现类传入:
//在实现类接口阶段把实现类型传入,此处传入String类型
public class Test implements MyInterface<String>{
@Override
public String server(String s) {
return s;
}
}
- 方法2:使用泛型类实现接口,等实例化对象的时候再确定类型
//使用泛型类实现接口,等实例化对象时再确定
public class Test01<T> implements MyInterface<T>{
@Override
public T server(T t) {
return t;
}
}
- 下面进行测试:
public class Demo {
public static void main(String[] args) {
//方法1:
Test impl1 = new Test();
impl1.server("Hello");
//方法2:
Test01<String> impl2 = new Test01<>();
impl2.server("Hi!");
}
}
泛型方法:不需要传递数据类型,数据类型会根据传递的数据改变。
//泛型方法:语法:<T>方法返回值类型。调用方法时传递其类型
public class Test {
public static void main(String[] args) {
Test test = new Test();
//T类型不需要自己传递,他会根据传递的数据自行决定
test.show("Hello");
test.show(1);
test.show(2.14);
}
//创建泛型方法
public<T> T show(T t){
System.out.println("泛型方法"+t);
//如果将T作为返回值类型,最后一定要加上返回值,如果返回值为void,后面这句返回值可以不加。
return t;
}
}
泛型集合:集合如果不使用泛型,则都是Object类型,那么我们在输出时,有时候就需要强转类型,就容易出错。
概念:参数化类型,类型安全的集合,强制集合元素的类型必须一致。
特点:1.编译时即可检查,而不是在运行时才抛出异常。
2.访问时,不必类型转换(拆箱)。
3.不同泛型之间引用不能相互赋值,泛型不存在多态。
import java.util.ArrayList;
//泛型集合
public class Fx {
public static void main(String[] args) {
//转换异常问题示范
//首先定义一个Object类型的集合
ArrayList<Object> arraylist1 = new ArrayList<>();
arraylist1.add("XXX");
arraylist1.add("10");
//当集合内,有字符串类型,也有基本类型时候,进行强转时候,就一定会有一部分无法转换成另一种类型。就会出现类型转换异常。
//此处遍历只能用Object类型遍历,否则就会报错。除非判断正确类型并进行强转才能避免。
for (Object o : arraylist1) {
System.out.println(o);
}
//而泛型将其类型确定后,就不再可以添加其他类型的元素了.遍历时也不再是Object类型了。
ArrayList<String> arraylist2 = new ArrayList<>();
arraylist2.add("xxx");
arraylist2.add("yyy");
for (String s : arraylist2) {
System.out.println(s);
}
//当然,我们也可以传输自己定义的类型,但是元素也只能添加该类型的元素。
//不同的类型不可以相互赋值,比如下面的例子,会报错
//arraylist1 = arraylist2;
}
}
5.Set接口与实现类
特点:无序、无下标、元素不可重复。
方法:全部继承Collection中的方法。
Set接口的使用
//Set接口的使用
public class Test {
public static void main(String[] args) {
//创建集合,由于Set是接口,所以需要使用其实现类创建新的对象
Set<String> set = new HashSet<String>();
//添加数据
set.add("苹果");
set.add("华为");
set.add("小米");
//由于其元素不可重复性,如果再次添加上述元素,则仍然只会输出三个元素。
set.add("小米");
System.out.println("数据个数:"+set.size());
System.out.println("元素:"+set.toString());
//删除数据。注:由于无序性,所以无法根据角标删除元素,只能根据元素值删除元素
//remove是删除元素,clear是清空元素,不再演示
//遍历:1、增强for。2、Iterator迭代器
//判断:1、contains():是否包含某元素。2、isEmpty():集合是否为空。
}
}
hashSet实现类
//存储结构:哈希表(数组+链表+红黑树)
//Set接口的使用,由于使用方法和Set使用基本一致,此处只做一些补充
public class Test {
public static void main(String[] args) {
//创建集合,由于Set是接口,所以需要使用其实现类创建新的对象
HashSet<Person> persons = new HashSet<Person>();
//添加数据
Person p1 = new Person("尼可乐",26);
Person p2 = new Person("里可",24);
Person p3 = new Person("尼可",22);
persons.add(p1);
persons.add(p2);
persons.add(p3);
//不可以重复添加同一对象,但是可以创建不同的对象,具有相同元素。
persons.add(new Person("尼可",22));
System.out.println(persons.size());//此处为4
//如果想要实现属性相同,则判定为同一对象,则可以在我们创建的类中重写hashCode和equals方法
//快捷键:alt+insert--->equals&hashCode
//重写后则遇到这种情况新添加的对象就不会被视为是新的元素了。
}
}
//注意要先创建一个类供此处练习,我是创建了一个Person的类进行的练习。
TreeSet实现类
//TreeSet的使用
//存储结构:红黑树
public class Demo05 {
public static void main(String[] args) {
//创建集合
TreeSet<String> treeSet = new TreeSet<>();
//1.添加元素
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("Hello");
System.out.println("元素数量:"+treeSet.size());
System.out.println(treeSet.toString());
//2.删除:remove。清空:clear
//3.1增强for遍历
//3.2迭代器Iterator遍历
//4.判断:contains。
}
}
补充:
//使用TreeSet保存数据
public class Demo06 {
public static void main(String[] args) {
TreeSet<Person> persons = new TreeSet<>();
Person p1 = new Person("尼可乐",26);
Person p2 = new Person("里可",24);
Person p3 = new Person("半引号",22);
persons.add(p1);
persons.add(p2);
persons.add(p3);
System.out.println("元素个数:"+persons.size());
System.out.println(persons.toString());
//不重写接口的方法会报错。
//由于红黑树无法比较,需要实现Camparable接口,此接口中只有一个方法。重写这个方法,给他设定比较规则,就可以进行正常运行了
//删除
//遍历1.增强for 2.迭代器
//判断
}
}
//此处是提前创建了Person类。
实现Comparable接口方法如下,此接口中只有一个方法:compareTo,重写此方法。
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.getAge() - o.age;
//先按照姓名比再按年龄比。
return n1 == 0 ? n2 : n1;
}
实现定制比较:
//TreeSet的使用
//Comparator接口:实现定制比较(比较器)
public class Demo07 {
public static void main(String[] args) {
TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge() - o2.getAge();
int n2 = o2.getName().compareTo(o2.getName());
return n1 == 0?n2:n1;
}
});
Person p1 = new Person("尼可乐",26);
Person p2 = new Person("里可",24);
Person p3 = new Person("半引号",22);
Person p4 = new Person("半引号",22);
persons.add(p1);
persons.add(p2);
persons.add(p3);
persons.add(p4);
System.out.println(persons.toString());
//此处输出只能输出三个元素
}
}
案例:
//案例:使用TreeSet集合实现字符串按照长度进行排序
//comparator实现定制比较
public class Demo08 {
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("Hellowolrd");
treeSet.add("chengdu");
treeSet.add("xian");
treeSet.add("shanghai");
treeSet.add("wuhan");
treeSet.add("hubei");
System.out.println(treeSet.toString());
}
}
6.Map接口与实现类
map接口特点:
- 用于存储任意键值对(key,value)
- 键:无序、无下标、不允许重复
- 值:无序、无下标、可以 重复
hashMap的使用
//Map接口的使用
//HashMap的使用1
public class Demo01 {
public static void main(String[] args) {
//创建Map集合
Map<String,String> map = new HashMap<>();
//1.添加元素
map.put("cn","中国");
map.put("us" ,"美国");
map.put("uk","英国");
//key不变但是value变了以后,value值会覆盖掉之前的value值。
map.put("us","美利坚合众国");
System.out.println("元素个数"+map.size());
System.out.println(map.toString());
//2.删除
map.remove("us" );
System.out.println("删除之后:"+map.size());
//3.遍历
//3.1使用keySet();返回值是所有key的set集合
//使用keySet方法返回set集合,然后再用增强for遍历keySet获取key的值,再用get(key)获得value值
Set<String> keyset = map.keySet();
for (String key : keyset) {
System.out.println(key+":"+map.get(key));
}
//3.2使用entrySet()方法,一个Entry就相当于一个键值对。
Set<Map.Entry<String,String>> entries = map.entrySet();
for (Map.Entry<String, String> entry : entries) {
System.out.println(entry.getKey()+"="+entry.getValue());
}
//4.判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("中国"));
}
}
//HashMap集合的使用
//存储结构:哈希表(数组加链表)
//使用key的hashcode和equals作为重复
public class Demo02 {
public static void main(String[] args) {
//创建集合
HashMap<Student,String> student = new HashMap<Student,String>();
//1.添加元素
Student s1 = new Student("ad",123);
Student s2 = new Student("ap",234);
Student s3 = new Student("tank",230);
student.put(s1,"下路");
student.put(s2,"中路");
student.put(s3,"上路");
//如果将元素的换掉值,输出结果值会覆盖。
student.put(s3,"打野");
//这样可以加进来,但是有时候会导致重复
//重写hashCode和equals则不会加进来了。
student.put(new Student("tank",230),"辅助");
System.out.println("元素个数:"+student.size());
System.out.println(student.toString());
//2.删除:remove()
//3.遍历
//3.1使用keyset
for (Student key : student.keySet()) {
System.out.println(key+":"+student.get(key));
}
//3.2使用entrySet()
for (Map.Entry<Student, String> entry : student.entrySet()) {
System.out.println(entry.getKey()+"="+entry.getValue());
}
//4.判断:contains()
//此时在判断中添加新的元素则会判断存在,因为重写了hashCode和equals方法。
}
}
//此处提前创建了Student类
TreeMap的使用
public class Demo03 {
public static void main(String[] args) {
//新建集合
//定制比较器。
TreeMap<Student,String> treeMap = new TreeMap<Student,String>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return 0;
}
});
//1.添加元素
Student s1 = new Student("ad",123);
Student s2 = new Student("ap",234);
Student s3 = new Student("tank",230);
//treeMap结构是红黑树,不可以直接进行添加元素。
treeMap.put(s1,"下路");
treeMap.put(s2,"中路");
treeMap.put(s3,"上路");
System.out.println("元素个数:"+treeMap.size());
System.out.println(treeMap.toString());
//2.删除remove
//3.遍历
//3.1 使用keySet
for (Student key : treeMap.keySet()) {
System.out.println(key+":"+treeMap.get(key));
}
//3.使用2entrySet()
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey()+":"+entry.getValue());
}
//4.判断contains
//5.定制比较
}
}
7.Collection工具类
//工具类的使用
public class ToolsClass {
public static void main(String[] args) {
//创建集合
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(5);
list.add(7);
list.add(9);
list.add(1);
//sort排序
System.out.println("排序之前:"+list.toString());
Collections.sort(list);
System.out.println("排序之后:"+list.toString());
//binarySearch二分查找
int i = Collections.binarySearch(list, 12);
System.out.println(i);//找不到则会输出负数
//copy复制
List<Integer> dest = new ArrayList<>();
//由于copy方法要求两个集合容量要相等,所以需要做一个循环操作,使目标集合大小和原始集合容量相等
for (int j = 0; j < list.size(); j++) {
dest.add(0);
}
Collections.copy(dest,list);
System.out.println(dest.toString());
//reverse反转
Collections.reverse(list);
System.out.println("反转之后:"+list);
//shuffle 打乱
Collections.shuffle(list);
System.out.println("打乱之后:"+list);
//补充1:list转成数组
Integer[] arr = list.toArray(new Integer[7]);
//此处给的长度如果小于list长度,那么输出的长度和list相同,如果大于的话,则和给的长度相同
System.out.println(arr.length);
System.out.println(Arrays.toString(arr));
//补充2:将数组转成集合
String[] names = {"张三","王五","赵四"};
//此集合为受限集合,不能删除或添加。
List<String> list1 = Arrays.asList(names);
System.out.println(list1);
int[] nums = {01,20,30,40,50};
//<>中如果是int[]那么数组中就不再是数字了,而是一个数据,一个数组
List<int[]> list2 = Arrays.asList(nums);
//所以基本类型转成数组时候不能使用int,而需要修改为包装类。
Integer[] nums1 = {01,20,30,40,50};
List<Integer> list3 = Arrays.asList(nums1);
System.out.println(list3);
}
}
8.总结
集合的概念:对象的容器,和数组类似,定义了多个对象进行操作的常用方法。
List集合:有序、有下标、元素可重复。(常用实现类:ArrayList、LinkedList、Vector)
Set集合:无序、无下标、元素不可重复(HashSet、TreeSet)
Map集合:存储一对数据,无序、无下标,键不可重复,值可重复。(HashMap、HashTable、TreeMap)
Collections:集合工具类,定义了除了存取以外的集合常用方法。