Java泛型

一、泛型基础说明

泛型是JDK1.5的一种新特性,它的本质是参数化类型的应用,也就是说操作的数据类型被指定为一个参数,在用到的时候再指定具体的类型。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类,泛型接口和泛型方法。
Java语言中的泛型,它只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原始类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说, ArrayList<Integer>与ArrayList<String>就是同一个类 。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型。
类型擦除:泛型附加的类型信息对JVM来说不可见。
在这里插入图片描述
举个例子:

public class t7 {
 
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<String> ll = new ArrayList<>();
		List<Integer> kk = new ArrayList<>();
		System.out.println(ll.getClass());//输出:class java.util.ArrayList
		System.out.println(kk.getClass());//输出:class java.util.ArrayList
		System.out.println(ll.getClass() == kk.getClass());//输出:true
		就是因为泛型擦除。
 
	}
 }

二、泛型分类

1.泛型类

一个泛型类(generic class)就是具有一个或多个类型变量的类。定义一个泛型类十分简单,只需要在类名后面加上<>,再在里面加上类型参数。
举例说明:

//泛型类
public class MyDemo<T>{
    private T value;
    public MyDemo(T value){
        this.value = value;
    }
    public T getValue(){
        return value;
    }
    public void setValue(T value){
        this.value = value;
    }
}
//泛型类使用
public static void main(String[] args) throws ClassNotFoundException{
    MyDemo<String> demo = new MyDemo("Hello");
    String str = demo.getValue();
    System.out.println(str);
    demo.setValue("hi");
    str = demo.getValue();
    System.out.println(str);
}

2.泛型方法

表达方式如下:

[权限修饰词] <T1,T2,...,Tn> methods(/*...*/) {/*...*/}

尖括号内表示类型参数列表,即方法变量的类型

public class TestDemo {
    @Test
    public void should_return_value_when_get_with_params(){
        String str = get("Hello","world");
        Assert.assertEquals("the str should be equals to Hello","Hello",str);
        
       int num = get(123,"Hello");
       Assert.assertEquals("num should be equals to 123","123",num);
    }
    public static <T, U> T get(T t, U u) {
        if (u != null)
            return t;
        else
            return null;
    }
}

3.泛型接口

interface Show<T,U>{
    void show(T t,U u);
}
 
class ShowTest implements Show<String,Date>{
    @Override
    public void show(String str,Date date) {
        System.out.println(str);
        System.out.println(date);
    }
}

三、通配符

通配符表示为:?

(1)T、K、V、E等泛型字母称为有“有类型”,类型具体使用时而定。
(2)?为未知类型,类型参数不确定,可以是任意类型。只能用在声明类型、方法参数上,不能用在定义泛型类上

/**
 * ? -->通配符,类型不确定,用于声明 变量|形参 上
 * 不能用在:
 * 1,创建对象
 * 2,创建泛型类 、泛型方法、泛型接口上
 *
 */
public class WildcardTest {

    public static void main(String[] args) {
        //声明
        List<?> list = new ArrayList<Integer>();
        list = new ArrayList<String>();
        list = new ArrayList<Object>();
        
        test(list);
        //编译错误,不能创建对象
//        list = new ArrayList<?>();
    }
    
    public static void test    (List<?> list){
        
    }
    //?不能用在泛型方法上
    /*public static <?> void test2(List<?> list){
        
    }*/
    //?不能创建泛型类
    /*class Test<?>{
        
    }*/
}

五、泛型上下边界

1.作用

先从通配符’?'说起,已知通配符可以是任意类类型,在实际业务或功中在使用通配符时会遇到很多安全问题如:传入的泛型类没有特定的方法或属性,类型转换错误等等。所以为了防止这些问题的发生,就有了上下边界,用于指定通配符的范围。

2.上边界

<? extends T> 表示该通配符所代表的是T类型的子类

// 上边界指定格式
? extends 指定类型(可以是类也可以是接口)

// 要求
class ? extends 指定类
// 或
class ? implements 指定接口

// 要求继承指定类且必须实现指定接口
? extends 指定类&指定接口
// 如下
? extends A&B

上限<? extends T>不能往里存,只能往外取 (即:只能get)
因为编译器只知道容器里的是Fruit或者Fruit的子类,但不知道它具体是什么类型,所以存的时候,无法判断是否要存入的数据的类型与容器种的类型一致,所以会拒绝set操作。

如果需要经常往外读,则使用<? extends T>

2.下边界

<?super T>表示该通配符所代表的类型是T类型的父类

下限<? super T>往外取只能赋值给Object变量,不影响往里存
因为编译器只知道它是Fruit或者它的父类,这样实际上是放松了类型限制,Fruit的父类一直到Object类型的对象都可以往里存,但是取的时候,就只能当成Object对象使用了。
如果经常往里存就是用<?super T>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值