为什么使用泛型
- 例如:未规定泛型时,ArrayList可以存放String类和Integer类型的元素;但规定泛型为String时,就只可以存储String类型的元素(图中为编译器发现的问题)
- 泛型只在编译阶段有效
泛型的使用
泛型类
- 示例:泛型类,实例化对象时,指定不同的泛型
public class A<T> {
private T key;
public void setKey(T key ){
this.key = key;
}
public T getKey(){
return this.key;
}
public static void main(String[] args){
//----------------------------------------
A<String > a1 = new A<String>();
a1.setKey("xxx");
String s = a1.getKey();
//----------------------------------------
A<Integer> a2 = new A<Integer>();
a2.setKey(1);
Integer i = a2.getKey();
//----------------------------------------
A a3 = new A();//相当于A<Object> a3 = new A<Obiect>();
a3.setKey("hello");//或者a3.setKey(new Object());
a3.setKey(896);
Object obj = a3.getKey();//896
}
}
注: 同样的类,但是在new对象时,泛型指定不同的数据类型,这些对象不能互相赋值
- 示例:泛型类构造器不可带泛型
public static class DNode<T>{
public T value;
public DNode<T> last;
public DNode<T> next;
public DNode(T data){
value = data;
}
}
泛型接口
- 泛型接口IB,类B1,B2继承接口。其中B1不指定泛型,类加泛型声明;B2继承时指定接口泛型
public class TestIB {
public static void main(String[] args) {
//B1和B2类的使用区别
B1 b1 = new B1();//相当于B1<Object> b1 = new B1();
B1<String> b2 = new B1();
B1<Integer> b3 = new B1();
B2 b4 = new B2();//不用指定泛型,因为已经确定为String
b1.test(new Object());
b1.test("yurt");
b1.test(45634);
b2.test("453rt");
b3.test(876);
b4.test("ryut");
}
}
interface IB<T> {
public T test (T t);
}
/**
* @Description: 未传入泛型实参,声明类时,泛型声明一起加到类中
*/
class B1<T> implements IB<T>{
@Override
public T test(T t) {
return null;
}
}
/**
* @Description: 传入泛型实参String,如果实现接口时指定接口的泛型的具体数据类型,
* 这个类实现接口所有方法的位置,都要泛型替换实际的具体数据类型
*/
class B2 implements IB<String>{
@Override
public String test(String s) {
return null;
}
}
泛型方法
泛型方法,在调用时确定泛型具体数据类型
/**
* Created with IntelliJ IDEA.
*
* @Author: xuexuezi
* @Date: 2022/11/10/23:28
* @Description: 测试泛型方法
*/
public class C<E> {
/*在类中可定义泛型变量,可在普通方法内使用
但不能在static静态方法中使用,如果要使用泛型,只能使用静态方法自己定义的泛型
*/
private E e;
//此处方法的泛型化都属于方法的重载,因为同名且参数不同;注意判断方法是否重载与返回值无关
//==========================无返回值的方法泛型化=========================
public void test(){
System.out.println(this.e);//可以使用泛型变量
}
//将public void test();泛型化
public<T> void test(T s){
T t = s;
System.out.println(this.e);//可以使用泛型变量
}
//==========================有返回值的方法泛型化==========================
public String test1(String s){
return s;
}
//泛型化
public<T> T test1(T s){//与test中的T在一个类中不冲突,属于方法内的定义
return s;
}
//==================无返回值,可变参数类型的方法泛型化=====================
public void test2(String... strs){//与数组做参数使用方法相同,传参可以传数组名,new匿名数组,直接传元素串
for(String s: strs){
System.out.println(s);
}
}
//泛型化
public<T> void test2(T... strs){
for(T s: strs){
System.out.println(s);
}
}
//=======================静态的方法泛型化===========================
public static void test3(int i){
System.out.println(i);
}
//泛型化
public static<T> void test3(T t){
System.out.println(t);
//System.out.println(e);//类定义的泛型变量,静态方法不可用
}
//========================方法的使用=============================
public static void main(String[] args) {
/*泛型方法在调用之前没有固定的数据类型,在调用时,传入的参数是什么类型,就会把泛型改成什么类型*/
C<Object> c = new C<Object>();//<Object>不可省略
Integer ii = c.test1(2);//传入的参数是Integer,泛型就固定成Integer,返回值就是Integer
Boolean b = c.test1(true);//传入的参数是Boolean,泛型就固定成Boolean,返回值就是Boolean
c.test();
C.test3(false);
}
}
注: 泛型方法
使用时,不指定泛型的情况<Object>
不可省略;但继承泛型接口且继承时不指定泛型的类
和泛型类
使用时不指定泛型的情况,可以省略<Object>
通配符
泛型通配符
- 方法参数不确定集合List的数据类型,用
?
代替。传参时,向?
传入数据类型来规定集合数据类型
public class WildCard {
public void test(List<?> list){//需要一个list参数,但不确定数据类型
Iterator<?> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static void main(String[] args){
WildCard d = new WildCard();
List<String> l1 = new ArrayList<String>();
l1.add("rtury");
l1.add("45terw");
List<Integer> l2 = new ArrayList<Integer>();
l2.add(45);
l2.add(564);
l2.add(3456);
d.test(l1);
d.test(l2);
}
}
有限制的通配符
- 有限制的通配符,定义类的继承关系:Aa->Bb->Cc->Dd;B1和B2类实现接口IB
- 定义三个方法的参数限制
List<? extends Cc> list
只允许泛型为C及C的子类的引用调用Set<? super Bb> set
只允许泛型为TestIB及TestIB父类的引用调用List<? extends IB> list
只允许泛型为实现IB接口的实现类引用调用
import java.util.*;
/**
* Created with IntelliJ IDEA.
*
* @Author: xuexuezi
* @Date: 2022/11/11/4:47
* @Description: 有限制的通配符,定义类的继承关系:Aa->Bb->Cc->Dd,B1和B2类实现接口IB
*/
class Aa{
}
class Bb extends Aa{
}class Cc extends Bb{
}
public class Dd extends Cc{
public void test(List<? extends Cc> list){//只允许泛型为C及C的子类的引用调用
Iterator<?> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public void test2(Set<? super Bb> set){//只允许泛型为TestIB及TestIB父类的引用调用
Iterator<?> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public void test3(List<? extends IB> list){//只允许泛型为实现IB接口的实现类引用调用
Iterator<?> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
public static void main(String[] args) {
Dd d = new Dd();
List<Aa> la = new ArrayList<>();
List<Bb> lb = new ArrayList<>();
List<B1> lb1 = new ArrayList<>();
List<Cc> lc = new ArrayList<>();
List<Dd> ld = new ArrayList<>();
Set<Aa> sa = new HashSet<>();
Set<Bb> sb = new HashSet<>();
Set<Cc> sc = new HashSet<>();
Set<Dd> sd = new HashSet<>();
//==========================调用test,list泛型为C及C的子类的引用调用=====================
System.out.println("调用test,list泛型为C及C的子类的引用调用");
d.test(lc);
d.test(ld);
//d.test(lb1);
//====================调用test2,set泛型为TestIB及TestIB父类的引用调用==================
System.out.println("调用test2,set泛型为TestIB及TestIB父类的引用调用");
d.test2(sa);
d.test2(sb);
//d.test2(sc);
//d.test2(sd);
//====================调用test3,list泛型为实现IB接口的实现类引用调用=====================
System.out.println("调用test3,list泛型为实现IB接口的实现类引用调用");
//d.test3(la);
//d.test3(lb);
d.test3(lb1);
//d.test3(lc);
}
}
- 测试结果,不符合通配符条件的参数,编译报错