Java 泛型 详解笔记(Generic) <?>

遇到布懂的就收藏下来,学完一遍后返回再看一遍就好了,加油!

一、Java泛型是什么

Java 泛型(generics)是 JDK 5 中引入的一个新特性,

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数,然后在使用的时候/调用的时传入具体的类型。

二、泛型有什么用

泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

如下代码中,不使用泛型:


import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * 需求:collection集合存储字符串并遍历
 */
public class GenericDemo01 {
    public static void main(String[] args) {
        Collection c=new ArrayList();
        //添加元素
        c.add("Hello");
        c.add("World");
        c.add("Algorithm");
        //添加不同类型的元素
        c.add(100);
        //遍历集合
//这样是正确的:
//        Iterator it=c.iterator();
//        while(it.hasNext()){
//            Object obj=it.next();
//            System.out.println(obj);
//        }
//这样是错误的:
        Iterator it=c.iterator();
        while(it.hasNext()){
            String s=(String)it.next();//ClassCastException
            System.out.println(s);
            //上面添加类型时可以任意添加,但是在我们写代码的时候可能只是以为只有String一种类型,这时就会出现类型转化异常
        }
/*错误的输出:
        Hello
        World
        Algorithm
        Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        at com.ArrayListTest.GenericDemo01.main(GenericDemo01.java:28)
*/
    }
}

使用泛型后的对比:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * 需求:collection集合存储字符串并遍历
 */
public class GenericDemo01 {
    public static void main(String[] args) {
        Collection<String> c=new ArrayList<>();
        //添加元素
        c.add("Hello");
        c.add("World");
        c.add("Algorithm");
        //添加不同类型的元素
       // c.add(100);//此时  此处会报错,在编译前就发现错误
        //遍历集合
        Iterator<String> it=c.iterator();
        while(it.hasNext()){
            String s=it.next();//此处也就不用强制类型转换
            System.out.println(s);
        }//这样是错误的
    }
}

泛型可以用在类、方法和接口中,分别被称为泛型类、泛型方法和泛型接口。
好处: 把运行期的问题提前到编译器,避免强制类型转换。

三、泛型定义格式

<类型> :指一种类型的格式。这里的类型可以看成形参
<类型1,类型2…> :指多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成形参。
举例:

Collection<String> c=new ArrayList<String>();

HashMap<String,String> hm=new HashMap<String,String>(); 

泛型具体应用:

1. 泛型方法
定义格式:修饰符 <类型> 返回值类型 方法名 (类型 变量名)

eg:public  <T> void show(T  t){  }
  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

实例:

public class GenericMethodTest {
    // 泛型方法 printArray
    public static < E > void printArray( E[] inputArray )
    {
        // 输出数组元素
        for ( E element : inputArray ){
            System.out.printf( "%s ", element );
        }
        System.out.println();
    }
    public static void main(String[] args) {
        // 创建不同类型数组: Integer, Double 和 Character
        Integer[] intArray = { 1, 2, 3, 4, 5 };
        Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
        Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
        System.out.println( "整型数组元素为:" );
        printArray( intArray  ); // 传递一个整型数组
        System.out.println( "\n双精度型数组元素为:" );
        printArray( doubleArray ); // 传递一个双精度型数组

        System.out.println( "\n字符型数组元素为:" );
        printArray( charArray ); // 传递一个字符型数组
    }
}

2. 泛型类

  • 泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。
  • 和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。

下面用一个实例来说明泛型类的定义格式:


public class Box<T> {
    private T t;

    public void add(T t) {
        this.t = t;
    }

    public T get() {
        return t;
    }

    public static void main(String[] args) {
        Box<Integer> integerBox = new Box<Integer>();
        Box<String> stringBox = new Box<String>();

        integerBox.add(new Integer(11));
        stringBox.add(new String("泛型类定义"));

        System.out.printf("整型值为 :%d\n\n", integerBox.get());
        System.out.printf("字符串为 :%s\n", stringBox.get());
    }
}

3. 泛型接口
定义格式:修饰符 interface 接口名<类型>{ }

 示例:public interface Generic<T>{ }

具体实现可以参照List接口的实现类

如下实例:
定义一个接口Generic

public interface Generic<T> {
    void show(T t);
}

一个实现类:

public class GenericImol<T> implements Generic<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

一个测试类:

public class GenericDemo {
    public static void main(String[] args) {
        Generic<String> g1=new GenericImol<String>();
        g1.show("泛型接口示例");

        Generic<Integer> g2=new GenericImol<Integer>();
        g2.show(666);

        Generic<Double> g3=new GenericImol<Double>();
        g3.show(66.6);
    }
}

类型通配符

类型通配符: <?>

  1. 如:List<?> 表示类型未知的List 。它的元素可以匹配任意类型。
    说明:带通配符的List仅表示是List,List 等所有List<具体类型实参>的父类。

如下实例:


import java.util.ArrayList;
import java.util.List;

public class GenericDemo02 {
    public static void main(String[] args) {
        List<String> name=new ArrayList<>();
        List<Integer> age=new ArrayList<>();
        List<Number> number=new ArrayList<>();

        name.add("Generic");
        age.add(666);
        number.add(111);

        getData(name);
        getData(age);
        getData(number);
    }
    public static void getData(List<?> data){
        System.out.println("data:"+data.get(0));
    }
}

getData的参数是List类型的,所以当name,age,number作为方法实参只因为通配符的作用。

  1. 如果不希望List<?>是任何泛型List的父类,只希望它代表一类泛型 list 的父类,可以使用类型通配符的上限

类型通配符上限:<? extends 类型>

例如:List<? extends Number> 表示的类型是Number或其子类型。

类型通配符下限: <? super 类型>

例如:List<? super Number> 表示的类型是Number或其父类型。

实例演示:


import java.util.ArrayList;
import java.util.List;
public class GenericDemo03 {
    public static void main(String[] args) {
        //类型通配符  <?>
        List<?> list1=new ArrayList<Object>();
        List<?> list2=new ArrayList<Number>();
        List<?> list3=new ArrayList<Integer>();
        //类型通配符上限  <?>
        //List<? extends Number> list4=new ArrayList<Object>();//会报错
        List<? extends Number> list5=new ArrayList<Integer>();
        List<? extends Number> list6=new ArrayList<Double>();
        List<? extends Number> list7=new ArrayList<Number>();
        //类型通配符下限
        //List<? super Number> list8=new ArrayList<Integer>();//会报错
        List<? super Number> list9=new ArrayList<Number>();
        List<? super Number> list10=new ArrayList<Object>();

    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr小布懂

谢谢那么帅还对我这么好

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值