JavaSE 泛型(Generic)
一、为什么要有泛型Generic?
-
为了保证只有指定类型添加到集合中,类型安全
-
举例说明:
package com.generic.demo01; import java.util.ArrayList; import java.util.List; public class Demo01 { public static void main(String[] args) { //未使用泛型的集合任意类型可接受 List list = new ArrayList(); list.add(111); list.add("SSS"); list.add(true); //需求:保证集合仅添加一个类型的数据 List<String> list1 = new ArrayList<String>(); list1.add("aaaa"); list1.add(111); //该语句出错,不能添加 } }
注意:
(1) Java中的泛型,只在编译阶段有效。
(2)泛型信息不会进入到运行时阶段。
二、泛型的使用
1 泛型类
-
对象实例化若不指定泛型,默认为:Object
-
泛型不同的引用不能互相赋值
package com.generic.demo01;
public class Demo02 {
public static void main(String[] args) {
A<String> a1 = new A<String>(); //在new A对象时指定泛型类型为String
a1.setKey("xxxx"); //对象使用setKey(T,key)方法,其中的key形参为String类型
String s = a1.getKey();//T getKey() 返回值就是new对象确定返回值时String
A<Integer> a2 = new A<Integer>();
a2.setKey(1);
Integer a = a2.getKey();
A a3 = new A(); //相当于A<Object> a3 = new A<Object>();
a3.setKey(new Object());
Object obj = a3.getKey();
//同样的类,但是在new对象时泛型指定了不同的数据类型,这些对象不能互相赋值
//a1 = a2; //错误语句
}
}
//此处的泛型T可以任意取名,A,B,V
//一般使用<T> --type
class A<T>{ //泛型类
private T key;
public void setKey(T key){
this.key = key;
}
public T getKey(){
return this.key;
}
}
2 泛型接口
- 定义语句:
//定义一个泛型接口
interface Generator<T>{
T next();
}
- 在声明类的时候,需要将泛型的声明也一起加到类中,否则会报错:“Unknown class”
- 即:
class FruitGenerator<T> implements Generator<T>{...}
class FruitGenerator implements Generator<String>{...}
- 实现接口语句:
class FruitGenerator1<T> implements Generator<T>{
@Override
public T next(){
return null;
}
}
//
class FruitGenerator2 implements Generator<String>{
@Override
public String next(){
return null;
}
}
案例展示:
package com.generic.demo02;
public class Demo01 {
public static void main(String[] args) {
B1<Object> b1 = new B1<Object>();
B1<String> b2 = new B1<String>();
//B2<Integer> b3 = new B2<Integer>();//不能执行,只能为String
B2 b3 = new B2();
}
}
interface IB<T>{
T test(T t);
}
//未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加入到类中
class B1<T> implements IB<T>{ //接口没有具体类型,则实现类也是一个泛型
@Override
public T test(T t) {
return null;
}
}
//若实现接口时,指定了接口泛型的具体数据类型,这个类实现接口所有方法的位置都要泛型替换实际的具体数据类型。
class B2 implements IB<String>{ //接口有具体类型,实现类创建对象时不用再声明泛型,声明反而会出错
@Override
public String test(String s) {
return null;
}
}
3 泛型方法
泛型方法有以下几种:
- 无返回值的泛型方法
- 有返回值的泛型方法
- 形参为可变参数的泛型方法
- 静态方法的泛型方法
泛型方法注意:
-
泛型方法在调用之前没有固定的数据类型,调用时确定
-
在调用时传入的参数是什么类型,泛型就会改为什么类型
案例展示:
package com.generic.demo03;
public class Demo01 {
public static void main(String[] args) {
Cc<Object> c = new Cc<Object>();
c.test("xxx");
//泛型方法在调用之前没有固定的数据类型
//在调用时传入的参数是什么类型,泛型就会改为什么类型
//泛型方法会在调用时确定泛型具体是什么类型
Integer i = c.test1(2);//传递的参数是Integer,泛型就固定为Integer,并返回Integer
Boolean b = c.test1(true);//传递参数是Boolean,泛型就固定为Boolean,并返回Boolean
}
}
class Cc<E>{
private E e;
//静态方法的泛型方法
public static <T> void test3(T t){
//在静态方法中,不能使用类定义泛型,如果要使用泛型,只能使用静态方法自己定义的泛型
//System.out.println(this.e);
System.out.println(t);
}
//无返回值的泛型方法
public <T> void test(T s){
//在类上定义的泛型,可以在普通的方法中使用
System.out.println(this.e);
T t = s;
}
//有返回值的泛型方法
public <T> T test1(T s){
return s;
}
//形参为可变参数的泛型方法
public <T> void test2(T... strs){
for (T s : strs){
System.out.println(s);
}
}
}
4 通配符<?>
不确定集合中的元素具体的数据类型,使用?表示所有类型。
-
无限制的通配符
案例展示:
package com.generic.demo04; import java.util.ArrayList; import java.util.List; public class Demo01 { public static void main(String[] args) { Dd d = new Dd(); List<String> li1 = new ArrayList<>(); d.test(li1);//可放入 List<Integer> li2 = new ArrayList<Integer>(); d.test(li2);//可放入 } } class Dd{ public void test(List<?> list){ //test方法需要一个list集合的参数,不确定list集合中元素数据类型 } }
-
有限制的通配符
分为三种:
<? extends Person>
//只允许泛型为Person及Person子类的引用调用。<? super Person>
//只允许泛型为Person及Person父类的引用调用。<? extends Comparable>
//只允许泛型为实现Comparable接口的实现类的引用调用。
案例展示:
package com.generic.demo04; import java.util.ArrayList; import java.util.List; public class Demo01 { public static void main(String[] args) { List<C1> lc = new ArrayList<C1>(); d.test1(lc); //可以放入 List<D1> ld = new ArrayList<D1>(); d.test1(ld); //可以放入 List<B1> lb = new ArrayList<B1>(); d.test1(lb); //不可以放入,出错! d.test2(lb); //可以放入 List<IAImpl> lia = new ArrayList<IAImpl>(); d.test3(lia); //可以放入 } } class Dd{ public void test1(List<? extends C1> list){//list参数的元素数据类型是C1及其子类 } public void test2(List<? super C1> list){//list参数元素数据类型是C1及其父类 } public void test3(List<? extends IA> list){//list元素数据类型为IA的实现类 } } class A1{} class B1 extends A1{} class C1 extends B1{} class D1 extends C1{} interface IA{} class IAImpl implements IA{}
写在最后
Let us not become weary in doing good, for at the proper time we will reap a harvest if we do not give up.
To Demut!