泛型的定义及使用

一、泛型的概念
泛型是程序语言设计的一种特性,jdk1.5定义了泛型,即参数化类型,就是把类型当做参数一样传递,类似于方法中的变量参数,然后在使用时传入具体的类型。

二、泛型类的实现与使用

public class<T>{}//自定义泛型类
public interface<T>){}//自定义泛型接口
public <T> method(T element){return element}//自定义泛型方法

实现泛型类代码示例:

public class List<T>{
    private   T[] elements=(T[])new Object[10];//用来装任意类型的元素
    private int size;//记录数据的长度

    public void add(T element){ //设计一个添加元素的方法,不考虑扩容的情况
        elements[size]=element;
        size++;
    }
    public T get(int index){//设计一个获取元素的方法
        if(index<size){
            return elements[index];
        }
        return null;
    }

    public String toString(){
        T[] array=Arrays.copyOf(elements,size);
        return Arrays.toString(array);
    }
    public static void main(String[] args) {
        List<String> list1=new List<>();
        list1.add("hello");
        list1.add("world");
        System.out.println(list1);
        System.out.println(list1.get(0));

        System.out.println("=========================");

        List<Integer> list2=new List<>();
        list2.add(1);
        list2.add(2);
        list2.add(3);
        System.out.println(list2);
        System.out.println(list2.get(1));

    }
}
[hello, world]
hello
=========================
[1, 2, 3]
2

Process finished with exit code 0

泛型接口
泛型接口与泛型类的定义基本相同,如下:

public interface List<T>{
     T add();
}

//第一种,没有指定类型
class MyList<T> implements List<T>{

    @Override
    public T add() {
        return null;
    }
}
//第二种,指定了类型
class  MyList2<String> implements List<String>{

    @Override
    public String add() {
        return null;
    }
}

泛型方法
是不是泛型方法和该方法所在的类是不是泛型类无关,就如同上面的示例中 public T get(int index)它并不是一个泛型方法,只是使用了它所在类中的泛型,只有声明了泛型才是泛型方法,比如将这个方法改成下面的实例它才是一个泛型方法。

public <T> T get(int index){...}

在权限符和返回值之间加<T>,就声明这个方法是个泛型方法
使用泛型方法可以取代整个类泛型化,当只是其中的个别方法需要用到泛型的时候,就应该尽量使用泛型方法,而不是将整个类泛型化。
对于一个静态方法,它是无法访问泛型类的类型参数,如果静态方法需要使用泛型,那么就应该将此方法声明泛型方法。

public static <T> void example(){...}//静态的泛型方法

创建泛型类的对象时,需要指定类型参数的值,而使用泛型方法的时候,通常不必指定类型参数,编译器会为我们找出具体参数值,称为类型参数推断

public class Main {
    public <T> void print(T x){
        System.out.println(x.getClass().getName());
    }
    public static void main(String[] args) {
    Main ma=new Main();
    ma.print("String");//不需要指明泛型
    ma.print(1);
    ma.print(1.0);
    ma.print('C');
    ma.print(ma);
    }
}

输出结果:

java.lang.String
java.lang.Integer
java.lang.Double
java.lang.Character
Main

Process finished with exit code 0

三、泛型的作用
1.增强代码复用性,简单便捷,就如同我上面定义了List类中的方法,可以对任何类型的参数做处理,不需要重新设计一个类,或者针对某个类型变量特意重载方法。
2.消除强制类型转换,将出错的提示信息出现在编译期,只要编译时没出错,运行时就不会出现类型转换异常,我们在编译时就可以检查类型是否安全。
3.性能相对于进行强制转型要高的多,由于JVM不用去处理泛型对类型的强制转换,这些工作都在编译器完成,所以可以带来潜在的性能收益。

四、什么是类型擦除
由于JVM里没有泛型,所以的泛型对于JVM来说都是普通类,当我们在使用泛型的时候,编译器就会将泛型代码中的类型完全擦出,使其变成原始类型,也就是编译后生成的字节码文件是不带泛型的,无界的泛型类型<T>擦除后的原始类型就是Object类型,有界泛型类型擦除之后的原始类型就是父类型,如 <T extends Person>,类型擦除后的原始类型就是Person类型。多重有界泛型类型擦除之后的原始类型就是第一个父类,如<T extends Animal&Person>,那么类型擦除后的原始类型就是Animal类。

五、泛型的上下边界
在使用泛型的时候,我们可以对传入的类型参数进行上下边界的限制,比如说,类型参数只准传入某种类型的父类或者某种类型的子类。
<T extends Number> 表示只能传入Number的子类

public class List<T extends Number>{
    private   T[] elements=(T[])new Object[10];//只能装Number子类的元素
    private int  size;//记录数据的长度

    public  void add(T element){ //设计一个添加元素的方法,不考虑扩容的情况
        elements[size]=element;
        size++;
    }
}
		List<String> list1=new List<>();//实际上这一行编译会报错String类不属于Number子类。
		//以下参数类型都是Number的子类不会报错
        List<Integer> list2=new List<>();
        List<Float> list3=new List<>();
        List<Double> list4=new List<>();

在泛型方法中添加上下边界限制,必须在权限声明和返回值之间的`上添加上下边界
如:

  public <? extends Number> T get(int index){//设计一个获取元素的方法
       return null;
    }

泛型的下界<? super Person>,
表示Person的所有父类,可以一直追溯到老祖宗Object

六、泛型通配符
我们在定义泛型时,会遇到各种不同的通配符,如:T,E,K,V,? 这是编码时一种约定俗成的东西,比如T也可以替换A~Z之间的任意字母,通常是这样约定的:
1.?代表不确定的java类型
2.T(type)表示一个具体的java类型
3.K V(key value)分别代表java中的键和值
4.E(element)代表Element

? 无界通配符
对于一个不确定或者不关心实际要操作的类型,可以使用一个无限制通配符<?>,表示可以持有任意类型,也可以用来表示类型参数的边界
下界通配符<? extends E>,表示这个泛型中的参数必须是E或者是E的子类
上界通配符<? extends E>,表示这个泛型中的参数必须是E或者是E的父类,可以追溯到Object

?与T的区别
1.?和T都可以表示不确定的类型,区别是我们可以对T进行操作,但是对?不行,如:

T t1=operate();//可以
? t2=operate();//不可以

?通常用于泛型方法的调用代码和形参,不可以定义类或者泛型方法。
2.T可以用来确保泛型参数一致性,?不可以,如:

public <T extends Number> T test1(List<T> ex)//这个可以保证返回值值或者参数类型都是T,确保参数一致性

public void test2(List<? extends Number a,List<? extends Number>>)

当T约定是Number的子类后,但声明时如果是其他的类型,就会出错,

3.T类型参数可以多重限定而?不行,例如:

<T extends A&B>

使用&符号设定多重边界,指定泛型T必须是A和B的共有子类。此时变量T就具有了所有限定的方法和属性,对于?来说,因为他不是一个确定的类型,所以不能多重限定。

3.通配符可以使用超类限定而T不行
T只有一种限定方式:<T extends A>
通配符?可以进行两种限定:

<? extends A>
<? super B>

五、使用泛型所需要注意的问题
1.当我们使用泛型需要用到基本类型时候,<>里只能填基本类的包装类型,例如 <Integer>、<Boolean>。这是由于在类型擦除的时候。会将泛型代码还原成原始类型(父类或者Object),基本类型不是任何一种类,所以必须使用他们的包装类。
2.我们定义了一个泛型类或者泛型方法,不一定要非要在<>里传入类型参数,如果不传入参数,使用泛型的方法和成员变量可以为任意类型。

  List list=new List();
        list.add("hello");
        list.add(1);
        System.out.println(list);

输出结果:

[hello, 1]

Process finished with exit code 0

3.使用泛型的时候,类型参数可以有多个,如常见的Map<String,Integer> 。
4.泛型只在编译期有效,泛型信息不会进入到运行时期。
5.不能对确切的泛型类型使用instanceof操作,编译时会报错。如下面操作是非法的。

if(example instanceof Example<Person>){
//..........
}

6.编译器对泛型的类型推断只对赋值操作有效,其他时候并不起作用,如果将一个泛型方法调用的结果作为一个参数,传递给另一个方法,这时候编译器并不会执行类型推断,它会认定,调用泛型方法之后,其返回值被赋给一个Object类型变量

  • 7
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
泛型定义使用方法如下所示: 1. 定义含有泛型的方法: 泛型定义在方法的修饰符和返回值类型之间,格式为:修饰符 <泛型> 返回值类型 方法名(参数列表(使用泛型)){ 方法体; } 在调用含有泛型的方法时,需要确定泛型的具体数据类型,传递什么类型的参数,泛型就是什么类型。 2. 示例代码: ```java public class GenericMethod { public <E> void method01(E e){ System.out.println(e); } } ``` 3. 泛型类的实现与使用泛型类的定义格式为:public class <T>{} 泛型接口的定义格式为:public interface <T>{} 泛型方法的定义格式为:public <T> method(T element){return element;} 4. 泛型方法的声明: 泛型方法的声明需要在修饰符与返回值类型之间添加泛型标识符 <T,E,...>,只有这种格式声明的方法才是泛型方法。 泛型标识符可以是任意类型,常见的如T,E,K,V等。 5. 泛型方法的使用: 普通泛型方法的使用与普通方法相同,根据方法的定义传递相应的参数即可。 综上所述,泛型定义使用方法包括定义含有泛型的方法、泛型类的实现与使用泛型方法的声明和泛型方法的使用。 #### 引用[.reference_title] - *1* [泛型定义使用](https://blog.csdn.net/Liamcsl/article/details/114438049)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [泛型定义使用](https://blog.csdn.net/qq_45036591/article/details/104034126)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [JAVA泛型-泛型方法的定义使用](https://blog.csdn.net/qq_39505245/article/details/120925331)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值