视频地址:https://www.bilibili.com/video/BV1Cv411372m
此笔记是:P128 - P132
1.集合的概述
-
集合和数组都是容器。
-
数组的特点
- 数组定义完成并启动后,类型确定、长度固定。
- 适合元素的个数和类型确定的业务场景,不适合做需要增删数据操作。
- 在进行增删数据操作的时候,数组是不太合适的,增删数据都需要放弃原有数组或者移位。
-
集合的特点
- 集合是Java中存储对象数据的一种容器。【只能存储对象,不支持基本类型】
- 集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。集合更像气球。
-
集合非常适合做元素的增删操作。
- 注意:集合只能存储引用类型数据,如果要存储基本类型数据可以选用包装类【相当于把一个基本类型变成所谓的对象类型】。
- 注意:集合只能存储引用类型数据,如果要存储基本类型数据可以选用包装类【相当于把一个基本类型变成所谓的对象类型】。
2.集合的体系特点
-
集合类体系结构
- Collection单列集合,每个元素(数据)只包含一个值。
- Map双列集合,每个元素包含两个值(键值对)。
- 注意:前期先掌握Collection集合体系的使用。
-
Collection集合体系
-
Collection集合特点
- List系列集合:添加的元素是有序、可重复、有索引。
- ArrayList、LinekdList :有序、可重复、有索引。
- Set系列集合:添加的元素是无序、不重复、无索引。
- HashSet: 无序、不重复、无索引;LinkedHashSet: 有序、不重复、无索引。
- TreeSet:==按照大小默认升序排序、==不重复、无索引。
- List系列集合:添加的元素是有序、可重复、有索引。
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/**
目标:明确Collection集合体系的特点
*/
public class CollectionDemo1 {
public static void main(String[] args) {
// 有序 可重复 有索引
Collection list = new ArrayList();
list.add("Java");
list.add("Java");
list.add("Mybatis");
list.add(23);
list.add(false);
System.out.println(list);// 打印结果为:[Java,Java,Mybatis,23,false]
// 无序 不重复 无索引
Collection list1 = new HashSet();
list1.add("Java");
list1.add("Java");
list1.add("Mybatis");
list1.add(23);
list1.add(23);
list1.add(false);
list1.add(false);
System.out.println(list1); // 打印结果为:[Java,false,23,Mybatis]
}
}
-
集合对于泛型的支持
- 集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型。
Collection<String> lists = new ArrayList<String>(); Collection<String> lists = new ArrayList<>(); // JDK 1.7开始后面的泛型类型申明可以省略不写
注意:集合和泛型都只能支持引用数据类型,不支持基本数据类型,所以集合中存储的元素都认为是对象。
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
/**
目标:明确Collection集合体系的特点
*/
public class CollectionDemo1 {
public static void main(String[] args) {
// Collection<String> list2 = new ArrayList<String>();
Collection<String> list2 = new ArrayList<>(); // JDK 7开始之后后面类型申明可以不写
list2.add("Java");
// list2.add(23);
list2.add("黑马");
// 集合和泛型不支持基本数据类型,只能支持引用数据类型
// Collection<int> list3 = new ArrayList<>();
Collection<Integer> list3 = new ArrayList<>();
list3.add(23);
list3.add(233);
list3.add(2333);
Collection<Double> list4 = new ArrayList<>();
list4.add(23.4);
list4.add(233.0);
list4.add(233.3);
}
}
3.Collection的常用方法(掌握)
-
Collection集合
-
Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
-
Collection API如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
目标:Collection集合的常用API.
Collection是集合的祖宗类,它的功能是全部集合都可以继承使用的,所以要学习它。
Collection API如下:
- public boolean add(E e): 把给定的对象添加到当前集合中 。
- public void clear() :清空集合中所有的元素。
- public boolean remove(E e): 把给定的对象在当前集合中删除。
- public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。
- public boolean isEmpty(): 判断当前集合是否为空。
- public int size(): 返回集合中元素的个数。
- public Object[] toArray(): 把集合中的元素,存储到数组中。
小结:
记住以上API。
*/
public class CollectionDemo {
public static void main(String[] args) {
// HashSet:添加的元素是无序,不重复,无索引。
Collection<String> c = new ArrayList<>();
// 1.添加元素, 添加成功返回true。
c.add("Java");
c.add("HTML");
System.out.println(c.add("HTML"));
c.add("MySQL");
c.add("Java");
System.out.println(c.add("黑马"));
System.out.println(c); // [Java, HTML, HTML, MySQL, Java, 黑马]
// 2.清空集合的元素。
// c.clear();
// System.out.println(c);
// 3.判断集合是否为空 是空返回true,反之。
// System.out.println(c.isEmpty());
// 4.获取集合的大小。
System.out.println(c.size());
// 5.判断集合中是否包含某个元素。
System.out.println(c.contains("Java")); // true
System.out.println(c.contains("java")); // false 精准包含
System.out.println(c.contains("黑马")); // true
// 6.删除某个元素:如果有多个重复元素默认删除前面的第一个!
System.out.println(c.remove("java")); // false
System.out.println(c);
System.out.println(c.remove("Java")); // true
System.out.println(c);
// 7.把集合转换成数组 [HTML, HTML, MySQL, Java, 黑马]
Object[] arrs = c.toArray();
System.out.println("数组:" + Arrays.toString(arrs));
System.out.println("----------------------拓展----------------------");
Collection<String> c1 = new ArrayList<>();
c1.add("java1");
c1.add("java2");
Collection<String> c2 = new ArrayList<>();
c2.add("赵敏");
c2.add("殷素素");
// addAll把c2集合的元素全部倒入到c1中去。
c1.addAll(c2);
System.out.println(c1); // [java1,java2,赵敏,殷素素]
System.out.println(c2); // [赵敏,殷素素]
}
}
4.Collection集合的遍历方式(掌握)
4.1 方式一:迭代器
-
迭代器遍历概述
- 遍历就是一个一个的把容器中的元素访问一遍。
- 迭代器在Java中的代表是Iterator,迭代器是集合的专用遍历方式。
-
为什么开发中要遍历?
- 开发中经常要统计元素的总和,找最值,找出某个数据然后干掉等等业务都需要遍历。
-
Collection集合获取迭代器
-
Iterator中的常用方法
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
目标:Collection集合的遍历方式。
a.迭代器遍历集合。
-- 方法:
public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的
boolean hasNext():判断是否有下一个元素,有返回true ,反之。
E next():获取下一个元素值!
--流程:
1.先获取当前集合的迭代器
Iterator<String> it = lists.iterator();
2.定义一个while循环,问一次取一次。
通过it.hasNext()询问是否有下一个元素,有就通过
it.next()取出下一个元素。
小结:
记住代码。
*/
public class CollectionDemo01 {
public static void main(String[] args) {
Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("素素");
lists.add("灭绝");
System.out.println(lists);
// [赵敏, 小昭, 素素, 灭绝]
// it
// 1、得到当前集合的迭代器对象。
Iterator<String> it = lists.iterator();
// String ele = it.next();
// System.out.println(ele); //赵敏
// System.out.println(it.next()); //小昭
// System.out.println(it.next()); //素素
// System.out.println(it.next()); //灭绝
// System.out.println(it.next()); // 再来无元素了!会报NoSuchElementException 出现无此元素异常的错误
// 2、定义while循环-遍历
while (it.hasNext()){ // hasNext() 表示询问有无元素,有则进入
String ele = it.next();
System.out.println(ele);
// 循环遍历时,最好每问一次,取一次即可,不要在循环遍历里取两次,奇数次对象元素时取值会出崩
}
System.out.println("-----------------------------");
}
}
- 迭代器执行流程
4.2 方式二:foreach/增强for循环
-
增强for循环
for(元素数据类型 变量名 : 数组或者Collection集合) { //在此处使用变量即可,该变量就是元素 }
-
增强for循环:既可以遍历集合也可以遍历数组
-
它是JDK5之后出现的,其内部原理是一个Iterator迭代器,遍历集合相当于迭代器的简化写法。
-
实现Iterable接口的类才可以使用迭代器和增强for,Collection接口已经实现了Iterable接口。
-
增强for修改变量[无变化,修改只是变量值,集合里面的值并不会改变]
/**
目标:Collection集合的遍历方式。
b.foreach(增强for循环)遍历集合。
foreach是一种遍历形式,可以遍历集合或者数组。
foreach遍历集合实际上是迭代器遍历集合的简化写法。
foreach遍历的关键是记住格式:
for(被遍历集合或者数组中元素的类型 变量名称 : 被遍历集合或者数组){
}
*/
public class CollectionDemo02 {
public static void main(String[] args) {
Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("殷素素");
lists.add("周芷若");
System.out.println(lists);
// [赵敏, 小昭, 殷素素, 周芷若]
// ele
for (String ele : lists) {
System.out.println(ele);
}
System.out.println("------------------");
double[] scores = {100, 99.5 , 59.5};
for (double score : scores) {
System.out.println(score);
// if(score == 59.5){
// score = 100.0; // 修改无意义,不会影响数组的元素值。
// }
}
System.out.println(Arrays.toString(scores));
}
}
4.3 方式三:lambda表达式
-
Lambda表达式遍历集合
- 得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。
-
Collection结合Lambda遍历的API
-
主要是通过调用集合的foreach方法,里面是匿名对象,通过源码进行遍历。而这个对象可以简化成Lambda形式。
5.Collection集合存储自定义类型的对象
- 电影类 Movies.java
public class Movie {
private String name;
private double score;
private String actor;
public Movie() {
}
public Movie(String name, double score, String actor) {
this.name = name;
this.score = score;
this.actor = actor;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public String getActor() {
return actor;
}
public void setActor(String actor) {
this.actor = actor;
}
@Override
public String toString() {
return "Movie{" +
"name='" + name + '\'' +
", score=" + score +
", actor='" + actor + '\'' +
'}';
}
}
- 实现类
import java.util.ArrayList;
import java.util.Collection;
public class TestDemo {
public static void main(String[] args) {
// 1、定义一个电影类
// 2、定义一个集合对象存储3部电影对象
Collection<Movie> movies = new ArrayList<>();
movies.add(new Movie("《你好,李焕英》", 9.5, "张小斐,贾玲,沈腾,陈赫"));
movies.add(new Movie("《唐人街探案》", 8.5, "王宝强,刘昊然,美女"));
movies.add(new Movie("《刺杀小说家》",8.6, "雷佳音,杨幂"));
System.out.println(movies); // 地址 因为重写了电影类的tostring,打印地址全部打印对象内容,但不影响里面存的还是地址!!!
// 3、遍历集合容器中的每个电影对象
for (Movie movie : movies) {
System.out.println("片名:" + movie.getName());
System.out.println("得分:" + movie.getScore());
System.out.println("主演:" + movie.getActor());
}
}
}
6.List系列集合(掌握)
6.1 List集合特点、特有API
-
Collection集合体系
-
List系列集合特点
- ArrayList、LinekdList :有序,可重复,有索引。
- 有序:存储和取出的元素顺序一致
- 有索引:可以通过索引操作元素
- 可重复:存储的元素可以重复
-
List集合特有方法
- List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了。
- List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了。
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
/**
目标:ArrayList集合。
Collection集合的体系
Collection<E>(接口)
/ \
Set<E>(接口) List<E>(接口)
/ \ / \ \
HashSet<E>(实现类) TreeSet<E>(实现类) LinkedList<E>(实现类) Vector(线程安全) ArrayList<E>(实现类)
/
LinkedHashSet<E>(实现类)
Collection集合体系的特点:
Set系列集合: 添加的元素,是无序,不重复,无索引的。
-- HashSet:添加的元素,是无序,不重复,无索引的。
-- LinkedHashSet:添加的元素,是有序,不重复,无索引的。
List系列集合:添加的元素,是有序,可重复,有索引的。
-- LinkedList: 添加的元素,是有序,可重复,有索引的。
-- ArrayList: 添加的元素,是有序,可重复,有索引的。
-- Vector 是线程安全的,速度慢,工作中很少使用。
1、List集合继承了Collection集合的全部功能,"同时因为List系列集合有索引",
2、因为List集合多了索引,所以多了很多按照索引操作元素的功能:
3、ArrayList实现类集合底层基于数组存储数据的,查询快,增删慢!
- public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
- public E get(int index):返回集合中指定位置的元素。
- public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
- public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回更新前的元素值。
小结:
ArrayList集合的底层是基于数组存储数据。查询快,增删慢!(相对的)
*/
public class ListDemo01 {
public static void main(String[] args) {
// 1.创建一个ArrayList集合对象:
// List:有序,可重复,有索引的。
List<String> list = new ArrayList<>(); // 一行经典代码!
list.add("Java");
list.add("Java");
list.add("MySQL");
list.add("MySQL");
// 2.在某个索引位置插入元素。
list.add(2, "HTML");
System.out.println(list); //[Java,Java,HTML,MySQL,MySQL]
// 3.根据索引删除元素,返回被删除元素
System.out.println(list.remove(2)); //HTML
System.out.println(list); //[Java,Java,MySQL,MySQL]
// 4.根据索引获取元素:public E get(int index):返回集合中指定位置的元素。
System.out.println(list.get(1)); // Java
// 5.修改索引位置处的元素: public E set(int index, E element)
System.out.println(list.set(1, "even")); //返回修改前的数据 Java
System.out.println(list); //[Java,even,MySQL,MySQL]
}
}
6.2 List集合的遍历方式小结
- List集合的遍历方式有几种?
- 迭代器
- 增强for循环
- Lambda表达式
- for循环(因为List集合存在索引)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
拓展:List系列集合的遍历方式有:4种。
List系列集合多了索引,所以多了一种按照索引遍历集合的for循环。
List遍历方式:
(1)for循环。(独有的,因为List有索引)。
(2)迭代器。
(3)foreach。
(4)JDK 1.8新技术。
*/
public class ListDemo02 {
public static void main(String[] args) {
List<String> lists = new ArrayList<>();
lists.add("java1");
lists.add("java2");
lists.add("java3");
/** (1)for循环。 */
System.out.println("-----------------------");
for (int i = 0; i < lists.size(); i++) {
String ele = lists.get(i);
System.out.println(ele);
}
/** (2)迭代器。 */
System.out.println("-----------------------");
Iterator<String> it = lists.iterator();
while (it.hasNext()){
String ele = it.next();
System.out.println(ele);
}
/** (3)foreach */
System.out.println("-----------------------");
for (String ele : lists) {
System.out.println(ele);
}
/** (4)JDK 1.8开始之后的Lambda表达式 */
System.out.println("-----------------------");
lists.forEach(s -> {
System.out.println(s);
});
}
}
6.3 ArrayList集合的底层原理
-
Collection集合体系
-
ArrayList集合底层原理
-
ArrayList底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。
-
第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。
List<String> list = new ArrayList<>(); list.add("a");
-
- 底层原理总结:
- 在第一次分配长度为10的数组,然后往里加元素,用size记录当前集合中的个数,也是下一个插入的位置。
- 一旦元素超过10,也就是size到了索引10这个位置,即元素存满了,会按照1.5倍扩容,把元素重新迁移出来。
6.4 LinkedList集合的底层原理
-
LinkedList的特点
- 底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API。
-
LinkedList集合的特有功能
import java.util.LinkedList;
import java.util.List;
/**
目标:LinkedList集合。
LinkedList也是List的实现类:底层是基于双链表的,增删比较快,查询慢!!
LinkedList是支持双链表,定位前后的元素是非常快的,增删首尾的元素也是最快的
所以LinkedList除了拥有List集合的全部功能还多了很多操作首尾元素的特殊功能:
- public void addFirst(E e):将指定元素插入此列表的开头。
- public void addLast(E e):将指定元素添加到此列表的结尾。
- public E getFirst():返回此列表的第一个元素。
- public E getLast():返回此列表的最后一个元素。
- public E removeFirst():移除并返回此列表的第一个元素。
- public E removeLast():移除并返回此列表的最后一个元素。
- public E pop():从此列表所表示的堆栈处弹出一个元素。
- public void push(E e):将元素推入此列表所表示的堆栈。
小结:
LinkedList是支持双链表,定位前后的元素是非常快的,增删首尾的元素也是最快的。
所以提供了很多操作首尾元素的特殊API可的实以做栈和队列现。
如果查询多而增删少用ArrayList集合。(用的最多的)
如果查询少而增删首尾较多用LinkedList集合。
*/
public class ListDemo03 {
public static void main(String[] args) {
// LinkedList可以完成队列结构,和栈结构 (双链表)
// 1、做一个队列:
LinkedList<String> queue = new LinkedList<>(); //这里没用多态是因为要用它的独有功能
// 入队
queue.addLast("1号");
queue.addLast("2号");
queue.addLast("3号");
System.out.println(queue); //[1号,2号,3号]
// 出队
// System.out.println(queue.getFirst()); // 1号
System.out.println(queue.removeFirst()); //[2号,3号]
System.out.println(queue.removeFirst());
System.out.println(queue);
// 2、做一个栈
LinkedList<String> stack = new LinkedList<>();
// 入栈 压栈 (push) push()就是addFirst()
stack.push("第1颗子弹");
stack.push("第2颗子弹");
stack.push("第3颗子弹");
stack.push("第4颗子弹");
System.out.println(stack);// [第4颗子弹,第3颗子弹,第2颗子弹,第1颗子弹]
// 出栈 弹栈 pop()就是removeFirst()
// System.out.println(stack.getFirst()); // 第4颗子弹 但栈里内容并不做任何变动
System.out.println(stack.removeFirst()); // 删除并取出 [第3颗子弹,第2颗子弹,第1颗子弹]
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack.pop());
System.out.println(stack);
}
}
7.补充知识:集合的并发修改异常问题(重要)
- 问题引出
- 当我们从集合中找出某个元素并删除的时候可能出现一种并发修改异常问题。
- 哪些遍历存在问题?
- 迭代器遍历集合且直接用集合删除元素的时候可能出现。
- 增强for循环遍历集合且直接用集合删除元素的时候可能出现。
- 哪种遍历且删除元素不出问题
- 迭代器遍历集合但是用迭代器自己的删除方法操作可以解决。
- 使用for循环遍历并删除元素不会存在这个问题。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
目标:研究集合遍历并删除元素可能出现的:并发修改异常问题。
*/
public class Test {
public static void main(String[] args) {
// 1、准备数据
ArrayList<String> list = new ArrayList<>();
list.add("黑马");
list.add("Java");
list.add("Java");
list.add("赵敏");
list.add("赵敏");
list.add("素素");
System.out.println(list);
// [黑马, Java, Java, 赵敏, 赵敏, 素素]
// it
// 需求:删除全部的Java信息。
// a、迭代器遍历删除(使用迭代器删除当前位置的元素,保证不后移,能够成功遍历到全部元素)
Iterator<String> it = list.iterator();
// while (it.hasNext()){
// String ele = it.next();
// if("Java".equals(ele)){
// // 删除Java
// // list.remove(ele); // 集合删除会出毛病
// it.remove(); // 删除迭代器所在位置的元素值(没毛病)
// }
// }
// System.out.println(list);
// b、foreach遍历删除 (会出现问题,这种无法解决的!!foreach不能边遍历边删除,会出bug)
// for (String s : list) {
// if("Java".equals(s)){
// list.remove(s);
// }
// }
// c、lambda表达式(会出现问题,这种无法解决的!!!Lambda遍历不能边遍历边删除,会出bug)
// list.forEach(s -> {
// if("Java".equals(s)){
// list.remove(s);
// }
// });
// d、for循环(边遍历边删除集合没毛病,但是必须从后面开始遍历删除才不会出现漏掉应该删除的元素!!如果不这样并不会出现异常错误,但是数据删除会出现问题,会漏删)
for (int i = list.size() - 1; i >= 0 ; i--) {
String ele = list.get(i);
if("Java".equals(ele)){
list.remove(ele);
}
}
// e.for循环(不用上述的从后往前的删,直接i--)
for (int i = 0; i < list.size() ; i++) {
String ele = list.get(i);
if("Java".equals(ele)){
list.remove(ele);
i--;
}
}
System.out.println(list);
}
}
8.补充知识:泛型深入(理解)
8.1 泛型的概述和优势
- 泛型概述
- 泛型:是JDK5中引入的特性,可以在编译阶段约束操作的数据类型,并进行检查。
- 泛型的格式:<数据类型>; 注意:泛型只能支持引用数据类型。
- 集合体系的全部接口和实现类都是支持泛型的使用的。
- 泛型的好处
- 统一数据类型。
- 把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为编译阶段类型就能确定下来。
8.2 自定义泛型类
-
泛型类的概述
- 定义类时同时定义了泛型的类就是泛型类。
- 泛型类的格式:修饰符 class 类名<泛型变量>{ }
范例:public class MyArrayList<T> { }
- 此处泛型变量==T可以随便写为任意标识,常见的如E、T、K、V==等。
- 作用:编译阶段可以指定数据类型,类似于集合的作用。
-
课程案例导学
- 模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可。
import java.util.ArrayList; public class MyArrayList<E> { private ArrayList lists = new ArrayList(); public void add(E e){ lists.add(e); } public void remove(E e){ lists.remove(e); } @Override public String toString() { return lists.toString(); } }
public class Test { public static void main(String[] args) { // 需求:模拟ArrayList定义一个MyArrayList ,关注泛型设计 MyArrayList<String> list = new MyArrayList<>(); list.add("Java"); list.add("Java"); list.add("MySQL"); list.remove("MySQL"); System.out.println(list); MyArrayList<Integer> list2 = new MyArrayList<>(); list2.add(23); list2.add(24); list2.add(25); list2.remove(25); System.out.println(list2); } }
- 模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可。
-
泛型类的原理:
- 把出现泛型变量的地方全部替换成传输的真实数据类型。
8.3 自定义泛型方法
-
泛型方法的概述
- 定义方法时同时定义了泛型的方法就是泛型方法。
- 泛型方法的格式:修饰符 <泛型变量> 方法返回值 方法名称(形参列表){}
范例: public <T> void show(T t) { }
-
作用:方法中可以使用泛型接收一切实际类型的参数,方法更具备通用性。
-
课程案例导学
- 给你任何一个类型的数组,都能返回它的内容。也就是实现Arrays.toString(数组)的功能!
/** 目标:自定义泛型方法。 需求:给你任何一个类型的数组,都能返回它的内容。Arrays.toString(数组)的功能! 小结: 泛型方法可以让方法更灵活的接收数据,可以做通用技术! */ public class GenericDemo { public static void main(String[] args) { String[] names = {"小璐", "蓉容", "小何"}; printArray(names); Integer[] ages = {10, 20, 30}; printArray(ages); Integer[] ages2 = getArr(ages); String[] names2 = getArr(names); } public static <T> T[] getArr(T[] arr){ return arr; } public static <T> void printArray(T[] arr){ //表示接收一切类型数组 if(arr != null){ StringBuilder sb = new StringBuilder("["); for (int i = 0; i < arr.length; i++) { sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", "); } sb.append("]"); System.out.println(sb); }else { System.out.println(arr); } } }
- 给你任何一个类型的数组,都能返回它的内容。也就是实现Arrays.toString(数组)的功能!
-
泛型方法的原理:
- 把出现泛型变量的地方全部替换成传输的真实数据类型。
8.4 自定义泛型接口
-
泛型接口的概述
- 使用了泛型定义的接口就是泛型接口。
- 泛型接口的格式:修饰符 interface 接口名称<泛型变量>{}
范例: public interface Data<E>{}
-
作用:泛型接口可以让实现类选择当前功能需要操作的数据类型
-
课程案例导学
- 教务系统,提供一个接口可约束一定要完成数据(学生,老师)的增删改查操作
- 教务系统,提供一个接口可约束一定要完成数据(学生,老师)的增删改查操作
-
泛型接口的原理:
- 实现类可以在实现接口的时候传入自己操作的数据类型,这样重写的方法都将是针对于该类型的操作。
8.5 泛型通配符、上下限
- 通配符:?
-
? 可以在“使用泛型”的时候代表一切类型。
-
E T K V 是在定义泛型的时候使用的。
-
- 泛型的上下限:
- == ? extends Car: ?==必须是Car或者其子类 泛型上限
- == ? super Car : ?==必须是Car或者其父类 泛型下限
- 泛型通配符:案例导学
- 开发一个极品飞车的游戏,所有的汽车都能一起参与比赛。
- 注意:
- 虽然BMW和BENZ都继承了Car但是ArrayList< BMW >和ArrayList< BENZ >与ArrayList< Car >没有关系的!!
- 虽然BMW和BENZ都继承了Car但是ArrayList< BMW >和ArrayList< BENZ >与ArrayList< Car >没有关系的!!