[java]day07Collection&泛型
集合
集合长度可变, 数组长度不可变
集合能存引用类型, 数组可存任意类型.
集合都需要用get/set/remove等包装方法来操作元素.
集合继承关系
Collection是单列集合根接口
java.util.
java.util.Collection
list: 有序/有id/可重复
ArrayList
LinkList
set: (无序)/无id/不可重复
hashset:无序,底层哈希表
linkhashset: 有序
map
ArrayList(底层是可变长数组)和LinkedList(底层是链表)操作方法基本一致,不过多了一些头尾元素的操作方法.
查询多的场景用ArrayList.
增删多的是用LinkedList
Collection接口公共功能
基本都是无参方法. 因为list支持index, 而set无index.
add
isEmty
size
remove
clear
contains
toArray
iterator()
集合接口继承层次较深, 要研究上层定义的公共方法, 使用多态方式创建.
Collection
public class Test {
public static void main(String[] args) throws Exception {
Collection<String> coll = new ArrayList<>();
coll.add("m1");
coll.add("m2");
coll.add("m3");
coll.add("m1");
System.out.println(coll.isEmpty());
System.out.println(coll.size());
System.out.println(coll.remove("m1"));
System.out.println(coll);
System.out.println(coll.contains("m1"));
coll.add("g1");
coll.add("g2");
//集合遍历(集合没有索引),转为数组后遍历
Object[] arr = coll.toArray();
for (int i = 0; i < arr.length; i++) {
Object obj = arr[i];
//System.out.println(arr[i]);
//获取数组元素的某些属性不方便
System.out.println(obj + " " + ((String) obj).length());
}
coll.clear();
System.out.println(coll);
}
}
iterator
集合的遍历方式: 1.传统的for 2.iterator(迭代器) 3.增强for
如ArrayList实例生成一个迭代器对象list.iterator(),对这个对象迭代. 先判断有无元素, 然后取出元素,直到取完为止.称为迭代.
iterator接口常用方法
java.util.iterator:
public abstract boolean hasNext()
public abstract E next()
public abstract void remove()
public class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("m1");
list.add("m2");
list.add("m3");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
Iterator<String> it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
for (String s : list) {
System.out.println(s);
}
}
}
iterator实现原理
iterator内部类实现.iterator()方法返回一个实现来Iterator接口的实例.
public class ArrayList<E> extends AbstractList<E>{
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
...
public boolean hasNext()
public E next()
...
增强for
增强for主要用于遍历功能, 不是用来增删改的
用增强for遍历,期间不要增删改元素, 会抛错(ConcurrentModificationException). 因为它线程不安全(但高效)
public class Test {
public static void main(String[] args) {
int[] arr = {11, 22, 33};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
for (Integer i : arr) {
System.out.println(i);
}
}
}
public class Test {
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
coll.add("m1");
coll.add("m2");
coll.add("m3");
Iterator<String> it = coll.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
for (String s : coll) {
System.out.println(s);
}
}
}
- 在进行集合元素获取时,如果集合中已经没有元素了,还继续使用迭代器的next方法,将会抛出 java.util.NoSuchElementException没有集合元素异常。
- 在进行集合元素获取时,如果添加或移除集合中的元素 , 将无法继续迭代 , 将会抛出 ConcurrentModificationException并发修改异常.
泛型(generic)
可以在类或方法中预支地使用未知的类型。
广泛的类型, 代码模版化思路
public class ArrayList<E>
public class ArrayList<Integer>
public class ArrayList<String>
//有这些标记
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型
S、U、V - 2nd、3rd、4th types
泛型 | 确定时机 | 定义 | 实例化 |
---|---|---|---|
定义在类上, 修饰字段类型 | 实例化类时确定类型 | class MyClass<T> | MyClass<Integer> mc = new MyClass<>(); |
定义在方法上,修饰方法参数类型 | 调用方法时确定类型 | public <T> void show(T s) | mc.show(10); |
定义在接口上,约束实现类方法的参数类型 | 实现接口时确定类型 | interface MyInter<T> | class MyInterImplA implements MyInter<String> |
如果不指定类型,直接使用,默认Object类型
MyClass mc = new MyClass();
使用泛型好处
1.避免强转
2.错误提前到编译时
3.类型统一,add/get
4.实现代码模版化,将数据类型当错参数传递
注意: ArrayList arr2 = new ArrayList();
//public class ArrayList
public class Test {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
arr.add("m1");
arr.add("m2");
arr.add("m3");
for (String s : arr) {
System.out.println(s + " " + s.length());
}
ArrayList arr2 = new ArrayList(); //public class ArrayList<E> 带泛型的类, 如果直接new,得到的类型是Object.
arr2.add("m1");
arr2.add("m2");
arr2.add("m3");
//arr2.add(1000);//编译没错,运行时(String) s)转换元素类型, 会导致ClassCastException
for (Object s : arr2) {
System.out.println(s + " " + ((String) s).length());//强制类型转换
}
}
}
泛型的定义与使用
E element
T type
K V
定义在类上
定义在类上
用于约束实例属性的类型
创建class时确定类型
public class Test {
public static void main(String[] args) {
MyClass<String> mc = new MyClass<>();
mc.setT("m1");
//mc.setT(1000); //只能传str
System.out.println(mc.getT());
MyClass<Integer> mc2 = new MyClass<>(1000);
int t = mc2.getT();
System.out.println(t);
}
}
class MyClass<T>{
private T t;
public MyClass() {
}
public MyClass(T t) {
this.t = t;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
定义在方法上
定义在方法上
用于约束方法参数的类型
调用方法时确定类型
public class Test {
public static void main(String[] args) {
MyClass<String> mc = new MyClass<>();
mc.print("m1"); //只能str
//mc.print(22);
mc.show(100);//任意类型
}
}
class MyClass<T> {
public void print(T t) {
System.out.println(t);
}
public <E> void show(E e) {//方法上定义属于自己的泛型
System.out.println(e);
}
}
定义在接口上
定义在接口上
约束(类实现)接口方法的参数类型
类实现接口是确定类型
public class Test {
public static void main(String[] args) {
MyInterImplA mia = new MyInterImplA();
mia.print("hi");
MyInterImplB<String> mib = new MyInterImplB<>();
mib.print("hi");
MyInterImplB<Integer> mib2 = new MyInterImplB<>();
mib2.print(1212);
}
}
interface MyInter<T> {
void print(T t);
}
//定义实现类时,确定接口上泛型的具体类型
class MyInterImplA implements MyInter<String> {
@Override
public void print(String s) {
System.out.println(s);
}
}
//定义实现类时,不确定接口的类型,那么
// 实现类必须定义为泛型类
// 实现类上泛型变量名要和接口上泛型变量名一致
class MyInterImplB<T> implements MyInter<T> {
@Override
public void print(T t) {
System.out.println(t);
}
}
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E>
public interface List<E> extends Collection<E>
public interface Collection<E> extends Iterable<E>
public interface Iterable<T>
泛型通配符
只能用来匹配泛型,不能用来定义泛型.
通配符基本使用
public class Test {
public static void main(String[] args) {
ArrayList<String> s = new ArrayList<>();
s.add("m1");
ArrayList<Integer> in = new ArrayList<>();
in.add(100);
printArrayList(s);
printArrayList(in);
}
//public static void printArrayList(ArrayList<Integer> list){
//
//}
//代表任意一种引用类型,只能用来匹配泛型,不能用来定义
public static void printArrayList(ArrayList<?> list){
for (Object o : list) {
System.out.println(o);
}
}
}
public class Test {
public static void main(String[] args) {
//泛型不存在多态,创建对象时候,左右两边<>保持一致
ArrayList<Object> list1 = new ArrayList<Object>();
//ArrayList<Object> list2 = new ArrayList<String>();
//ArrayList<?> 可以接受ArrayList任意类型的泛型对象(<>随便写一种引用类型都ok)
ArrayList<?> list;
list = new ArrayList<>();
list = new ArrayList<Integer>();
list = new ArrayList<String>();
list = new ArrayList<Student>();
}
}
通配符高级使用
/*
* 父类: Person
* 子类: Woker
* 子类: Teacher
* 子类: JavaTeacher
*
* 一个类的子类可以有任意多个,如何表示一个类的任意子类呢
*
* ? extends Person: 表示是Person类型或者Person类型的任意子类
* ? extends E // E类型的上限
* ? super Teacher: 表示是Teacher类型或者Teacher类型的任意父类
* ? super E // E类型的下限
* */
public class Test {
public static void main(String[] args) {
ArrayList<Person> list1 = new ArrayList<>();
ArrayList<Woker> list2 = new ArrayList<>();
ArrayList<Teacher> list3 = new ArrayList<>();
ArrayList<JavaTeacher> list4 = new ArrayList<>();
ArrayList<Integer> in = new ArrayList<>();
printArrayList(list1);
printArrayList(list2);
printArrayList(list3);
printArrayList(list4);
//printArrayList(in);
}
//只能打印Person子类对象
public static void printArrayList(ArrayList<? extends Person> list) {
for (Object o : list) {
System.out.println(o);
}
}
}
class Person {
}
class Woker extends Person {
}
class Teacher extends Woker {
}
class JavaTeacher extends Teacher {
}