目录
????????在Java中,集合是一种用来存储和操作一组对象的容器。它提供了各种实现类和接口,可以根据需求选择合适的集合类型。常见的集合类型有List、Set和Map。List是一个有序的集合,可以包含重复的元素;Set是一个不允许重复元素的集合;Map是一种键值对的集合,每个键值对都是一个Entry对象,键是唯一的。集合框架提供了丰富的方法和功能,可以方便地对集合进行增删改查等操作。?
集合和数组是Java中两种不同的数据结构,它们的差异主要体现在以下几个方面:
数据类型:数组是一种固定长度的数据结构,它可以包含相同类型的元素。集合是一种可变长度的数据结构,可以包含不同类型的元素。
大小调整:数组的长度在创建时就被确定,无法动态改变。如果需要增加或删除元素,需要创建一个新的数组。集合的大小是可以动态调整的,可以根据需要添加或删除元素。
类型安全:数组可以包含任何类型的元素,包括基本数据类型和自定义类型。集合在泛型的支持下,可以确保只添加特定类型的元素,提供了类型安全的机制。
迭代和搜索:对于数组,可以通过下标来访问和修改元素,也可以使用循环遍历数组中的元素。集合提供了更多的迭代和搜索方法,例如迭代器和foreach循环。
功能:集合提供了很多便捷的方法和功能,例如排序、查找、去重等。数组相对较为简单,只提供了基本的访问和修改功能。
总的来说,数组在空间上更加高效,因为它们不需要额外的对象来维护元素的添加和删除。但集合在使用上更加灵活,提供了更多的功能和方便的操作方法。根据实际需求,选择使用数组还是集合是根据具体情况来决定的。
????????java.util.Collection:单列集合的根接口,用于存储一系列符合某种规则的元素,里边定义了所有单列集合共性的方法,任意单列集合都可以使用其中的方法,且继承自java.util包中的Iterable接口,因此它的实现类可以通过迭代器进行遍历。它有List和Set两个重要的子接口。
Collection的常用方法,它的所有实现类都可以使用。
修改集合:
????????boolean add(E e):向集合中添加元素,一般返回true。
????????boolean remove(E e):删除集合中的某个元素,存在元素(就删除元素,返回true),不存在元素(删除失败,返回false)。
????????void clear():清空集合中所有的元素,但是不删除集合,集合还在。
????????
获取集合:
????????int size():获取集合的长度,返回集合中元素的个数。
????????Object[] toArray():将集合转成一个数组,可以通过索引获取数组元素。
????????
判断集合:
????????boolean contains(E e):判断集合中是否包含某个元素,包含返回true,不包含返回false。
????????boolean isEmpty():判断集合是否为空,集合为空返回true,集合不为空返回false。
package com.zhy.coll;
import java.util.ArrayList;
import java.util.Collection;
public class CollectTest {
public static void main(String[] args) {
//Collection是一个接口,使用多态创建具体的实现类对象,
//Collection<String>是采用泛型写法,表示该集合只能存储String类型的元素,如果省略,表示可以存储Object类型的元素
Collection coll = new ArrayList();
//1.add(E e):向集合中添加元素
coll.add("张三");
coll.add(123);
coll.add(true);
System.out.println("初始化集合:" + coll);
//2.remove(E e):删除集合中的某个元素
coll.remove(true);
System.out.println("移除值为true的元素:" + coll);
//3.size():获取集合的长度
int length = coll.size();
System.out.println("集合的长度:" + length);
//4.toArray():将集合转成一个数组,遍历数组,可以通过索引获取数组元素
Object[] obj = coll.toArray();
System.out.print("遍历数组元素:");
for(int i = 0; i < obj.length; i++) {
System.out.print(obj[i] + " ");
}
//5.contains(E e):判断集合中是否包含某个元素
boolean flag = coll.contains(123);
System.out.println("\n集合中是否包含元素123:" + flag);
//6.isEmpty():判断集合是否为空
boolean isNull = coll.isEmpty();
System.out.println("清空集合前,集合是否为空:" + isNull);
//7.clear():清空集合中所有的元素
coll.clear();
System.out.println("清空集合中所有的元素:" + coll);
System.out.println("清空集合后,集合是否为空:" + coll.isEmpty());
}
}
?????????java.util.Iterator:即Collection集合元素的通用遍历方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来;继续再判断,如果还有就再取出来,一直把集合中的所有元素取出,这种取出方式专业术语称为迭代。
boolean hasNext():判断集合中还有没有下一个元素,有就返回true,没有就返回false。
E next():返回迭代器的下一个元素,取出集合中的下一个元素。
????????Iterator迭代器是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊,Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象Iterator<E> iterator():返回在此collection的元素上进行迭代的迭代器。步骤如下:
package com.zhy.coll;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectTest {
public static void main(String[] args) {
//1.创建集合对象
Collection coll = new ArrayList();
//2.将集合中添加元素
coll.add("张三");
coll.add(123);
coll.add(true);
System.out.println("初始化集合:" + coll);
//3.获取迭代器实现类,多态写法
Iterator iterator = coll.iterator();
//4.使用迭代器遍历集合元素
System.out.print("使用迭代器遍历集合:");
while (iterator.hasNext()) {
//取出集合的下一个元素,如果集合为空,会抛出异常NoSuchElementException(没有元素异常)
//所以要和iterator.hasNext()组合使用,先判断,在取值。
Object obj = iterator.next();
System.out.print(obj + " ");
}
}
}
?
????????底层使用的也是迭代器,使用for循环的格式,简化了迭代器的书写,是JDK1.5之后出现的新特性,用来遍历集合和数组,因为没有索引,所以不能对集合中的元素进行增删操作。
格式:
????????for(集合/数组中元素的数据类型 变量名:集合名/数组名){
????????????????System.out.println("变量名");
????????}注:增强for循环必须有被遍历的目标,目标只能是集合或者数组。
package com.zhy.coll;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectTest {
public static void main(String[] args) {
//1.创建集合对象
Collection coll = new ArrayList();
//2.将集合中添加元素
coll.add("张三");
coll.add(123);
coll.add(true);
System.out.println("初始化集合:" + coll);
//3.使用增强for遍历集合
System.out.print("使用增强for遍历集合:");
for(Object obj : coll) {
System.out.print(obj + " ");
}
}
}
????????是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型,也可以看做是一个变量,用来接收数据类型。
用法:?是在容器后面添加<Type>,Type可以是类,抽象类,接口,表示只能存放这种类型或者其子类。
E e:Element 元素
T t:Type 类型
例如:ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型定义为泛型,创建集合对象的时候,就会确定泛型的数据类型。
综合考虑,使用泛型的好处大于弊端,推荐使用泛型。?
package com.zhy.coll;
import java.util.ArrayList;
import java.util.List;
public class CollectTest {
public static void main(String[] args) {
//创建不带泛型的集合,那可以存储任意类型的数据
List list = new ArrayList();
list.add(123);
list.add("张三");
//创建带<String>泛型的集合,只能存储字符串类型的数据
//如果存储非String类型的数据,会编译报错
List<String> list2 = new ArrayList<String>();
list2.add("Annie");
list2.add("Bob");
}
}
????????定义一个含有含有泛型的类,模拟ArrayList集合,泛型是一个未知的数据类型,当我们不确定需要什么数据类型的时候,可以使用泛型,泛型可以接收任意类型的数据,可以是Integer、String...,创建对象的时候确定泛型的数据类型。
格式:
????????修饰符 class 类名<代表泛型的变量>
????????
注意:
????????需要在所有使用数据类型的地方都改成泛型,包括类、属性、方法、局部变量的数据类型。
package com.zhy.coll;
public class GenericClass<E> {
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
}
package com.zhy.coll;
public class CollectTest {
public static void main(String[] args) {
//创建GenericClass对象,泛型指定为String类型,就是将定义类中的所有E都换成String
GenericClass<String> geClass = new GenericClass<String>();
geClass.setName("张三");
System.out.println(geClass.getName());
//创建GenericClass对象,泛型指定为Integer类型,就是将定义类中的所有E都换成Integer
GenericClass<Integer> geClass2 = new GenericClass<Integer>();
geClass2.setName(123);
System.out.println(geClass2.getName());
}
}
????????定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间。
格式:
????????修饰符 <泛型> 返回值类型 方法名(参数列表 使用泛型){
????????????????方法体;
????????}????????
注意:
? ? ? ? 含有泛型的方法,在调用方法的时候确定泛型的数据类型,传递什么类型的参数,泛型就是什么类型。
泛型应用到接口上,有两种形式。一是接口定义为泛型,接口的实现类,指定接口的泛型。二是接口使用什么类型,实现类就使用什么类型,创建对象时确定。?
格式:
????????修饰符 interface 接口名<泛型>{}
使用:
? ? ? ? 方式一:Scanner类实现了Iterator接口,并指定接口的泛型为String,所有重写了next方法泛型默认就是Stringpublic interface Iterator<E> { E next(); }
public final class Scanner implements Iterator<String>, Closeable { public String next() {//……} //…… }
? ? ? ? 方式二:类跟着接口走,就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型。
public interface List<E> extends Collection<E> { void add(int index, E element); E get(int index); //…… }
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { public boolean add(E e) {//……} public E get(int index) {//……} //…… }
?????????当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以使用通配符<?>表示,但是一旦使用泛型的通配符后,只能使用Object类中的共性方法,集合中元素自身方法无法使用。
?:代表任意的数据类型,不能创建对象使用,只能作为方法的参数使用。
?????????之前指定泛型的时候,实际上是可以任意设置的,只要是类就可以设置,但是在JAVA的泛型中可以指定一个泛型的上限和下限。
泛型的上限:
????????格式:类型名称 <? extends T> 对象名称
????????含义:表示只能接收T类型及其子类。所以往集合里面取出来的元素一定可以转型为T类型,是安全的。但是往集合放元素,可能放的子类A的数据,但实际是子类B的泛型,无法确定类型,所以会编译报错。????????
泛型的下限:
????????格式:类型名称 <? super T> 对象名称
????????含义:表示只能接收T类型及其父类。所有对象都继承Object对象,所以不管往集合里面放入什么类型的数据,Object都可以接收,是安全的。但是如果从集合里面取元素,无法确定类型,用实际类型接收不可取。总结:
? ? ? ? 1.如果希望只取出,不插入,就使用 "? extends T"。
? ? ? ? 2.如果希望只插入,不取出,就使用 "? super T"。
? ? ? ? 3.如果希望,又能插入,又能取出,就不要用通配符 "?"。
? ? ? ? 4.子类泛型和父类泛型 不可以像对象那样进行子父类之间的转换。
package com.zhy.coll;
import java.util.ArrayList;
public class TestGeneric {
/**
* 遍历Animal及其子类的集合
* @param list
*/
public static void iterate(ArrayList<? extends Animal> list) {
for (Animal animal : list) {
System.out.println(animal.name);
}
}
public static void main(String[] args) {
//传递Animal对象集合
ArrayList<Animal> animals = new ArrayList<>();
iterate(animals);
//传递Animal的子类对象Dog集合
ArrayList<Dog> dogs = new ArrayList<>();
iterate(dogs);
}
}