Java 泛型(generics)详解及代码示例、Java 类型通配符详解及代码示例

Java 泛型(generics)详解及代码示例、Java 类型通配符详解及代码示例

- 概念
  • Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
  • java中使用泛型举例:
    • List接口也使用了泛型:
      在这里插入图片描述
    • ArrayList 是泛型类。
      在这里插入图片描述
- 泛型标记符:
  • Java中的泛型标记符有:
    1、E - Element (在集合中使用,因为集合中存放的是元素)
    2、T - Type(Java 类)
    3、K - Key(键)
    4、V - Value(值)
    5、N - Number(数值类型)
    6、? - 表示不确定的 java 类型
- 泛型分类
  • 泛型方法
  • 泛型类
- 泛型方法:
  • 泛型方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。定义泛型方法的规则如下:
    1、所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的 )。
    2、每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
    3、类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
    4、泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)。

  • 泛型方法代码示例:

//collectionReverse.java
import java.util.Arrays;
import java.util.Collections;

public class GenericMethodDemo {
    
    

    public static <E> void collectionReverse(E[] colArray){
    
    
        Collections.reverse(Arrays.asList(colArray));
        System.out.println("逆序后的集合的排列顺序为:"+Arrays.toString(colArray));
    }

    public static void main(String[] args) {
    
    
        Integer[] i = {
    
    1, 2, 3, 4, 5};
        Character[] c = {
    
    'G', 'e', 'n', 'e', 'r', 'i', 'c'};
        String[] s = {
    
    "first", "second", "third", "fourth", "fifth"};
        System.out.println("原序集合顺序为:"+Arrays.toString(i));
        collectionReverse(i);
        System.out.println("--------------------------------------");
        System.out.println("原序集合顺序为:"+Arrays.toString(c));
        collectionReverse(c);
        System.out.println("--------------------------------------");
        System.out.println("原序集合顺序为:"+Arrays.toString(s));
        collectionReverse(s);
    }

}

//执行结果如下:
//原序集合顺序为:[1, 2, 3, 4, 5]
//逆序后的集合的排列顺序为:[5, 4, 3, 2, 1]
//--------------------------------------
//原序集合顺序为:[G, e, n, e, r, i, c]
//逆序后的集合的排列顺序为:[c, i, r, e, n, e, G]
//--------------------------------------
//原序集合顺序为:[first, second, third, fourth, fifth]
//逆序后的集合的排列顺序为:[fifth, fourth, third, second, first]

//Process finished with exit code 0
  • 有界的类型参数:
    可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
  • 有界的类型参数代码示例:
//BoundedGenericMethodDemo.java
import java.util.Arrays;
import java.util.Collections;

public class BoundedGenericMethodDemo {
    
    

    public static <E extends Number> void collectionReverse(E[] colArray){
    
    
        Collections.reverse(Arrays.asList(colArray));
        System.out.println("逆序后的集合的排列顺序为:"+Arrays.toString(colArray));
    }

    public static void main(String[] args) {
    
    
        Integer[] i = {
    
    1, 2, 3, 4, 5};
        Character[] c = {
    
    'G', 'e', 'n', 'e', 'r', 'i', 'c'};
        String[] s = {
    
    "first", "second", "third", "fourth", "fifth"};
        System.out.println("原序集合顺序为:"+Arrays.toString(i));
        collectionReverse(i);
        System.out.println("--------------------------------------");
        System.out.println("原序集合顺序为:"+Arrays.toString(c));
        collectionReverse(c);
        System.out.println("--------------------------------------");
        System.out.println("原序集合顺序为:"+Arrays.toString(s));
        collectionReverse(s);
    }

}

//执行结果如下,由于定义了类型上限,即调用泛型方法传递的参数必须是Number 类的子类,所以传递Character[] 和 String[] 都会报错。将collectionReverse(c) 和 collectionReverse(s) 两行代码注释掉即可:
//java: 无法将类 com.example.utils.generic.BoundedGenericMethodDemo中的方法 collectionReverse应用到给定类型;
//  需要: E[]
//  找到: java.lang.Character[]
//  原因: 推断类型不符合上限
//    推断: java.lang.Character
//    上限: java.lang.Number
- 泛型类
  • 泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。
  • 泛型类代码示例:
//GenericClassDemo.java
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;

public class GenericClassDemo<K, V> {
    
    

    private K k;
    private V v;

    public void put(K k, V v){
    
    
        this.k = k;
        this.v = v;
    }

    public V get(K k){
    
    
        return v;
    }

    public static void main(String[] args) {
    
    

        GenericClassDemo<String, Character[]> gcd = new GenericClassDemo<>();
        gcd.put("java_say", new Character[]{
    
    'h','e','l','l','o','泛','型','类'});

        Character[] java_says = gcd.get("java_say");
        System.out.println("打印出来的值为:"+Arrays.toString(java_says));

    }

}

//执行结果如下:
//打印出来的值为:[h, e, l, l, o, 泛, 型, 类]

//Process finished with exit code 0

- 类型通配符
  • 类型通配符一般是使用 ? 代替具体的类型参数。例如 List<?> 在逻辑上是 List<String>, List<Integer> 等所有 List<具体类型实参> 的父类。
  • 只有泛型类的类型参数可以使用 ? 类型通配符来替换。代码示例如下:
//GenericClassBox.java
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class GenericClassBox<K, V> {
    
    

    private K k;
    private V v;

    public void put(K k, V v){
    
    
        this.k = k;
        this.v = v;
    }

    public V get(K k){
    
    
        return v;
    }

    public static void main(String[] args) {
    
    

        GenericClassBox<String, String> gcd1 = new GenericClassBox<>();
        gcd1.put("java_say","hello, 类型通配符");

        GenericClassBox<Integer, Integer> gcd2 = new GenericClassBox<>();
        gcd2.put(2,2);

        GenericClassBox<Character, String> gcd3 = new GenericClassBox<>();
        gcd3.put(new Character('a'), "bc");

        getValue(gcd1);
        System.out.println("--------------------------");
        getValue(gcd2);
        System.out.println("--------------------------");
        getValue(gcd3);



    }

    public static void getValue(GenericClassBox<?,?> data){
    
    
        System.out.println("使用通配符获取到的值为:"+data.v);
    }

}

//执行结果如下:
//使用通配符获取到的值为:hello, 类型通配符
//--------------------------
//使用通配符获取到的值为:2
//--------------------------
//使用通配符获取到的值为:bc

//Process finished with exit code 0
  • 有界的类型通配符:
    1、<? extends T>表示该通配符所代表的类型是T类型的子类。
    2、<? super T>表示该通配符所代表的类型是T类型的父类。

  • 有界的类型通配符代码示例:

//BoundedGenericClassBox.java
public class BoundedGenericClassBox<K, V> {
    
    

    private K k;
    private V v;

    public void put(K k, V v){
    
    
        this.k = k;
        this.v = v;
    }

    public V get(K k){
    
    
        return v;
    }

    public static void main(String[] args) {
    
    

        BoundedGenericClassBox<Integer, String> gcd1 = new BoundedGenericClassBox<>();
        gcd1.put(1,"hello, 有界的类型通配符");
        getValue(gcd1);

    }

    public static void getValue(BoundedGenericClassBox<? extends Number,? super String> data){
    
    
        //第一个类型通配符 ? 代表的类型必须是Number的子类
        //第二个类型通配符 ? 代表的类型必须是String的父类
        System.out.println("使用有界的通配符获取到的值为:"+data.v);
    }

}

//执行结果如下:
//使用有界的通配符获取到的值为:hello, 有界的类型通配符

//Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/qq_38132105/article/details/125818943