码迷,mamicode.com
首页 > 编程语言 > 详细

Java笔记:泛型

时间:2018-02-20 22:26:06      阅读:234      评论:0      收藏:0      [点我收藏+]

标签:允许   hid   min   自动   来替   信息   gets   return   super   

一、简单实例

技术分享图片
class Solution<T> {
    private T obj;

    Solution(T obj) {
        this.obj = obj;
    }

    public T getObj() {
        return obj;
    }

    public static void main(String[] args) {
        Solution<Integer> solution = new Solution<>(100);
        Object obj = solution.getObj();
        System.out.println(obj.getClass().getName());//java.lang.Integer
        System.out.println(obj);//100
    }
}
View Code


二、类型安全

若简单地使用Object来替代泛型并确保类型转换正确,那么即使不适用泛型也能得到相同的功能。但是如果类型转换不正确,程序就会在运行时发生错误,使用泛型可以自动确保类型安全,这个过程中消除了手动输入类型转换以及类型检查的需要,运行时的错误就可以转换为编译时的错误,这是泛型的主要优势。

 

三、多个类型参数

技术分享图片
class Solution<T, V> {
    private T objA;
    private V objB;

    Solution(T objA, V objB) {
        this.objA = objA;
        this.objB = objB;
    }

    public T getObjA() {
        return objA;
    }

    public V getObjB() {
        return objB;
    }

    public static void main(String[] args) {
        Solution<Character, Integer> solution = new Solution<>(‘0‘, 0);
        System.out.println(solution.getObjA());
        System.out.println(solution.getObjB());
    }
}
View Code

 

四、有界类型

通过指定超类限制能够传递给类型参数的类型。

技术分享图片
class Solution<T extends Number> {
    private T[] arr;

    double getSum() {
        double sum = 0;
        for (T i : arr)
            sum += i.doubleValue();
        return sum;
    }

    Solution(T... nums) {
        arr = nums;
    }

    public static void main(String[] args) {
        Solution<Integer> solution = new Solution<>(1, 2, 3, 4, 5);
        System.out.println(solution.getSum());
    }
}
View Code

除了指定超类作为边界之外,还可以指定接口作为边界。

五、通配符参数

技术分享图片
boolean sameSum(Solution<T> ob) {
        return getSum() == ob.getSum();
}
View Code

假设我们需要比较具有不同泛型参数的相同类型对象,上述代码并不能满足要求。只有当比较对象具有相同的泛型参数时,上述代码才可以被调用。正确的解决方法需要用到通配符,通配符同样可指定为有界。

技术分享图片
class Solution<T extends Number> {
    private T[] arr;

    double getSum() {
        double sum = 0;
        for (T i : arr)
            sum += i.doubleValue();
        return sum;
    }

    boolean sameSum(Solution<? extends Number> ob) {
        return getSum() == ob.getSum();
    }

    Solution(T... nums) {
        arr = nums;
    }

    public static void main(String[] args) {
        Solution<Integer> solutionA = new Solution<>(1, 2, 3, 4, 5);
        Solution<Double> solutionB = new Solution<>(5.0, 4.0, 3.0, 2.0, 1.0);
        System.out.println(solutionA.sameSum(solutionB));//true
    }
}
View Code

 

六、泛型方法

技术分享图片
class Solution {
    static <T extends Number, V extends Number> boolean contain(T[] arr, V x) {
        for (int i = 0; i < arr.length; i++)
            if (arr[i].doubleValue() == x.doubleValue())
                return true;
        return false;
    }

    public static void main(String[] args) {
        Double[] arr = {1.0, 2.0, 3.0, 4.0, 5.0};
        System.out.println(contain(arr, 1));
    }
}
View Code

构造函数同样支持泛型。

技术分享图片
class Solution {
    private double number;

    <T extends Number> Solution(T t) {
        number = t.doubleValue();
    }
}
View Code

 

七、泛型接口

泛型接口与泛型类相似。

技术分享图片
interface MinMax<T extends Comparable<T>> {
    T min();
    T max();
}

class Solution<T extends Comparable<T>> implements MinMax<T> {
    private T[] arr;

    @Override
    public T min() {
        T res = arr[0];
        for (int i = 1; i < arr.length; i++)
            if (res.compareTo(arr[i]) > 0)
                res = arr[i];
        return res;
    }

    @Override
    public T max() {
        T res = arr[0];
        for (int i = 1; i < arr.length; i++)
            if (res.compareTo(arr[i]) < 0)
                res = arr[i];
        return res;
    }

    Solution(T... nums) {
        arr = nums;
    }

    public static void main(String[] args) {
        Solution<Integer> ob = new Solution<>(1, 2, 3, 4, 5);
        System.out.println(ob.min());
        System.out.println(ob.max());
    }
}
View Code

 

八、历史遗留

早期的Java是不支持泛型的,现在仍然存在大量历史遗留代码。为了使这些遗留代码保留功能同时又和泛型兼容,Java允许使用泛型类而不提供任何类型参数,这会为类创建原始类型。原始类型与不使用泛型的遗留代码是兼容的,但失去了泛型的类型安全性。本质上就是使用Object替换了类型参数所表示的类型。

技术分享图片
class Solution<T> {
    private T ob;

    Solution(T ob) {
        this.ob = ob;
    }

    T getOb() {
        return ob;
    }

    public static void main(String[] args) {
        Solution solution = new Solution(new String("Hello World"));
        System.out.println(solution.getOb());
    }
}
View Code

 

九、泛型类层次

使用泛型超类。

技术分享图片
class A<T> {
    T a;

    A(T a) {
        this.a = a;
    }

    T getA() {
        return a;
    }
}

class B<T, V> extends A<T> {
    V b;

    B(T a, V b) {
        super(a);
        this.b = b;
    }

    V getB() {
        return b;
    }
}
View Code

泛型层次比较。

技术分享图片
class Solution {
    public static void main(String[] args) {
        B<String, String> obB = new B<>("Hello", "World");
        System.out.println(obB instanceof A<?>);//true
    }
}
View Code

当需要对泛型类进行强制转换时,必须确保其相互兼容并且泛型参数相同。

 

十、擦除

为了兼容以前的Java版本,对Java语言的语法或虚拟机所做的任何修改必须避免破坏以前的代码,所以Java使用擦除实现泛型。

擦除的工作原理:编译Java代码时,所有泛型信息被擦除。那么必须使用他们的界定类型替换类型参数,如果没有显式指定界定类型,就会使用Object。之后进行适当的类型转换以保持与类型参数所指定类型的兼容。这意味着允许时时没有类型参数的,Java泛型只是一种源代码机制,运行时的类型转换必然会带来开销。

 

十一、模糊性错误

技术分享图片
class Solution<T, V> {
    private T a;
    private V b;

    Solution(T a, V b) {
        this.a = a;
        this.b = b;
    }

    void set(T a) {
        this.a = a;
    }

    void set(V b) {
        this.b = b;
    }
}
View Code

上述代码出现了模糊性错误,当T和V为相同类型时,无法确定调用的方法。

 

十二、限制

  • 不能实例化类型参数的对象或数组。
  • 静态成员不能使用在类中声明的类型参数。
  • 泛型类不能扩展Throwable,即不能创建泛型异常类。

若要实例化泛型对象的数组,需要使用通配符。

技术分享图片
class Solution<T> {
    public static void main(String[] args) {
        Solution<Integer>[] solutionsA = new Solution<Integer>[10];//错误
        Solution<?>[] solutionsB = new Solution<?>[10];//正确
    }
}
View Code

 

Java笔记:泛型

标签:允许   hid   min   自动   来替   信息   gets   return   super   

原文地址:https://www.cnblogs.com/arseneyao/p/8455450.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!