JavaSE 泛型

为什么要定义泛型

比如下面的例子

public class Example {
    private Object object;     /
    public  Object getObject(){
        return object;
    }
    public void setObject(Object object){
        this.object=object;
    }

    public static void main(String[] args) {
        Example example=new Example();
        example.setObject(new Boolean(true));
        System.out.println(example.getObject());
        example.setObject(new Float(3.14));
        float f=(float)example.getObject();
        System.out.println(f);
        int i=(int)example.getObject();
        System.out.println(i);
    }
}

example.setObject(new Float(3.14));
float f=(float)example.getObject();
在上面这段代码中,将setObject()的参数传入的是一个Float类,而将Float转换为float变量是没有任何问题的
但是 int i=(int)example.getObject(); 将Float类转换成int类型在运行时他会抛出异常,无法转换。但是在编译的时候并不会报错,这对程序的开发和调试会造成影响
在这里插入图片描述
编译时并没有报错
在这里插入图片描述
运行时出错

定义泛型

定义类时

类名<类型参数1,类型参数2,....类型参数n>{}
类名<T>				
类型<T,A,B>       //多个泛型
public class Example<T> {
    private T object;
    public  T getObject(){
        return object;
    }
    public void setObject(T object){
        this.object=object;
    }

    public static void main(String[] args) {
        Example<Boolean> example1=new Example<Boolean>();
        example1.setObject(true);
        System.out.println(example1.getObject());
        Example<Float> example2=new Example<Float>();
        example2.setObject(3.14f);    //float型后面要加f
        float f=example2.getObject();
        System.out.println(f);
        //int i=(int)example2.getObject();  编译报错   不能转换为int,强制转换也不行
    }
}
输出结果:
true
3.14

在main方法里实例化Example< Boolean > example1=new Example< Boolean >() 时,example1里的T就已经变成了Boolean类。
实例化 Example example2=new Example()时,example2的T就变成了Float类,所以它的getObject()方法的返回值也就变成了Float,所以可以赋值给float变量,且不能强制转化为其他类型,所以这时int i=(int)example2.getObject()时会报错。
实力话Example< Boolean > example1=new Example< Boolean >()时也可以Example< Boolean > example1=new Example< >()这么声明
如果是实例化Example example1=new Example(),那么example的 T 默认是Object类

注意

使用泛型声明类时,在<>里声明泛型名称,名称声明时不要和java里已经存在的类重名

在这里插入图片描述
泛型名称中有String,而在类中声明String并赋值时会出错,因为这里的String是泛型名称而不是java里的String,所以无法赋值。想要使用String就得用类的全称java.lang.String
在这里插入图片描述

泛型的用法

(1)定义泛型类时声明多个类型
类名<T1,T2>
(2)定义泛型时声明数组类型
类名<T>{
   T[] over;
}
public class Example<T> {
    private T[] object;       //泛型数组
    public  T[] getObject(){
        return object;
    }
    public void setObject(T[] object){
        this.object=object;
    }

    public static void main(String[] args) {
        Example<String> example=new Example<>();
       String[] strs={"1","2","3"};
       example.setObject(strs);
       for(int i=0;i<example.getObject().length;i++){
           System.out.println(example.getObject()[i]);
       }
    }
}
输出结果;
1
2
3
(3)集合类声明容器的元素

还记得Map吗,Map就是使用了泛型
Map的定义

Map<K k,V v>     //这就是使用了泛型
比如
 Map<String,Integer> map=new HashMap<String, Integer>();

还有ArrayList<>,Vector<>等等

集合类泛型定义
ArrayListArrayList< E >
HashMapHashMap<K,V>
HashSetHashSet< E >
VectorVector< E>

泛型的高级用法

(1)限制泛型可用类型
class 类名<T extends anyClass>                 //anyClass:某个接口或类

在这里插入图片描述
限制T 继承List后,就不能用HashMap,HashMao没有继承List

(2)类型通配符

泛型机制中,提供了类型通配符
作用:在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或类的子类

 类名<? >
 类名<? extends anyClass>    //泛型必须是anyClass的子类,且此对象不能做增加和改写操作
 类名<? super anyClass>      //泛型必须是anyClass的父类,且此对象不能做增加和改写操作
public class Example<T extends List> {
    public static void main(String[] args) {
            List<String> l1=new ArrayList<>();
            List<?> l2=new ArrayList<Number>();
            List<?> l3=l1;
            l1.add("成员1");
            System.out.println(l3.get(0));
            l1.set(0,"成员改变");
            //l2.add("123");   编译报错
            //l3.set(0,"改变");   编译报错
            System.out.println(l3.get(0));
    }
}
输出结果:
成员1
成员改变

因为l2,l3使用了类型通配符,所以不能增加和修改操作


public class Example<T extends List> {
    public static void main(String[] args) {
           List<? extends List> l1=new ArrayList<List>();
           //List<? extends List> l2=new ArrayList<Object>();  编译报错  因为object不是List的子类
           List<? super List> l3=new ArrayList<Object>();    //y因为Object是List的父类   
    }
}

注意

?类型通配符是在使用的时候可以用,不能在定义的时候去用
在这里插入图片描述
报错,因为不能在定义的时候去用

(3)继承泛型类与实现泛型接口
interface MyInterface<T>{
}
class Father<T>{
    
}
public class Son<T1 ,T2,T3,T4> extends Father<T1> implements MyInterface<T3>{
    public static void main(String[] args) {
        
    }
}

Son继承Father,所以Son的泛型里要有Father的泛型T1,Son实现接口MyInterface,所以Son的接口里要有T3,其他的T2,T4是Son独有的

1.全部继承

 Son<T1 ,T2,T3> extends Father<T1,T3>      //全部继承  Son的T1,T3继承自Father,只有T2是Son独有的
public class Example{
    public static void main(String[] args) {
        Father<Integer,String> f=new Son<>(1,"2");
        //Son<Integer,String,Boolean> s=new Son<>(1,"3");  报错   因为T3是Boolean ,而构造方法里传入了字符串
        Son<Integer,String,Boolean> s=new Son<>(1,true);
    }
}
class Father<T1,T2>{
    T1 t1;
    T2 t2;
    public Father(T1 t1,T2 t2){
        this.t1=t1;
        this.t2=t2;
        System.out.println("t1的类型"+this.t1.getClass());
        System.out.println("t2的类型"+this.t2.getClass());
    }
}
class Son<T1 ,T2,T3> extends Father<T1,T3> {
    public Son(T1 t1,T3 t3){
        super(t1,t3);
    }
}
输出结果:
t1的类型class java.lang.Integer
t2的类型class java.lang.String
t1的类型class java.lang.Integer
t2的类型class java.lang.Boolean

class Son<T1 ,T2,T3> extends Father<T1,T3>
Son<Integer,String,Boolean> s=new Son<>(1,“3”); 会报错 。因为T3是Boolean ,而构造方法里传入了字符串
2.部分继承

 Son<T1 ,T2,T3> extends Father<T1,String >      //部分继承  在继承时已经将父类的一个泛型实例化了 Son的T1继承自Father,只有T2,T3是Son独有的
public class Example{
    public static void main(String[] args) {
        Father<Integer,String> f=new Son<>(1,"2");
       // Son<Integer,String,Boolean> s=new Son<>(1,true);  报错  因为true 不是字符串类型
        Son<Integer,String,Boolean> s=new Son<>(1,"3")    //子类的T2,T3随便写 因为他们都不继承自父类,而构造方法里的第一个参数必须是Integer 因为T1继承自父类
    }
}
class Father<T1,T2>{
    T1 t1;
    T2 t2;
    public Father(T1 t1,T2 t2){
        this.t1=t1;
        this.t2=t2;
        System.out.println("t1的类型"+this.t1.getClass());
        System.out.println("t2的类型"+this.t2.getClass());
    }
}
class Son<T1 ,T2,T3> extends Father<T1,String> {
    public Son(T1 t1,String t3){     //这里就必须是String  因为已经实例化为String,所以必须传入String
        super(t1,t3);
    }
}

class Son<T1 ,T2,T3> extends Father<T1,String>
Son<Integer,String,Boolean> s=new Son<>(1,true); 会报错 因为true 不是字符串类型
Son<Integer,String,Boolean> s=new Son<>(1,“3”) ;不会报错 父类的T3已经实例化为String,所以构造方法的第二个参数必须是字符串类型 。子类的T2,T3随便写 因为他们都不继承自父类,而构造方法里的第一个参数必须是Integer 因为T1继承自父类

3.实现父类泛型

class Son<T1 ,T2,T3> extends Father<Integer,String>    //已经将父类的泛型全部实现 子类的T1,T2,T3都与父类无关
public class Example{
    public static void main(String[] args) {
        //Father<Integer,String> f=new Son<>(1,"2");
        //Son<Integer,String,Boolean> s=new Son<>(1,true);
        Son<Integer,String,Boolean> s1=new Son<>(1,"3");    //因为与父类的泛型无关,所以子类的T1,T2,T3随便写
        Son<Integer,Integer,Integer> s2=new Son<>(1,"3");
    }
}
class Father<T1,T2>{
    T1 t1;
    T2 t2;
    public Father(T1 t1,T2 t2){
        this.t1=t1;
        this.t2=t2;
        System.out.println("t1的类型"+this.t1.getClass());
        System.out.println("t2的类型"+this.t2.getClass());
    }
}
class Son<T1 ,T2,T3> extends Father<Integer,String> {
    public Son(Integer t1,String t3){  
        super(t1,t3);  //这里就必须是Integer,String  因为已经实例化为Integer,String,所以必须传入Integer,String
    }
}

class Son<T1 ,T2,T3> extends Father<Integer,String>
Son<Integer,String,Boolean> s1=new Son<>(1,“3”);
Son<Integer,Integer,Integer> s2=new Son<>(1,“3”);
因为与父类的泛型无关,所以子类的T1,T2,T3随便写,但是构造方法里传入的参数必须是父类已经实现的泛型

4.不实现父类泛型

class Son<T1 ,T2,T3> extends Father      //不继承父类的任何泛型    这时父类的泛型就默认为Object
public class Example{
    public static void main(String[] args) {
        //Father<Integer,String> f=new Son<>(1,"2");
        //Son<Integer,String,Boolean> s=new Son<>(1,true);
        Son<Integer,String,Boolean> s1=new Son<>(1,"3");
        Son<Integer,Integer,Integer> s2=new Son<>(1,3.14f);
        Son<String,String,String> s3=new Son<>("1",3.14);     //构造方法参数随便写
        //子类的T1,T2,T3也随便写
    }
}
class Father<T1,T2>{
    T1 t1;
    T2 t2;
    public Father(T1 t1,T2 t2){
        this.t1=t1;
        this.t2=t2;
        System.out.println("t1的类型"+this.t1.getClass());
        System.out.println("t2的类型"+this.t2.getClass());
    }
}
class Son<T1 ,T2,T3> extends Father {
    public Son(Object t1,Object t3){     //因为不实现父类泛型所以默认是Object
        super(t1,t3);
    }
}
输出结果:(输出结果只与构造方法的参数有关)
t1的类型class java.lang.Integer
t2的类型class java.lang.String
t1的类型class java.lang.Integer
t2的类型class java.lang.Float
t1的类型class java.lang.String
t2的类型class java.lang.Double
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值