JAVA泛型

JAVA泛型

 

Java 泛型(generic) 是在JDK 1.5版本引用的一种新的特性,泛型提供编译时安全检查机制,该机制允许程序员在编译时检查非安全的类型。

一、泛型本质

泛型本质是数据化类型,即先给类型指定一个参数,然后使用时再指定参数具体的值,那么这个类型可以在使用时候决定,这种参数类型可以用在类、接口、方法中,分别被称为泛型类、泛型接口、泛型方法。

        List<String> list = new ArrayList<>();

二 、为什么使用泛型

泛型好处在编译时候检测类型安全,并且泛型强制转换都是自动或者隐式的,提高代码重用性。

泛型作用:1、确保类型安全性,2、消除类型强制转换,3、提高代码性能,4、提高代码重用性

1、确保类型安全性

在没有泛型之前,从集合中读取数据都需要类型转换,如果一不小心将插入错误的类型对象,在运行时转换处理就会出错。

没有泛型前

       
         ArrayList list = new ArrayList();
        list.add("ChenBinBin");
        list.add(9527); //编译不报错,
 

使用泛型后

        ArrayList<String> list = new ArrayList<>();
        list.add("ChenBinBin");
        list.add(9527); //编译时报错

使用泛型后,定义好的集合list在编译时候添加整数类型add(9527)会报错,

2、消除类型强制转换

泛型优点之一:消除代码中许多类型的强制转换,提高代码的可读性,并且减少出错的机会。

泛型之前

        ArrayList nameList = new ArrayList();
        nameList.add("ChenBinBin");
        String name = (String) nameList.get(0);//获取集合对象时候,需要强制转换类型
        System.out.println(name);

泛型之后

        ArrayList<String> nameList = new ArrayList<>();
        nameList.add("ChenBinBin");
        String name = nameList.get(0); //不需要强制转换
        System.out.println(name);

3、提高代码性能

避免了不必要的装箱(Boxing)和拆箱(UnBoxing)操作

在泛型之前,简单类型object对象进行传递时会引起装箱(Boxing)和拆箱(UnBoxing)操作,这个有很大的开销.

在泛型之后,避免了不必要的装箱(Boxing)和拆箱(UnBoxing)操作.运行效率很高,尤其是对集合对象频繁操作,提升效果更加明显.

泛型变量固定了类型,使用的时候已经知道值类型是基本类型还是引用类型.从而避免了不必要的装箱和拆箱操作.

泛型之前

package com.chen.test.Demo;

public class NonGeneric {
    Object a = 1; //由于类型是Object,所以需要装箱操作
    int b = (int)a;//a对象是Object类型,传递给int类型,需要强制转换,拆箱操作
​
}

泛型之后

package com.chen.test.Demo;
​
public class JavaGeneric<T> {
    public T value;
​
    public JavaGeneric(T value) {
        this.value = value;
    }
​
    public static void main(String[] args) {
        JavaGeneric<Integer> javaGeneric = new JavaGeneric<Integer>(1);
    }
}
4、提高代码重用性

三、如何使用泛型类型

泛型可以使用在类、接口、方法,分别称为泛型类、泛型接口、泛型方法。

1、泛型类

泛型类定义格式:

public class 泛型类名 <泛型类型参数1,...>{}

注意: 泛型类型必须是引用类型,而非基本类型 ,当然泛型类型参数一般都是大写字母参数形式:

T :任意类型type
K :kay-value形式key
V :key-value形式value
E :集合中元素类型element

泛型类:

package com.chen.test.Demo.Generic;
​
public class GenericClass<T> {
    public T value;
​
    public GenericClass(T value) {
        this.value = value;
    }
​
    public T getValue() {
        return value;
    }
​
    public void setValue(T value) {
        this.value = value;
    }
//main Method
    public static void main(String[] args) {
        GenericClass<String> name = new GenericClass<>("ChenBinBin");
        System.out.println(name.getValue());
        name.setValue("YangJingJing");
        System.out.println(name.getValue());
        GenericClass<Integer> numStr = new GenericClass<>(9527);
        System.out.println(numStr.getValue());
    }
}
 

泛型类测试结果:

2、泛型接口

泛型接口定义格式:

public interface 接口名称<泛型类型1,...> {}

泛型接口

package com.chen.test.Demo.Generic;
​
public interface GenericInterface<T> {
    void showValue(T value);
}

写Integer和String两个泛型实现类

package com.chen.test.Demo.Generic;
​
public class IntegerShowValueImpl implements GenericInterface<Integer>{
    @Override
    public void showValue(Integer value) {
        System.out.println(value);
    }
}
package com.chen.test.Demo.Generic;
​
public class StringShowValueImpl implements GenericInterface<String>{
    @Override
    public void showValue(String value) {
        System.out.println(value);
    }
}

单元测试类

package com.chen.test;
​
import com.chen.test.Demo.Generic.IntegerShowValueImpl;
import com.chen.test.Demo.Generic.StringShowValueImpl;
​
public class GenericTest {
    public static void main(String[] args) {
        new StringShowValueImpl().showValue("ChenBinBin");
        new IntegerShowValueImpl().showValue(9527);
​
    }
}

测试结果:

值得注意: 使用泛型,前后类型需要一致性

3、泛型方法

泛型方法:是在调用方法的时候指明泛型的具体类型。

泛型方法定义格式

修饰符 <泛型参数变量> 返回类型 方法名(泛型参数类型){}
package com.chen.test.Demo.Generic;
​
public class GenericClass<T> {
    public GenericClass(T t) {
    }
​
    public GenericClass() {
​
    }
​
    public <T> T genericMethod(T value){
        System.out.println(value.getClass());
        System.out.println(value);
        return value;
    }
​
    public static void main(String[] args) {
        GenericClass<StringBuffer> g1 = new GenericClass("Hello ChenBinBin");//该类型可以定义多种形式
        String name = g1.genericMethod("ChenBinBin "); //传入String类型,返回String类型
        Integer num = g1.genericMethod(9527); //传入Integer类型,返回Integer类型
        GenericClass<Integer> g2 = new GenericClass();//该类型可以定义多种形式
        String name2 = g2.genericMethod("YangJingJing");
    }
}
​

值得注意: 泛型方法随着传入参数类型不同,返回类型也不同。泛型方法能是方法独立于类而参数变化

四、泛型通配符

Java 泛型通配符是用于解决泛型之间引用传递问题的特殊处理语法,主要有三种:无边界通配符、有上边界通配符、有下边界通配符

注意: 泛型仅仅存在编译时,在转换为字节码的时候会将泛型擦除

public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}

1、无边界通配符

格式形式:<?>

List<?> 表示传递的类型不知道是什么类型

展示代码

        List<?> list = new ArrayList<Integer>(); //泛型通配符,,定义对象不能添加元素
        //list.add(1);编译时报错

2、有上边界通配符

格式表达:

<? extends T> 表示传递类型必须是T以及T子类型

展示代码

package com.chen.test.Demo.Generic;
​
import java.util.ArrayList;
import java.util.List;
​
public class GenericApplication {
    public static void main(String[] args) {
        List<A> l1 = new ArrayList<>();
        List<B> l2 = new ArrayList<>();
        List<C> l3 = new ArrayList<>();
        show(l1);
        show(l2);
       // show(l3);编译时报错,只能是A以及A子类
​
    }
    public static <T> void show(List<? extends A> list){}
    class A{}
    class B extends A{}
    class C {}
}

3、有下边界通配符

格式表达式:

<? super T> 表示传递类型必须是T以及T父类类型

展示代码

package com.chen.test.Demo.Generic;
​
import java.util.ArrayList;
import java.util.List;
​
public class GenericApplication {
    public static void main(String[] args) {
        List<A> l1 = new ArrayList<>();
        List<B> l2 = new ArrayList<>();
        List<C> l3 = new ArrayList<>();
        show(l1);
       // show(l2); 编译时报错,只能是A以及A的父类
       //show(l3);编译时报错,只能是A以及A的父类
​
    }
    public static <T> void show(List<? super A> list){}
    class A{}
​
    class B extends A{}
​
    class C {}
}
​

4、通配符弊端

package com.chen.test.Demo.Generic;
​
import java.util.ArrayList;
import java.util.List;
​
public class GenericApplication {
    public static void main(String[] args) {
        List<? extends A> l1 = new ArrayList<B>();
        List<? super B> l2 = new ArrayList<A>();
//        l1.add(new B());// 编译时报错
        l2.add(new B());
    }
//    public static <T> void show(List<? super A> list){}
    static class A{}
​
    static class B extends A{}
​
}
​

5、通配符使用原则

如果频繁读取操作,适合使用extends上边界

如果频繁插入操作,适合使用super下边界

五、泛型中ETKVN含义

通过查询源码了解泛型参数类型具体含义:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{}
public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable {}
​

常见泛型参数类型:

T: 类中类型 Type
E: 集合中元素类型 element类型
V: 键值对Value(值)类型
K: 键值对Key(值)类型
N: 数字类型Number类型
?: 表示不确定的java类型

六、泛型实现原理

泛型本质是将数据类型参数化,通过擦除方式来实现,即在编译器在编译时候会对泛型 语法做一些类型转换操作。

定义一个泛型类和泛型成员变量,成员变量类型是T,T是泛型类型,具体是什么类型我们也不知道,它仅仅是限定类型的。

package com.chen.test.Demo.Generic;
​
public class GenericDemo<T>{
    private T value;
   
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值