【Java】0601 泛型、集合

一、什么是泛型?泛型可以做什么?

1、Java 泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

2、通俗的来讲,就是不同的数据类型要做一个相同的操作,比如排序,求最大值等。用泛型可以用一个相同方法对代替。

3、案例

package com.hao.base;

/**
 * @author haoxiansheng
 * Generics 泛型类
 * T - 这是参数传递给泛型类的泛型类型,可以取任何对象
 * t - 泛型类型T的一个实例
 */
public class Generics<T> {

    private T t;

    public Generics(T t) {
        this.t = t;
    }

    public T getT() {
        return t;
    }

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

    @Override
    public String toString() {
        return "Generics{" +
                "t=" + t +
                '}';
    }

    public void print() {
        System.out.println(t);
    }
}

// 测试
package com.hao.base;

/**
 * @author haoxiansheng
 */
public class Test1 {
    public static void main(String[] args) {
        Generics<Integer> integerGenerics = new Generics<>(9);
        integerGenerics.print();
        Generics<String> stringGenerics = new Generics<>("hello");
        stringGenerics.print();
    }
}

二、泛型定义规则

1、所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。

2、每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

3、类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

4、泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是基本类型(像int,double,char的等)。

5、命名规约

E - 元素,主要由Java集合(Collections)框架使用。

K - 键,主要用于表示映射中的键的参数类型。

V - 值,主要用于表示映射中的值的参数类型。

N - 数字,主要用于表示数字。

T - 类型,主要用于表示第一类通用型参数。

S - 类型,主要用于表示第二类通用类型参数。

U - 类型,主要用于表示第三类通用类型参数。

V - 类型,主要用于表示第四个通用类型参数。

6、例子

package com.hao.base;

import java.util.*;

/**
 * @author haoxiansheng
 */
public class GenericsTest1 {

    public static <E> void printArray(E[] inputArray) {
        for (E e : inputArray) {
            System.out.println(e);
        }
    }

    public static <E> void printArray(List<E> inputs) {
        inputs.forEach(System.out::println);
    }

    public static <K, V> void printMap(Map<K, V> map) {
        map.forEach((k, v) -> {
            System.out.println(k);
            System.out.println(v);
        });
    }


    /**
     * 比较大小
     * @param x
     * @param y
     * @param z
     * @param <T>
     * @return
     */
    public static <T extends Comparable<T>> T maximun(T x, T y, T z) {
        T max = x; // 假设x最大
        if (y.compareTo(max) > 0) {
            max = y;
        }
        if (z.compareTo(max) > 0) {
            max = z;
        }
        return max;
    }

    /**
     * 通配符 任何类型都可以
     * @param data
     */
    public static void printData(List<?> data) {
        data.forEach(System.out::println);
    }

    static class GenericsDemo<T, S> {
        private T t;

        private S s;

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

        @Override
        public String toString() {
            return "GenericsDemo{" +
                    "t=" + t +
                    ", s=" + s +
                    '}';
        }
    }


    public static void main(String[] args) {
        int[] a = {1, 2, 3};
        Integer[] b = {1, 2, 3};
        Map<String, Integer> map = new HashMap<>();
        map.put("1", 2);
        // error
        //printArray(a); // 不能使用基本数据类型
        printArray(b);
        System.out.println("=========");
        printMap(map);
        System.out.println("====通配符测试=====");
        List<String> strings = new ArrayList<>();
        strings.add("a");
        strings.add("b");
        printData(strings);
        ArrayList<Integer> integers = new ArrayList<>();
        printData(integers);
    }

}

三、类型推断

1、类型推断表示Java编译器查看方法调用及其对应的声明,以检查和确定类型参数。推断算法检查参数的类型,如果可用,则返回分配的类型。

Generics<T> generics = new Generics<>();
<>:尖括号运算符表示类型推断

四、类型擦除

1、泛型在编译时用于更严格的类型检查,并提供泛型编程。 要实现通用行为,java编译器应用类型擦除。

2、类型擦除是指编译器使用实际的类或桥接方法替换泛型参数的过程。 在类型擦除中,编译器确保不会创建额外的类,并且没有运行时开销。
类型擦除规则

用通用类型的类型参数替换其绑定的有界类型参数。

如果使用无界类型参数,则使用Object替换类型参数。

插入类型转换以保护类型安全。

生成桥接方法以在扩展通用类型中保持多态。

五、泛型语法

1、语法一

package com.hao.base;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author haoxiansheng
 */
public class GenericsTest2 {
    public static void main(String[] args) {
        //String  maximun1 = printNumber("1"); // 错误
        Integer maximun = printNumber(1);

    }

    /**
     * 声明有界泛型参数
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T extends Number> T printNumber(T t) {
        System.out.println(t);
        return t;
    }

    /**
     * 类型参数可以有多个边界
     * @param x
     * @param y
     * @param z
     * @param <T>
     * @return
     */
    public static <T extends Number & Comparable<T>> T maximun(T x, T y, T z) {
        T max = x;
        if (y.compareTo(max) > 0) {
            max = y;
        }
        if (z.compareTo(max) > 0) {
            max = z;
        }
        return max;
    }

    // list 泛型
    public <E> void printListGenerics(List<E> generics) {
        generics.forEach(System.out::println);
    }

    // set 泛型
    public <E> void printSetGenerics(Set<E> generics) {
        generics.forEach(System.out::println);
    }

    // map 泛型
    public <K,V> void printMapGenerics(Map<K,V> generics) {
        generics.forEach((k, v) ->{
            System.out.println(k);
            System.out.println(v);
        });
    }

    // 上限通配符 使用带有通配符的extends关键字
    public void printExtendsGenerics(Set<? extends Comparable> generics) {
        generics.forEach(System.out::println);
    }

    // 下界通配符 使用带有通配符的super关键字
    public <E> void printSuperGenerics(Set<? super GenericsTest2> generics) {
        generics.forEach(System.out::println);
    }

    // 无界通配符 使用未绑定的通配符 可以使用Object类方法访问变量
    public <E> void printObjectGenerics(Set<?> generics) {
        generics.forEach(System.out::println);
    }

}

2、语法二

package com.hao.base;

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

/**
 * @author haoxiansheng
 */
public class GenericsTest3 {
    public static void main(String[] args) {
        /**
         * 1
         * 错误操作 泛型不能使用原始类型
         */
        // IntTest<int> intTest = new IntTest<int>();
        IntTest<String> stringIntTest = new IntTest<>();
        IntTest<Integer> integerIntTest = new IntTest<>();
        printIntTest(stringIntTest);
        printIntTest(integerIntTest);

        /**
         * 2
         * 类型转换错误 泛型不能转换类型
         */
        IntTest<Number> number = new IntTest<>();
        number.setT(7);
        IntTest<Integer> integer = new IntTest<>();
       //integer = (IntTest<Integer>) number;
        integer = transform(number);
        System.out.println(integer);

        /**
         * 5
         * 泛型不能使用instanceof运算符
         *
         * 编译器使用类型擦除,运行时不会跟踪类型参数,IntTest <Integer>和IntTest <String>之间的运行时差异无法使用instanceOf运算符进行验证。
         */
        // if(integerIntTest instanceof IntTest<Integer>)

        /**
         * 6
         * 不允许使用参数化类型的数组
         *
         * 因为编译器使用类型擦除,类型参数被替换为Object,可以向数组添加任何类型的对象。但在运行时,代码将无法抛出ArrayStoreException。
         */

    }

    private static void printIntTest(IntTest intTest) {
        System.out.println(intTest);
    }

    private static IntTest<Integer> transform(IntTest<?> intTest) {
        IntTest<Integer> integer = (IntTest<Integer>) intTest;
        return integer;
    }

    /**
     * 3
     * 类型参数不能用于在方法中实例化其对象
     *
     * @param e
     * @param <E>
     * @return
     */
    public static <E> List<E> add(IntTest<E> e) {
        List<E> list = new ArrayList<>();
        // 错误的操作
        //E e = new E();
        //list.add(e);
        return list;
    }


    /**
     * 需要利用反射机制实现
     *
     * @param intTest
     * @param clazz
     * @param <E>
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <E> void add(IntTest<E> intTest, Class<E> clazz)
            throws IllegalAccessException, InstantiationException {
        List<IntTest<E>> list = new ArrayList<>();
        E e = clazz.newInstance();
        intTest.setT(e);
        list.add(intTest);
    }

    static class IntTest<T> {
        /**
         * 4
         * 使用泛型时,类型参数不允许为静态(static)。
         * 由于静态变量在对象之间共享,因此编译器无法确定要使用的类型。
         */
        //private static T t;
        private T t;

        public T getT() {
            return t;
        }

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

        @Override
        public String toString() {
            return "IntTest{" +
                    "t=" + t +
                    '}';
        }

        public void printInt() {
            System.out.println(t);
        }
    }

    /**
     * 7
     * 泛型不能使用异常
     * 通用类不允许直接或间接扩展Throwable类。
     */
//    class Box<T> extends Throwable{
//
//    }
    class Box<T extends Throwable> {
        /**
         * 9
         * 一个类不允许有两个重载方法,可以在类型擦除后使用相同的签名
         */
        //public void print(List<String> stringList) { }
        //public void print(List<Integer> integerList) { }

    }

    /**
     * 8
     *
     * 在一个方法中,不允许捕获一个类型参数的实例
     */



}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值