collection集合
1.1集合概述
集合:集合是java中提供的一种容器,可以用来存储多个数据。 集合和数组既然都是容器,他们有啥区别?
1.java中数组的长度是固定的,集合的长度是可变的。
2.数组存储的是同一类型的元素,可以存储基本数据类型值,也可以存储引用数据类型。集合中存储的都是对象,而且对象的类型可以不一致,在开发中一般当对象多的时候,使用集合进行存储。
1.2 集合框架
集合按照其存储结构可以分为两大类,分别是单列集合java.util.collection和双列集合java.util.Map。
collection: 单列集合的根接口。用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是List和Set接口,List接口特点是元素有序,元素可以重复。Set接口的特点是元素无序,并且不能重复。List接口主要的实现类有arrayList和linkedList,set接口主要的实现类有HashSet和TreeSet。
1.2.1 collection集合体系图
注意:
在学习使用集合的时候,学习顶层接口/抽象类中的共性方法,因为所有的子类都能使用。
在学习使用集合的时候,使用底层,因为顶层不是接口就是抽象类,不能创建对象使用,需要使用底层的子类创建对象使用
1.2.2 常用集合的底层及特点
集合名 | 底层实现原理 | 特点 |
ArrayList | 数组 | 查询快,增删慢 |
LinkedList | 链表 | 增删快,查询慢 |
vector(了解) | 数组 | 和arrayList类似,但是线程安全 |
HashSet | 哈希表+红黑树 | 无索引,不可存储重复元素,存取无序 |
LinkedHashSet | 哈希表+链表 | 无索引,不可存储重复元素,保证存取顺序 |
TreeSet(了解) | 二叉树 | 一般就用于排序 |
1.3collection常用功能
所有单列集合的最顶层接口,里面定义了所有单列集合共性的方法,任意的单列集合都可以使用collection中的方法。
共性方法:
1.public boolean add(E e) 把给定的对象添加到当前的集合中
2. public void clear() 清空集合中所有的元素
3. public boolean remove(E e) 把给定的元素在当前集合中删除
4. public boolean contains(E e) 判断当前集合中是否包含给定的对象
5.public boolean isEmpty() 判断当前集合是否为空
6. public int size() 返回集合中元素的个数
7.public Object[] toArray() 把集合中的元素,存储到数组中,并返回
代码演示:
public static void main(String[] args) {
//首先创建集合对象 使用多态形式
Collection<String> coll = new ArrayList<>();
// public boolean add(E e) 把给定的对象添加到当前的集合中
boolean b1 = coll.add("张三"); //true
coll.add("张二");
System.out.println(b1);
System.out.println(coll);
// public void clear() 清空集合中所有的元素
//
// public boolean remove(E e) 把给定的元素在当前集合中删除
boolean b2 = coll.remove("李四");
System.out.println(b2); //false
// public boolean contains(E e) 判断当前集合中是否包含给定的对象
System.out.println(coll.contains("lisi"));
System.out.println(coll.contains("张三"));
// public boolean isEmpty() 判断当前集合是否为空
System.out.println(coll.isEmpty());
// public int size() 返回集合中元素的个数
System.out.println(coll.size());
// coll.clear();
// System.out.println(coll.size());
// public Object[] toArray() 把集合中的元素,存储到数组中,并返回
Object[] objects = coll.toArray();
for(int i=0;i<objects.length;i++){
System.out.println(objects[i]);
}
}
iterator迭代器
1.概述
在程序开发中,经常需要遍历集合中的所有元素,因为有的集合没有索引,不能使用普通的for循环遍历,针对这种需求jdk专门提供了一个接口java.util.Iterator接口。Iterator接口也是java集合中的一员,但它 与collection、map接口有所不同,Collection接口与Map接口主要用于存储元素,而Iterator主要用于迭代访问(即遍历)collection中的元素,因此iterator对象也被称为迭代器对象。
1.1迭代的概念
迭代:即collection集合元素的通用获取方式,在取元素之前要先判断该集合中有没有元素,如果有,就把这个元素取出来,继续再判断,如果还有就再取出来,一直把集合中的所有元素全部取出,这种取出方式专业术语叫迭代。
1.2获取迭代器的方法
public Iterator iterator() 获取集合对应的迭代器,用来遍历集合中的元素
1.3 iterator接口中的方法
1.public E next() 判断集合中还有没有下一个元素,有就返回该元素,没有就报异常。
2. public boolean hasNext() 如果仍有元素可以迭代,则返回true
代码演示:
public static void main(String[] args) {
//创建一个集合对象
Collection<String> coll = new ArrayList<>();
//添加元素
coll.add("科比");
coll.add("麦迪");
coll.add("卡特");
coll.add("艾佛森");
//System.out.println(coll);
//多态形式获取Iterator对象
Iterator<String> it = coll.iterator();
//取出一个元素
String s = it.next();
//System.out.println(s);
//循环取出所有元素
while (it.hasNext()){
String str = it.next();
System.out.println(str);
}
System.out.println("-----------------------");
for(Iterator<String> it2=coll.iterator();it2.hasNext();){
String e = it2.next();
System.out.println(e);
}
}
注意:
1.Iterator接口也是有泛型的,迭代器的泛型是跟着集合走,集合是什么泛型,迭代器就是什么泛型。
- 发现使用迭代器取出集合中元素的代码,是一个重复的过程,所以我们可以使用循环优化,
不知道集合中有多少元素,使用while循环,循环结束的条件是hashNext方法返回false
- 在进行集合元素取出时,如果集合中已经没有元素了,还继续使用next方法,将会发生NoSuchElementException异常
泛型
1.1 泛型概述
在前面学习的集合概念中,我们都知道集合中也可以存储任意类型对象,只要把对象存储集合后,那么这时候都会被提升为object类型。当我们在取出每一个对象,并且进行相应的操作,这时候就必须要类型转换。
代码:
public class GenericDemo {
public static void main(String[] args) {
Collection coll = new ArrayList();
coll.add("abc");
coll.add(123); //由于集合中没有做任何限定 任何类型都可以在其中存储
coll.add("hqyj");
Iterator it = coll.iterator();
while (it.hasNext()){
//需要打印字符串的长度 就要把迭代出来的元素转换成String类型对象
String str = (String)it.next();
System.out.println(str.length());
}
}
}
上述代码在运行时,会报ClassCastException异常。
1.1.1 使用泛型主要是在我们不清楚需要什么数据类型的时候使用
注意:
1.泛型可以在类或者方法中预支的使用未知的类型
2.一般在对象创建的时候,将未知的类型确定具体的类型,当没有指定泛型时,默认为object类型。
1.2 泛型的好处与弊端
使用泛型 | 不使用泛型 | |
好处 | 1.避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型 2.把运行时期异常提升到了编译期 | 集合不使用泛型,默认的是object类型,可以存储任意类型的元素 |
弊端 | 泛型是什么类型,只能存储什么类型的数据 | 不安全,有可能引发异常 |
1.3 定义和使用具有泛型的类
格式:修饰符 class 类名<代表泛型的变量> {} 代码:
public class MyGenericClass<MVP>{
//没有MVP类型,在这里代表未知的一种数据类型,未来传递什么类型就是什么类型
private MVP mvp;
public void setMvp(MVP mvp){
this.mvp=mvp;
}
public MVP getMvp(){
return mvp;
}
}
测试类:
public static void main(String[] args) {
//创建一个泛型为String的类
MyGenericClass<String> my = new MyGenericClass<>();
//调用setMvp
my.setMvp("安东尼-戴维斯");
//调用getMvp
System.out.println(my.getMvp());
//创建一个泛型为Integer的类
MyGenericClass<Integer> my2 = new MyGenericClass<>();
my2.setMvp(123);
System.out.println(my2.getMvp());
}
1.4 定义和使用具有泛型的方法
格式: 修饰符 返回值类型 方法名(参数列表){
//方法体
}
代码:
public class GenericMethod {
//定义一个含有泛型的方法
public <M> void method01(M m){
System.out.println(m);
}
//定义一个含有泛型的静态方法
public static <S> void method02(S s){
System.out.println(s);
}
}
测试类:
public static void main(String[] args) {
//创建对象
GenericMethod gm1 = new GenericMethod();
/*
调用含有泛型的方法method01
传递什么类型,泛型就是什么类型
*/
gm1.method01(10);
gm1.method01(true);
gm1.method01(8.8);
gm1.method01("abc");
gm1.method02("静态方法,不建议创建对象调用,没有必要");
//推荐直接使用类名去调用静态方法
GenericMethod.method02("静态方法没有创建对象调用");
GenericMethod.method02(1);
}
1.5 定义和使用具有泛型的接口
格式: 修饰符 interface 接口名{
修饰符 <泛型> 返回值类型 方法名(参数列表)
}
代码:
定义含有泛型的接口
public interface GenericInterface<I>{
void method(I i);
}
接口实现类1:定义类时确定泛型的类型
public class GenericInterfaceImpl1<String> implements GenericInterface<String>{
@Override
public void method(String s) {
System.out.println(s);
}
}
接口实现类2:在声明的时候不确定泛型的类型,创建对象的时候,再确定泛型的类型
public class GenericInterfaceImpl2<I> implements GenericInterface<I>{
@Override
public void method(I i) {
System.out.println(i);
}
}
测试类:
public static void main(String[] args) {
//创建对象GenericInterfaceImpl1对象
GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
gi1.method("字符串");
//创建声明时没有确定泛型的实现类对象 再创建对象的时候确定泛型
GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
gi2.method(10);
GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();
gi3.method(8.8888888);
}
1.6泛型的通配符
当使用泛型类或者接口的时候,传递的数据中,泛型类型不确定,可以通过通配符表示。但是一旦使用泛型的通配符后,只能使用object类中的共性方法,集合中元素自身方法无法使用。
1.6.1 通配符的基本使用
泛型 通配符:不知道使用什么类型来接收的时候,此时可以使用?,?表示未知通配符,此时只能接收数据,不能往集合中存储数据。
代码:
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<>();
getElemet(list1);
Collection<String> list2 = new ArrayList<>();
getElemet(list2);
}
//带有通配符的方法
public static void getElemet(Collection<?> coll){}
注意:
1.泛型不存在继承关系,Collection list = new ArrayList();这种写法是错误的
2.通配符不能创建对象使用,只能作为方法的参数使用。ArrayList list = new ArrayList();也是错误的
1.7 通配符的高级使用----受限泛型(了解)
之前设置泛型的时候,实际上是可以任意设置的,只要是类就可以设置,但是在java中的泛型可以指定一个泛型的上限和下限。
泛型的上限:
格式: 类型名称 <? extends 类> 对象名称 意义: 只能接受该类型及其子类
泛型的下限:
格式: 类型名称 <? super 类> 对象名称 意义: 只能接受该类及其父类型
例如:
类与类之间的继承关系:Integer extends Number extends Object,String extends object
定义泛型的上限:
//定义泛型的上限 此时的泛型必须是number类或者number类型的子类 public static void getElement01(Collection<? extends Number> coll){}
定义泛型的下限:
//定义泛型的下限 此时的泛型必须是number类或者number类型的父类 public static void getElement02(Collection<? super Number> coll){}
测试类:
public static void main(String[] args) {
Collection<Integer> list1 = new ArrayList<>();
Collection<String> list2 = new ArrayList<>();
Collection<Number> list3 = new ArrayList<>();
Collection<Object> list4 = new ArrayList<>();
getElement01(list1);
//getElement01(list2);
getElement01(list3);
//getElement01(list4);
//getElement02(list1);
//getElement02(list2);
getElement02(list3);
getElement02(list4);
}
因为作者现在也是在学习的小白,这是跟随老师的笔记的总结,如果不对,请告诉我!!!(老师应该不会告我侵权吧)