Collection:存储一组对象
Map:存储一组键值对(key,value),键值对又称为映射关系。
List:有序(可以按照索引操作),可重复
Set:无序(不能按照索引操作),不可重复
HashSet:散列无规律
LinkedHashSet:按照元素添加的顺序排列
TreeSet:按照元素的大小顺序排列
关于底层,后面讲Map再细说
1、添加
2、删除
3、查询/查看
4、遍历方式
不要对当前集合调用集合的add,remove等方法,进行元素个数的修改。
调用迭代器的remove方法。
不能。
不能。
结论:foreach里面,针对当前集合的add,remove等都是无法操作。
除了从Collection接口继承的方法之外,List还扩展了哪些方法?
1、添加
add(int index, Object obj):指定位置添加一个元素。
addAll(int index, Collection c):指定位置添加一组元素。
2、删除
remove(int index):删除指定位置的元素。
3、查询
Object get(int index):返回index位置的元素
List subList(int start, int end):截取[start, end)位置的一组元素
int indexOf(Object obj):返回首次出现的索引值。不存在返回-1。
int lastIndexOf(Object obj):返回末次出现的索引值。不存在返回-1。
4、修改
set(int index, Object obj):替换[index]位置的元素
replaceAll(UnarayOperator u):要重写UnarayOperator 接口的apply方法,方法的参数是元素的原值,方法的返回值是元素的新值。
boolean equals(Object obj):比较两个对象是不是相等。怎么比较?
int hashCode():计算对象的身份证号
hashCode方法重写有一些要求?
重写equals方法有什么要求吗?
package com.atguigu.list;
import org.junit.Test;
public class TestEmployee {
@Test
public void test1()throws Exception{
//手动重写equals或hashCode方法的问题,这里只演示equals方法。
//需求:如下3个对象,我希望比较equals都相同
Employee e1 = new Employee(1,"张三","男");//编号,姓名,性别
Employee e2 = new Employee(1,"张三","man");
Employee e3 = new Employee(1,"张三","Man");
System.out.println(e1.equals(e2));
System.out.println(e1.equals(e3));
System.out.println(e2.equals(e3));
System.out.println(e1);
System.out.println(e2);
System.out.println(e3);
}
}
package com.atguigu.list;
import java.util.Objects;
public class Employee {
private int id;
private String name;
private String gender;
public Employee(int id, String name, String gender) {
this.id = id;
this.name = name;
this.gender = gender;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", gender='" + gender + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
if (id != employee.id) return false;
if (!Objects.equals(name, employee.name)) return false;
// return Objects.equals(gender, employee.gender);
return equalsGender(gender, employee.gender);
}
private boolean equalsGender(String gender1, String gender2){
if(gender1 == gender2){
return true;
}
if(gender1!=null && gender1.equals("男")){
gender1 = "man";
}
if(gender2!=null && gender2.equals("男")){
gender2 ="man";
}
return gender1.equalsIgnoreCase(gender2);//不区分大小写比较两个单词
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (gender != null ? gender.hashCode() : 0);
return result;
}
}
ListIterator也是一种迭代器,它是Iterator接口的子接口,而且是专门用于List系列的集合的迭代器。
List系列的集合.listIterator()可以获取ListIterator的对象。一开始迭代器在[0]位置。
List系列的集合.listIterator(int index)也可以获取ListIterator的对象。一开始迭代器在[index]位置。
Iterator接口有的方法,ListIterator也有。(因为会继承过来)
ListIterator接口又扩展了一些方法:
获取元素的下标
遍历的方向
支持的操作
package com.atguigu.list;
import org.junit.Test;
import java.util.ArrayList;
import java.util.ListIterator;
public class TestListIterator {
@Test
public void test1()throws Exception{
ArrayList list = new ArrayList();
list.add("hello");
list.add("world");
list.add("java");
ListIterator listIterator = list.listIterator();//返回的是ListIterator接口的实现类的对象
//从左往右遍历
while(listIterator.hasNext()){
int index = listIterator.nextIndex();//迭代器当前指向的元素的下标
int preIndex = listIterator.previousIndex();
Object obj = listIterator.next();
System.out.println("前一个元素的下标:" + preIndex);
System.out.println("当前元素下标:" + index + ":" + obj);
}
}
@Test
public void test2()throws Exception{
ArrayList list = new ArrayList();
list.add("hello");
list.add("world");
list.add("java");
// ListIterator listIterator = list.listIterator();//迭代器一开始在[0]位置
ListIterator listIterator = list.listIterator(list.size());//迭代器一开始在[list.size()]位置
//这里size=3,迭代器在[3]的位置
//从右往左遍历
while(listIterator.hasPrevious()){
int index = listIterator.previousIndex();
Object obj = listIterator.previous();
System.out.println("前一个元素的下标:" + index);
System.out.println("前一个元素:" + obj);
}
}
@Test
public void test3()throws Exception{
ArrayList list = new ArrayList();
list.add("hello");
list.add("world");
list.add("java");
//需求:在hello后面添加一个atguigu
/*
方式一:不用迭代器
*/
/*int index = list.indexOf("hello");//查询hello的位置
list.add(index + 1,"atguigu");//在hello的后面添加新元素atguigu
System.out.println(list);*/
/*
方式二:使用ListIterator迭代器
*/
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
Object obj = listIterator.next();
if("hello".equals(obj)){
listIterator.add("atguigu");
}
}
System.out.println(list);
}
@Test
public void test4()throws Exception {
ArrayList list = new ArrayList();
list.add("hello");
list.add("haha");
list.add("world");
list.add("java");
//需求:在hello的前面添加atguigu
/*
方式一:不用迭代器
*/
/* int index = list.indexOf("hello");//查询hello的位置
list.add(index ,"atguigu");//在hello的前面添加新元素atguigu,插入到hello原来的位置,然后自动把hello及其后面的元素右移
System.out.println(list);*/
/*
方式二:使用ListIterator迭代器
*/
ListIterator listIterator = list.listIterator(list.size());
while(listIterator.hasPrevious()){
Object obj = listIterator.previous();
if("hello".equals(obj)){
listIterator.add("atguigu");
}
}
System.out.println(list);
}
@Test
public void test5()throws Exception{
ArrayList list = new ArrayList();
list.add("hello");
list.add("haha");
list.add("world");
list.add("java");
//Hello,Haha,World,Java
//需求:把所有单词的首字母改为大写
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
Object obj = listIterator.next();
String str = (String) obj;
char first = str.charAt(0);
first = Character.toUpperCase(first);
String after = str.substring(1);//从[1]到最后
listIterator.set(first + after);//替换原来的元素
}
System.out.println(list);
}
}
详细请看
package com.atguigu.list;
import org.junit.Test;
import java.util.*;
public class TestListImpl {
@Test
public void test1()throws Exception{
//演示栈类型Stack
Stack stack = new Stack();
//它自己扩展的方法,为了体现它和列表的不同,突然栈的特点
stack.push("hello");//压栈
stack.push("world");
stack.push("java");
System.out.println(stack.pop());//弹出栈 java
System.out.println(stack.pop());//world
System.out.println(stack.pop());//hello
System.out.println(stack.pop());//java.util.EmptyStackException 空栈异常
}
@Test
public void test2()throws Exception {
//演示栈类型Stack
Stack stack = new Stack();
//它自己扩展的方法,为了体现它和列表的不同,突然栈的特点
stack.push("hello");//压栈
stack.push("world");
stack.push("java");
while(!stack.empty()){//非空判断
System.out.println(stack.pop());
}
}
@Test
public void test3()throws Exception{
//演示栈类型Stack
Stack stack = new Stack();
//它自己扩展的方法,为了体现它和列表的不同,突然栈的特点
stack.push("hello");//压栈
stack.push("world");
stack.push("java");
System.out.println(stack.peek());//peek偷偷看一眼,现在栈顶是谁,不敢拿
System.out.println(stack.peek());
System.out.println(stack.peek());
System.out.println(stack.peek());
}
@Test
public void test4()throws Exception{
//演示ArrayList 用作栈使用
ArrayList list = new ArrayList();
//关键点:要实现先进后出的效果
list.add("hello");
list.add("world");
list.add("java");
list.add("atguigu");
//出来的顺序:atguigu,java,world,hello 取走
while(list.size()>0){//有元素可取
System.out.println(list.remove(list.size()-1));
//list.size()-1是列表中最后一个元素的索引
}
System.out.println(list);//空的
}
@Test
public void test5()throws Exception{
//演示Queue接口的使用
Queue queue = new LinkedList();//这么写是希望大家知道它们的关系
queue.add("hello");
queue.add("world");
queue.add("java");
queue.add("atguigu");
//出来的顺序:hello,world,java,atguigu
System.out.println(queue.element());//hello 偷偷查看第一个元素,队头,谁带头
System.out.println(queue.element());//hello
System.out.println(queue.element());//hello
//关键点:先进先出
while(!queue.isEmpty()){//非空判断
System.out.println(queue.remove());
}
System.out.println(queue);//空的
}
@Test
public void test6()throws Exception{
Queue queue = new LinkedList();
// System.out.println(queue.element());//java.util.NoSuchElementException
System.out.println(queue.remove());//java.util.NoSuchElementException
}
@Test
public void test7()throws Exception{
Queue queue = new LinkedList();
System.out.println(queue.peek());//null
System.out.println(queue.poll());//null
}
@Test
public void test8()throws Exception{
//双端队列
Deque deque = new LinkedList();
//关键词:两头都可以进、出
deque.addFirst("hello");
deque.addLast("world");
deque.addFirst("world");
deque.addFirst("atguigu");
deque.addLast("chai");
//顺序:左边是first的话 atguigu,world,hello,world,chai
System.out.println(deque);
System.out.println(deque.removeLast());//chai
System.out.println(deque.removeFirst());//atguigu
}
}
泛型:泛指某个类型,代码中看到、、等都是和泛型有关的。
JDK1.5引入的泛型。
为了解决:
泛型带来的好处:
package com.atguigu.generic;
import org.junit.Test;
import java.util.ArrayList;
public class TestGeneric {
@Test
public void test1NoGeneric()throws Exception{
ArrayList list = new ArrayList();
list.add("hello");
list.add("java");
list.add("world");
list.add("atguigu");
//需求:输出元素,并且求字符串元素的长度
for (Object o : list) {
String str = (String) o;
System.out.println(str+"的长度:" + str.length());
}
}
@Test
public void test1UseGeneric()throws Exception{
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("java");
list.add("world");
list.add("atguigu");
//快捷键iter
for (String str : list) {//避免的向下转型
System.out.println(str+"的长度:" + str.length());
}
}
@Test
public void test2NoGeneric()throws Exception{
//给list添加元素,但是只能添加String,不能添加其他类型的对象
ArrayList list = new ArrayList();
list.add("hello");
list.add("java");
list.add("world");
list.add(1);//编译器不给提示,它不满足我们的要求
for (Object o : list) {
if(o instanceof String) {
String str = (String) o;
System.out.println(str + "的长度:" + str.length());
}
}
}
@Test
public void test2UseGeneric()throws Exception{
//给list添加元素,但是只能添加String,不能添加其他类型的对象
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("java");
list.add("world");
// list.add(1);//编译器立刻给出提示,它不满足我们的要求
}
}
泛型可以在两个位置定义和使用?
java.lang.Comparable:自然比较接口,它有一个抽象方法:int compareTo(T o),这里的T代表要比较大小的对象类型,T代表Type
java.util.Comparator:定制比较器接口,它也有一个抽象方法:int compare(T o1,T o2) ,这里的T代表要比较大小的对象类型
java.util.Collection:Collection集合根接口,这里的E代表的是集合元素的类型,E代表element元素
java.util.List、Set、Queue、Deque等子接口。
java.lang.Iterable:可迭代的接口
java.util.Iterator:迭代器接口
java.util.ArrayList、Vector、LinkedList、Stack:List系列集合类型
java.util.HashSet、LinkedHashSet、TreeSet:Set系列集合的类型。
如果一个类或接口名后面声明(定义)了泛型,那么使用该类或接口时,最好指定该泛型的具体类型,否则会有警告。
注意:
package com.atguigu.generic;
import org.junit.Test;
import java.util.ArrayList;
public class TestUseGenericClass {
@Test
public void test1()throws Exception{
//ArrayList,这里代表的是元素的类型
//存储整数
// ArrayList list = new ArrayList();//不支持基本数据类型
ArrayList<Integer> list = new ArrayList<Integer>();//只支持基本数据类型
list.add(1);
// list.add(1.0);//报错,它们都不能自动转为Integer对象
// list.add("hello");//报错,它们都不能自动转为Integer对象
}
@Test
public void test2()throws Exception{
//存储小数
ArrayList<Double> list = new ArrayList<Double>();
// list.add(1);//错误,1是int类型,它可以自动转为double(自动类型提升),但是不能自动转为Double(自动装箱)
list.add(1.0);
list.add((double)1);
list.add(1d);//在数字后面加d或D表示double
}
}
package com.atguigu.generic;
/*
需求:要求员工类Employee实现Comparable接口
T是Type单词的缩写,是要比较大小的对象的类型,
这里是两个员工对象要比较大小,T是Employee类型
员工对象默认按照id比较大小
*/
public class Employee implements Comparable<Employee>{
private int id;
private String name;
private double salary;
public Employee() {
}
public Employee(int id, String name, double salary) {
this.id = id;
this.name = name;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", name='" + name + '\'' +
", salary=" + salary +
'}';
}
@Override
public int compareTo(Employee o) {
return id - o.id;
}
}
package com.atguigu.generic;
import java.util.Comparator;
/*
需求:定制一个比较器,用于比较两个员工对象的大小,
要求:先按照薪资比较大小,如果薪资相同,再按照编号比较大小
实现Comparator接口,这里的T代表要比较大小的对象的类型,这里是员工类
*/
public class EmployeeSalaryComparator implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
// return o1.getSalary() - o2.getSalary();//double - double,结果是double,返回值类型是int
// return (int)(o1.getSalary() - o2.getSalary());//语法上没毛病, 15000.56 15000.42 看业务层面是否允许这样误差
/* if(o1.getSalary() > o2.getSalary()){
return 1;
}else if(o1.getSalary() < o2.getSalary()){
return -1;
}else{
return o1.getId() - o2.getId();
}*/
int result = Double.compare(o1.getSalary(), o2.getSalary());
//如果o1.getSalary() 大于 o2.getSalary(),该方法结果返回正整数
//如果o1.getSalary() 小于 o2.getSalary(),该方法结果返回负整数
//如果o1.getSalary() 等于 o2.getSalary(),该方法结果返回零
/*
Integer.compare(o1.getId(),o2.getId())比较两个int值,
//如果o1.getId() 大于 o2.getId(),该方法结果返回正整数
//如果o1.getId() 小于 o2.getId(),该方法结果返回负整数
//如果o1.getId() 等于 o2.getId(),该方法结果返回零
等价于 o1.getId() - o2.getId()
*/
return result == 0 ? Integer.compare(o1.getId(),o2.getId()): result;
}
}
package com.atguigu.generic;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.function.Predicate;
public class TestGenericInterface {
@Test
public void test1()throws Exception{
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
list.add("atguigu");
//需求:使用Iterator遍历集合的元素
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String str = iterator.next();
System.out.println(str);
}
}
@Test
public void test2()throws Exception{
//根据条件删除元素
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
list.add("atguigu");
//需求:删除包含o字母的元素
/*
方式一:removeIf
*/
list.removeIf(new Predicate<String>() {
@Override
public boolean test(String s) {
return s.contains("o");
}
});
System.out.println(list);
}
@Test
public void test3()throws Exception{
//根据条件删除元素
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
list.add("atguigu");
//需求:删除包含o字母的元素
/*
方式二:迭代器删除
*/
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
String str = iterator.next();
if(str.contains("o")){
iterator.remove();
}
}
System.out.println(list);
}
}
【修饰符】 class 类名<泛型字母列表>{
}
【修饰符】 interface 接口名<泛型字母列表>{
}
注意:
需求:
声明一个泛型类Coordinate坐标,坐标类中应该包含两个属性,分别是x和y,代表经度和维度值。
这里的x和y的类型不确定,可能是Integer,Double,String等。
package com.atguigu.generic;
/*
声明一个泛型类Coordinate坐标,坐标类中应该包含两个属性,分别是x和y,代表经度和维度值。
这里的x和y的类型不确定,可能是Integer,Double,String等。
*/
public class Coordinate<T> {
private T x;
private T y;
//同一个对象的x,y的类型一定相同
/*public static void method(T t){//在类名后面定义的泛型,不能用于静态成员
//因为类名后面的泛型T,要确定具体类型,通常在new对象时,而静态方法和对象无关。
}*/
public Coordinate() {
}
public Coordinate(T x, T y) {
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
@Override
public String toString() {
return "Coordinate{" +
"x=" + x +
", y=" + y +
'}';
}
}
package com.atguigu.generic;
//T,U代表任意类型
public class ZuoBiao<T,U> {
private T x;
private U y;
//同一个对象的x,y可能类型不同,也可能相同
public ZuoBiao() {
}
public ZuoBiao(T x, U y) {
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public U getY() {
return y;
}
public void setY(U y) {
this.y = y;
}
@Override
public String toString() {
return "ZuoBiao{" +
"x=" + x +
", y=" + y +
'}';
}
}
package com.atguigu.generic;
import org.junit.Test;
public class TestCoordinate {
@Test
public void test1()throws Exception{
//创建坐标类的对象
/* Coordinate c1 = new Coordinate("东经35.6","北纬25.6");
Coordinate c2 = new Coordinate(35.6,25.6);*/
//从JDK1.7开始,左边写了<>中的类型,右边可以省略,但是<>不要省略
Coordinate<String> c1 = new Coordinate<>("东经35.6","北纬25.6");
//c1对象的x,y都是String类型
Coordinate<Double> c2 = new Coordinate<>(35.6,25.6);
//c1对象的x,y都是Double
System.out.println(c1);
System.out.println(c2);
}
@Test
public void test2()throws Exception{
//x是String,y是Double
ZuoBiao<String,Double> z1 = new ZuoBiao<>("东经35.6",25.6);
//z1对象的x,y分别是String和Double
ZuoBiao<String,String> z2 = new ZuoBiao<>("东经35.6","北纬25.6");
//z2对象的x,y都是String
}
}
总结:
package com.atguigu.generic;
/*
Example:例子。
*/
public class Example<T> {
public void m1(T t){
//...
}
public void m2(T t){
//...
}
//以上写法,表示同一个对象的m1和m2方法的形参类型一定是一样的
//问题?如果希望同一个对象的m1和m2方法的形参类型不一样,怎么办?
//方式一:多定义几个字母
//方式二:每个方法单独自己定义泛型
}
package com.atguigu.generic;
public class Demo{
public <T> void m1(T t){
}
public <T> void m2(T t){
}
//以上写法,m1和m2方法的形参类型是独立
//m3的形参类型也是独立的
public static <T> void m3(T t){
}
}
java.util.Collection接口中有如下两个方法:
java.util.Arrays数组工具类中有一个这样的方法:
package com.atguigu.generic;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TestGenericMethod {
@Test
public void test1()throws Exception{
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("java");
list.add("world");
//Object[] toArray():不管元素什么类型,统一返回Object[]数组
Object[] objects = list.toArray();
//进一步遍历objects数组
for (int i = 0; i < objects.length; i++) {
String str = (String) objects[i];//还得强转,有点麻烦
}
}
@Test
public void test2()throws Exception{
ArrayList<String> list = new ArrayList<>();
list.add("hello");
list.add("java");
list.add("world");
// T[] toArray(T[] a):可以返回不同类型的数组
// String[] strings = new String[list.size()];
String[] strings = new String[0];//这里长度是多少不重要,因为集合的toArray方法中只是为了得到它的类型
System.out.println(strings.getClass());//它里面用的是这个信息,数组的类型
String[] array = list.toArray(strings);
//进一步遍历array数组
for (int i = 0; i < array.length; i++) {
System.out.println(array[i] +",长度:" + array[i].length());
}
}
@Test
public void test3()throws Exception{
List<String> stringList = Arrays.asList("hello", "java", "world");
List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5);
//顺便多说一句,asList方法返回的集合类型不是咱们上午学的ArrayList,Vector等类型,而是Arrays里面的一个内部类类型
System.out.println(stringList.getClass());//class java.util.Arrays$ArrayList
//而且这个内部类的集合,不支持添加元素,删除元素等操作
stringList.add("chai");//java.lang.UnsupportedOperationException不支持该操作异常
}
}
定义泛型时,能不能限定范围?
答案:可以,可以限定上限。
语法格式:
<T extends 上限> :这里的extends表示 T类型 <= 上限类型
子类 < 父类
实现类 < 父接口
子接口 < 父接口
<T extends 上限1 & 上限2 & 上限3>:这里&,表是要同时满足
T要同时 <= 上限1,上限2,上限3,而且相当于T同时继承或实现它们
上限1,上限2,上限3这些上限中,只能出现1个是类,其余只能是接口,而且类要在最左边,接口在后面。
需求:声明一个学生类,这个学生类与我们以往声明的学生类不一样,它的属性有姓名和成绩,但是这个成绩,可能是Integer,Double,BigInteger等数字类型,但是不能是String等其他类型。
package com.atguigu.generic;
/*
需求:声明一个学生类,这个学生类与我们以往声明的学生类不一样,它的属性有姓名和成绩,
但是这个成绩,可能是Integer,Double,BigInteger等数字类型,但是不能是String等其他类型。
*/
public class Student <T extends Number>{
private String name;
private T score;
public Student() {
}
public Student(String name, T score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getScore() {
return score;
}
public void setScore(T score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", score=" + score +
'}';
}
}
package com.atguigu.generic;
import org.junit.Test;
import java.util.ArrayList;
public class TestStudent {
@Test
public void test1()throws Exception{
Student<Integer> s1 = new Student<>();
Student<Double> s2 = new Student<>();
// Student s3 = new Student<>();//报错,因为String不满足 String <= Number条件
}
}
package com.atguigu.generic;
/*
需求:声明一个学生类,这个学生类与我们以往声明的学生类不一样,它的属性有姓名和成绩,
但是这个成绩,可能是Integer,Double,BigInteger等数字类型,但是不能是String等其他类型。
同时成绩的类型,必须实现Comparable接口,Cloneable接口等
*/
public class XueSheng <T extends Number & Comparable & Cloneable>{
}
package com.atguigu.generic;
import org.junit.Test;
public class TestXueSheng {
@Test
public void test1()throws Exception{
// XueSheng x = new XueSheng();
//错误,因为Integer没有实现Cloneable接口
}
}
泛型的擦除:一个泛型类或泛型接口在使用时,不去指定它的泛型,就称为泛型擦除。
泛型擦除后,泛型按什么类型处理呢?
如果泛型擦除了,默认按照第一个上限处理,如果没有指定上限,上限就是Object。
@Test
public void test2()throws Exception{
//Student,本来应该指定T的类型,现在不指定了,称为泛型擦除
Student s1 = new Student();
Number score = s1.getScore();
}
@Test
public void test3()throws Exception{
//ArrayList,本来要指定E的类型,现在不指定了,称为泛型擦除
ArrayList list = new ArrayList();
list.add("hello");
}
当使用一个已经声明好的泛型类或泛型接口,例如:Collection、ArrayList,Comparable等,用它们声明方法的形参,或变量时,仍然无法确定,该指定为什么类型,就可以使用通配符>。
答案:使用形式有3种,以ArrayList
package com.atguigu.wild;
import org.junit.Test;
import java.util.ArrayList;
public class TestWildCard {
@Test
public void test1()throws Exception{
//调用m1方法,可以传入的集合是什么样的呢?
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList<Object> list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
m1(list1);
m1(list2);
m1(list3);
}
public void m1(ArrayList<?> list){
for (Object o : list) {
System.out.println(o);
}
//编译时无法确定?是啥类型,编译器认为它添加什么都是有风险的,全部报错
/* list.add("hello");
list.add(1);
list.add(1.0);*/
list.add(null);
}
@Test
public void test2()throws Exception{
//调用m2方法,可以传入的集合是什么样的呢?
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList<Object> list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
// m2(list1);//错误, list1的泛型不满足 String <= Number条件
m2(list2);//对
// m2(list3);//错误, list3的泛型
}
public void m2(ArrayList<? extends Number> list){
for (Number number : list) {
System.out.println(number);
}
}
@Test
public void test3()throws Exception{
//调用m3方法,可以传入的集合是什么样的呢?
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList<Object> list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
// m3(list1);//错误, list1的泛型不满足 String >= Number条件,String和Number没关系
// m3(list2);//错误, list2的泛型不满足 Integer >= Number条件,Integer
m3(list3);//对
}
public void m3(ArrayList<? super Number> list){
for (Object o : list) {
System.out.println(o);
}
}
@Test
public void test4()throws Exception{
//演示m4方法调用
//调用m4方法,可以传入的集合是什么样的呢?
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList<Object> list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
// m4(list1);//错误,m4方法的形参已经明确是ArrayList
// m4(list2);
m4(list3);
}
public void m4(ArrayList<Object> list){
for (Object o : list) {
System.out.println(o);
}
}
@Test
public void test5()throws Exception{
//调用m5方法,可以传入的集合是什么样的呢?
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList<Object> list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
m5(list1);
m5(list2);
m5(list3);
}
public void m5(ArrayList list){//啥都不写,泛型擦除,唯一的小瑕疵,有警告
for (Object o : list) {
System.out.println(o);
}
}
@Test
public void test6()throws Exception{
//调用m6方法,可以传入的集合是什么样的呢?
ArrayList<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList<Object> list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
m6(list1,"chai");
m6(list2,1);
m6(list3,1.0);
}
public <T> void m6(ArrayList<T> list,T t){
for (T o : list) {
System.out.println(o);
}
list.add(t);
}
public void m7(ArrayList<?> list1, ArrayList<?> list2){//这里?独立的
}
public <T> void m8(ArrayList<T> list1, ArrayList<T> list2){//这里T是同一种类型
}
}
m4(list3);
}
public void m4(ArrayList list){
for (Object o : list) {
System.out.println(o);
}
}
@Test
public void test5()throws Exception{
//调用m5方法,可以传入的集合是什么样的呢?
ArrayList list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
m5(list1);
m5(list2);
m5(list3);
}
public void m5(ArrayList list){//啥都不写,泛型擦除,唯一的小瑕疵,有警告
for (Object o : list) {
System.out.println(o);
}
}
@Test
public void test6()throws Exception{
//调用m6方法,可以传入的集合是什么样的呢?
ArrayList list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
ArrayList list2 = new ArrayList<>();
list2.add(666);
list2.add(888);
ArrayList list3 = new ArrayList<>();
list3.add("尚硅谷");
list3.add(666);
m6(list1,"chai");
m6(list2,1);
m6(list3,1.0);
}
public void m6(ArrayList list,T t){
for (T o : list) {
System.out.println(o);
}
list.add(t);
}
public void m7(ArrayList> list1, ArrayList> list2){//这里?独立的
}
public void m8(ArrayList list1, ArrayList list2){//这里T是同一种类型
}
}