集合: 将多个数据(元素)存储在一起。也是一个容器。 理论上存储任意多个"不同数据类型"的数据。 只能存储 "引用数据类型的数据" 底层已经封装好了空间不足或者移动位置等这些操作。 //实际开发中 存储还是相同类型的数据(避免出现类型转换的异常) 数组: 一个容器。存储相同数据类型指定length个数据。 空间固定 数据类型必须相同。 数组可以存储什么类型的数据? int[] String[] Bike[] "所有的类型都可以。" 优势: 查询/修改性能最快。index 弊端: 新增/删除性能比较低。 空间固定----> 一值新增 手动扩容 数据是连贯的---->后面的数据向左移动位置
数组 VS 集合 相同点:容器。存储很多元素/数据。 不同点: 数组: 空间固定 数据类型必须相同 集合: 空间可变 数据类型可以相同
1. 集合分类
Collection VS Map
元素 | 元素是否可重复 | |
---|---|---|
Collection<T> | 存储的是单值元素(一次存储一个) | 具体看子级List/set |
Map<K,V> | 存储的是一组元素(key-value) | key必须唯一 value可重复的 |
2. Collection<T>
元素是否有序(索引位置) | 元素是否可重复 | |
---|---|---|
List<T> | 有序 | 可重复 |
Set<T> | 无序 | 不可重复 |
2.1 常用方法
方法 | 功能 |
---|---|
boolean`add(E e)
|
将指定的数据添加集合中 |
void``clear() |
清空集合里面所有的元素 |
boolean``contains(Object o) |
判断集合里面是否包含指定的数据 |
boolean``isEmpty() |
判断集合是否是空 |
Iterator<E>``iterator() |
获得集合对象的迭代器对象(遍历集合元素) |
boolean``remove(Object o) |
删除集合里面元素 |
int``size() |
获得集合元素个数 |
Object[]``toArray() |
集合转数组 |
<T> T[]``toArray(T[] a) |
|
default boolean``removeIf(Predicate<? super E> filter) |
删除满足条件的多个元素 |
Stream<E>``parallelStream() |
获得集合对象的并行化Stream对象 |
default Stream<E>``stream() |
获得集合串行化Stream对象 |
default void``forEach(Consumer<? super T> action) |
(遍历集合元素) |
Iterator
boolean hasNext() 判断指针/光标后面是否有更多的数据需要迭代】 E next() 获得指针之后的元素数据 default void remove() 从底层集合中删除此迭代器返回的最后一个元素(可选操作)。
2.2 使用方法
private static void demo1() { //创建集合对象 增删改查集合元素 Collection collection = new ArrayList(); //System.out.println(collection.isEmpty()); System.out.println(collection);//[] //1.新增元素---> 存储不同类型的数据 collection.add(100); collection.add("hello"); collection.add("hello"); collection.add("hello"); collection.add(true); collection.add(null); collection.add(new UserInfo()); collection.add(100.123); System.out.println(collection); System.out.println("集合的元素个数:" + collection.size()); //2.删除集合元素 /* collection.remove("hello"); collection.remove("hello"); collection.remove("hello");*/ //循环 遍历集合里面的每个元素 删除满足条件的数据 /*collection.removeIf(new Predicate() { @Override public boolean test(Object data) { return Objects.equals(data, "hello"); } });*/ //面向函数式编程----> 面向方法编程---->重写的那个方法 //lamda: ()->{} //类名/引用::方法名 //collection.removeIf(a -> Objects.equals(a, "hello")); //collection.removeIf("hello"::equals); //判断集合里面是否包含指定的数据 //System.out.println(collection.contains(100)); //清空集合元素 //collection.clear(); //集合转数组 //Object[] array = collection.toArray(); //System.out.println(Arrays.toString(array)); System.out.println(collection); System.out.println(collection.size()); }
2.3 遍历集合元素
private static void demo2() { Collection collection = new ArrayList(); collection.add(1); collection.add(10); collection.add(2); collection.add("abc"); collection.add(null); //循环遍历输出集合里面的每个元素数据 //增强for /*for(Object data:collection){ System.out.println(data); }*/ /* //1.获得集合对象的迭代器对象 Iterator it = collection.iterator();//集合里面的所有的数据都在it //2.判断指针之后是否有更多的数据需要迭代 while (it.hasNext()) { //3.获得指针之后的数据 Object data = it.next(); System.out.println(data); }*/ //1.8+ forEach /*collection.forEach(new Consumer() { @Override public void accept(Object obj) { System.out.println(obj); } });*/ //使用lamda替换上面的匿名内部类 //:: // collection.forEach(o->System.out.println(o)); collection.forEach(System.out::println); //遍历Collection: //1.增强for循环 //2. iterator() //3. forEach();
2.4 集合_泛型
public static void main(String[] args) { //使用泛型修饰集合 //泛型+集合: 限定集合元素数据类型。 只存储一种类型的数据。 Collection<String> nameCollection = new ArrayList<>(); //泛型只在编译期间有效 在运行期间其实泛型还是Object---->反射 泛型擦除 nameCollection.add("张三"); nameCollection.add("李四"); nameCollection.add("王五"); nameCollection.add("赵六"); //遍历集合元素 /*for (String name : nameCollection) { System.out.println(name); }*/ //nameCollection.forEach(System.out::println); /* Iterator<String> it = nameCollection.iterator(); while (it.hasNext()) { String str = it.next(); System.out.println(str); }*/ //nameCollection.remove("张三"); //nameCollection.removeIf("张三"::equals); System.out.println(nameCollection); //集合转数组 //无参的toArray()不推荐 返回值类型Object[] 需要进行手动类型转换 /*Object[] array1 = nameCollection.toArray(); for (Object o : array1) { String s= (String) o; }*/ //<T> T[] toArray(T[] a); //集合转数组: 推荐数组的空间 0 //length>size 有很多null 很容易NPE 空间内存浪费 //size<length>0 并发的时候 多次将集合转数组 GC进行回收无用的数组引用 //length==0 String[] strings1 = nameCollection.toArray(new String[0]); System.out.println("strings1:" + Arrays.toString(strings1)); }
3. 泛型<>
<T,k> T K V 一般都是使用 A-Z。 限定泛型里面参数化的数据类型。
只能是引用数据类型。
作用: 实现类型的自动转换。
泛型修饰类 ----> 泛型类 泛型修饰方法 ----> 泛型方法 泛型修饰接口 ----> 泛型接口
3.1 问题(使用变量维护不定类型的数据)
@Data public class MyClass { private Integer id; private String name; //使用data维护了一个不定类型数据 private Object data; }
private static void demo1() { //创建MyClass类对象 对属性进行取值以及赋值 MyClass myClass = new MyClass(); myClass.setId(1001); myClass.setName("zhangsan"); myClass.setData(100); //每次获取数据的时候 都要手动进行类型的强制转换 //有可能会出现类型转换的异常 Integer id = myClass.getId(); String name = myClass.getName(); Integer data = (Integer) myClass.getData(); data = data + 100; MyClass myClass1 = new MyClass(); myClass1.setData("hello"); String d = (String) myClass1.getData(); }
可以满足使用data变量维护不同类型的数据。但是每次获得数据的时候 都要进行类型的强制转换 进而实现其他的功能。
在这种情况下:
-
就会有可能出现类型转换的异常
-
每次都进行手动的转换 代码不是很优雅
3.2 泛型类解决
目标: 不使用类型的强制转换 实现类型的自动转换 。
使用泛型进行解决。
//MyClass<T> 代表是一个泛型类。T:参数化类型 //不清楚T的真实的数据类型。Object @Data public class MyClass<T> { private Integer id; private String name; //使用data维护了一个不定类型数据 private Object data; //参数化数据类型---->指定好的规则 A-Z T E K V private T data1; //实例方法: 对象/引用.方法 //参数化到底是什么类型? 创建对象的时候 指定的参数化类型具体是什么类型 public T a(T t) { return null; } }
public static void main(String[] args) { //需求: "实现类型的自动转换" //一般类 接口是泛型类或者泛型接口 一般都会指定参数化类型 MyClass<String> myClass = new MyClass<>(); myClass.setData1("hello"); String data1 = myClass.getData1(); MyClass<Integer> myClass1 = new MyClass<>(); myClass1.setData1(100); Integer data11 = myClass1.getData1(); }
3.3 泛型方法
在任意一个类里面 都可以使用泛型修饰方法。
使用参数化类型修饰方法 这个方法就是泛型方法。
//K:是一个参数化类型 不指定 默认Object public class FanXingClass<K> { private K a; //只是参数化类型 充当形参和返回值 //K类型是固定的 只能是一种 创建对象的时候 指定的数据类型 public K getA() { return a; } public void setA(K a) { this.a = a; } //泛型方法 //T: 不定类型 //K: 创建对象的时候类型 m1是一个实例方法 public <T> void m1(T abc, K bb) { } //静态方法 //是否可以使用参数化数据类型? 创建对象的时候指定参数化类型 //在泛型类里面 提供了很多静态的方法 里面使用参数化类型 这些静态方法都是"泛型方法" public static <K> void m2(K aaa) { } //一个泛型类里面 有很多的静态的方法 这个类一般都是工具类 用来封装一些的数据。 }
3.4 泛型接口
//后期有很多模块: User Product // 新增 删除 修改 查询 //T 就是 User Product.... class User { } class Product { } public interface BaseDao<T> { void add(T t); void delete(); void update(); T findOne(); Collection<T> findAll(); } class ProductDaoImpl implements BaseDao<Product>{ @Override public void add(Product product) { } @Override public void delete() { } @Override public void update() { } @Override public Product findOne() { return null; } @Override public Collection<Product> findAll() { return null; } } class UserDaoImpl implements BaseDao<User>{ @Override public void add(User user) { } @Override public void delete() { } @Override public void update() { } @Override public User findOne() { return null; } @Override public Collection<User> findAll() { return null; } }
3.5 上限和下限
//使用 T extends 具体类型 规定参数化类型的上限 //只能:Number以及Number类型所有的子类 public class DemoTest<T extends Number> { //?是一个通配符 统配任意一个类型 //下限: ?只能是String以及String的父级类型。 public static void a(Collection<? super String> collection) { } } class Test3 { public static void main(String[] args) { Collection<Comparable> collection = new ArrayList<>(); DemoTest.a(collection); } }