前言
泛型:可以在类或方法中预先地使用未知的类型。
tips:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。
提示:以下是本篇文章正文内容,下面案例可供参考
一、泛型定义
在类/接口定义:
语法: public class/interface 类名<泛型变量1[,泛型变量2....]>
使用范围: 泛型变量作为属性的数据类型, 泛型变量作为构造方法的参数的数据类型, 泛型变量作为普通方法的返回值数据类型, 参数的数据类型
在方法上定义: 可以是静态方法,也可以是普通方法
语法: 访问修饰符 <泛型变量1[,泛型变量2....]> 返回值类型/泛型变量 方法名(参数数据类型/泛型变量 参数名)
使用范围: 泛型变量作为定义它的方法的返回值数据类型, 参数的数据类型
静态方法不能使用类定义的泛型变量
/**
* 为什么要使用泛型
* 没有使用泛型: 带来那些不好的
*
* 没有使用泛型:
* 优点: 集合可以存储任意数据类型的元素
* 缺点: 1. 集合无法限制元素的类型
* 2. 获取元素,得到都是Object类型, 需要向下转型, 可能出现ClassCastException的异常
*/
public class Demo1 {
public static void main(String[] args) {
//添加任意数据类型的元素
List list = new ArrayList();
list.add("hello"); //String 向上转型, Object
list.add(123); //Integer 向上转型, Object
list.add(new Student(1,"张三")); //Student 向上转型, Object
//获取元素 Object get(下标), 遍历得到元素, 元素的类型: Object
Object ele = list.get(1);
if(ele instanceof String){
//需要进行向下转型
String str = (String) ele; //ClassCastException
}else if((ele instanceof Integer){
int i = (Integer) ele;
}
}
}
什么是泛型: 参数化类型, 通俗易懂: 把数据类型作为参数, 在创建类, 把数据类型作为一个参数传递给类,
>声明一个数据类型的变量:
>
>语法: <变量名>
>
>泛型变量在类/接口上 泛型类
>
>public class 类名<泛型变量名>{ //泛型变量名可以在类属性,方法,构造方法上使用
>
>}
>
>泛型变量: 默认的值: Object
>
>给泛型变量赋值: 在创建泛型类的对象时给泛型变量赋值:
>
>泛型变量: 类类型数据类型, 不能使用基本数据类型
>
>语法: 类名<类类型数据类型> 对象名 = new 类名<类类型数据类型>()
>定义泛型变量, 推荐大写, 就一个字母: 推荐的名字: T(type), K(key的数据类型),V(value的数据类型), E(element元素的数据类型)
>类上的泛型变量:
>
>注意:
>
> 1. 只能在类的属性上, 非静态方法的,构造方法上使用,不能再static的资源使用
>
> 2. 如果想在static方法上使用泛型变量, 那这个泛型变量只能在方法上声明,
//静态方法
public static <E> E fun3(){
return null;
}
3. 如果在方法上定义泛型变量, 这个泛型变量的赋值, 不是显示赋值, 如果泛型方法参数使用泛型变量,就是传递给方法的值的数据类型, 作为泛型变量的值 隐式赋值
4. 泛型方法的参数没有使用泛型变量, 是在调用这个方法, 使用变量接收这个方法的返回值, 接收返回值变量的数据类型, 作为泛型变量的值 这种方式,基本不使用
二、使用泛型
如果是使用泛型类/接口, 创建泛型类/接口的对象的时候, 类名/接口名<具体的数据类型>
泛型变量只能接收类类型,不能接收基本数据类型, 对于基本数据类型, 写的它的包装类
int (错误) --> Integer(对)
List<String> list = new ArrayList<String>(); //后面的实现类的泛型变量值与等号左边的泛型变量值一样
List<Object> list = new ArrayList<String>(); //错误的, 泛型中,没有泛型继承
在jdk1.7之后, =右边的泛型赋值可以省略,但是<>不能省略
List<String> list = new ArrayList<>();
使用泛型的优点:
-
限制了集合中元素的类型
-
获取元素的时候,不需要进行向下转型, 获取就是存储的类型
public static void main(String[] args) {
//使用泛型 list1集合中只能存储String类型的数据
List<String> list1 = new ArrayList<>();
//list1.add(111);//错误, 只能添加String
list1.add("hello");
list1.add("world");
//2.获取集合的元素
String str = list1.get(1);
}
如果是使用泛型方法: 不需要我们显示的赋值, 如果这个泛型变量作为参数的数据类型, 泛型变量的值为给参数赋值的数据类型.
public class GenericDemo2 {
//泛型方法
public static <T> T fun1(T a){
return a;
}
public static void main(String[] args) {
//使用泛型方法
String rs = fun1("abc"); // T 跟传递的参数的值的数据类型一样
}
}
三、 泛型通配符
当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示.但是一旦使用泛型的通配符后,只能使用Object类中的方法,集合中元素自身方法无法使用.
此时只能接收数据,获取元素,不能往该集合中存储数据
public class GenericDemo3 {
public static void main(String[] args) {
List<String> list1 = new ArrayList<>();
list1.add("hello");
list1.add("world");
//List<Integer> list2 = new ArrayList<>();
//List<Object> list3 = new ArrayList<>();
print2(list1);
// print2(list2);
// print2(list3);
}
//定义一个方法, 打印List集合, 集合的元素任意数据类型
//List没有泛型
/*public static void print(List list){
System.out.println("遍历集合:");
for (Object o : list) {
System.out.println(o);
}
}*/
//定义泛型类型的List接收任意list 泛型变量的值不确定, 使用泛型通配符 ?
//不能使用List<Object>, 因为泛型类不能继承
public static void print2(List<?> list){
System.out.println("遍历集合:");
for (int i = 0; i< list.size();i++) {
System.out.println(list.get(i));
}
//添加一个元素
//list.add("aaa");
}
}
f: 受限泛型
之前设置泛型的时候,实际上市可以设置任意类型的,只要是类就可以设置.但是在java的泛型中可以指定一个泛型的上限和下限.
泛型上限:
- 格式: `类型名称<? extends 类> 对象名称`
- 意义: 只能接收该类型及其子类
泛型下限:
- 格式:`类型名称<? super 类> 对象名称`
- 意义:只能接收该类型及其父类类型
/**
* 泛型上限:
* - 格式: `类型名称<? extends 类> 对象名称`
* - 意义: 只能接收该类型及其子类
*
* 泛型上限:
* - 格式:`类型名称<? super 类> 对象名称`
* - 意义:只能接收该类型及其父类类型
*/
public class GenericDemo {
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<Number> list3 = new ArrayList<>();
List<Object> list4 = new ArrayList<>();
fun1(list1);
fun1(list2); //报错
fun1(list3);
fun1(list4); //报错
fun2(list1); //报错
fun2(list2); //报错
fun2(list3);
fun2(list4);
}
//泛型上限: 此时的泛型?,必须是Number类型或者Number类型的子类
public static void fun1(List<? extends Number> list){}
//泛型下限: 此时的泛型?,必须是Number类型或者Number类型的父类
public static void fun2(List<? super Number> list){}
}
/**
* 使用泛型遍历Map
*/
public class Demo2 {
public static void main(String[] args) {
//创建一个Map, key: String , value: Student
Map<String,Student> studentMap = new HashMap<>();
//添加数据
studentMap.put("张三",new Student(1,"张三"));
studentMap.put("李四",new Student(2,"李四"));
//遍历Map 使用entrySet
//Map.Entry<String,Student> 是Set的泛型变量的值
//<String,Student> 是Entry的两个泛型变量的值
Set<Map.Entry<String,Student>> entrys = studentMap.entrySet();
//迭代器,增强for 遍历
for(Map.Entry<String,Student> entry :entrys){
String key = entry.getKey();
Student stu = entry.getValue();
System.out.println("key:"+key+"-->"+"value:"+stu);
}
}
}
四、Collections 集合帮助类/工具类
位于java.util包, 它的所有的方法都是static修饰的, 不需要创建对象,直接使用类名.方法名()调用
>面试题: Collection 与Collections区别
>
>Collection 是List,Set集合的父接口
>
>Collections 是集合的帮助类, 提供了对集合操作的方法,类似之前的Arrays
>public static <T> boolean addAll(Collection<T> c, T... elements): 往集合中添加一些元素
>
>public static void shuffle(List<?> list): 打乱集合顺序
>
>public static <T> void sort(List<T> list): 将集合中元素按照默认规则排序
>
>public static <T> void sort(List<T> list,Comparator<? super T>): 将集合中元素按照指定规则排
/**
* 集合帮助类: Collections
*/
public class CollectionsDemo1 {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
//使用集合的add() 添加元素 一个一个添加
/*list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");*/
//常用的方法:
//往Collection集合添加元素
//static <T> boolean addAll(Collection<? super T> c, T... elements)
Collections.addAll(list,"a","d","e","f","b");
System.out.println(list); //[a, b, c, d, e]
//public static void shuffle(List<?> list): 打乱集合顺序
List<String> list1 = new ArrayList<>();
Collections.addAll(list1,"大王","小王","黑桃A","黑桃K","黑桃Q","黑桃J","黑桃10","黑桃9","黑桃8","黑桃7","黑桃6","黑桃5");
System.out.println("洗牌前,牌的顺序:");
System.out.println(list1);
//打乱, 洗牌
Collections.shuffle(list1);
System.out.println("洗牌后,牌的顺序:");
System.out.println(list1);
//排序 public static <T> void sort(List<T> list): 将集合中元素按照默认规则排序 升序
Collections.sort(list);
System.out.println("排序之后,集合的顺序:");
System.out.println(list);
//List集合添加学生, 对学生排序 定义比较器: 类实现Comparable,
List<Student> stuList = new ArrayList<>();
stuList.add(new Student(1,"张三"));
stuList.add(new Student(6,"王五"));
stuList.add(new Student(4,"李四"));
System.out.println("排序前:");
System.out.println(stuList);
//排序
Collections.sort(stuList);
System.out.println("排序后:");
System.out.println(stuList);
//指定比较强:
// public static <T> void sort(List<T> list,Comparator<? super T>): 将集合中元素按照指定规则排序
Collections.sort(stuList, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return o2.getStuNo() - o1.getStuNo();
}
});
System.out.println("排序后:");
System.out.println(stuList);
}
}