一文带领大家了解什么是泛型

简介: 一文带领大家了解什么是泛型

对于泛型!其实大家了解不是很多,在各大高校的学习中,如果你不去深入的了解泛型,老师只是会一水儿过,并不会单独去带领大家了解!!那么,笔者结合自身的学习泛型的想法,结合了一些课件,索性写出了一篇关于泛型的简单博客,来带领大家了解泛型!!


一般的类和方法,只能使用具体的类型: 要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的 代码,这种刻板的限制对代码的束缚就会很大。


                                                                           ----- 来源《Java编程思想》对泛型的介绍。


简而言之,泛型:就是适用于许多许多类型,从代码上讲,就是对类型实现参数化!


在Java语法中,泛型是一个较难的语法,但是,在目前这个博客中,笔者仅仅讲解一部分,目前所接触的只是一丢丢!!后续在数据结构进阶阶段将会深入了解泛型!!


引出泛型??


实现一个类,类中包含一个数组成员,使得这个数组可以实现存放任何类型的数据,也可以根据成员方法返回数组中的某个下标的值??


解题思路:


我们之前学过的数组,只能存放指定类型的元素!

int[] array = new int[10];
String[] strs = new String[10];

所有类的父类默认为Object类,数组是否可以创建为Object类??

下面请看笔者根据上面两个思路所进行书写的代码:


class MyArray {
    public Object[] obj = new Object[3];
    public Object getPos(int pos) {
        return obj[pos];
    }//返回所对应的pos下标的值
    public void setObj(int pos , Object val) {
        obj[pos] = val;
    }//将数组下标为pos的元素赋值为val
}
public class Test {
    public static void main(String[] args) {
      MyArray myArray = new MyArray();
      myArray.setObj(0,10);//存放整型
        myArray.setObj(1,"hello"); //存放字符串
        myArray.setObj(2,10.56); //存放double类型 
        //实现了存储任意类型的数据!
    }
}


对于上述代码,实现了一个数组,并且该数组内部可以存放任何数据,但是,当我们想要打印该数组中的某下标的值时,列如: double d = myArray.getPos(2); 这样写会进行报错!!


0a2653c851af460fa595bd959398a8f1.png


当我们进行强制类型转化的时候,double d = (double) myArray.getPos(2); 不会进行报错了!!


2d65d23f6d4748949b924e4057485923.png


那么疑问又来了,笔者现在定义的数组很小,我们可以看到数组里面存储的数据类型,但是,当我们定义一个很大很大的数组时,当输出某一元素的时候,又怎能知道该下标所对应的元素类型呢??


上述代码实现后,我们可以发现:


任何类型的数据都可以存放

获取数据的时候(double d = myArray.getPos(2) ),编译报错,必须进行强制类型转化

虽然在这种情况下,当前数组任何数据都可以存储,但是,更多情况下,我们还是希望他只能持有一种数据类型,而不是同时持有这么多的类型,所以,泛型,的主要目的,就是指定当前的容器,要 持有什么类型的对象,让编译器去做检查,此时,就需要把类型作为参数进行传递,需要什么类型,就传入什么类型!!


下面请看笔者的简单的代码:


class MyArray<T> {
    //public Object[] obj = new Object[3];
    public T[] obj = (T[])new Object[3];
    //先这样理解,会有警告
    //在Java官方不会这样去写
    public T getPos(int pos) {
        return obj[pos];
    }//返回所对应的pos下标的值
    public void setObj(int pos , T val) {
        obj[pos] = val;
    }//将数组下标为pos的元素赋值为val
}
public class Test {
    public static void main(String[] args) {
        MyArray<Integer> myArray = new MyArray<Integer>();
        //实列化对象的同时,指定当前泛型类的指定参数类型是Integer
        //然后就可以进行存储指定的数据类型
        myArray.setObj(0,10);
        myArray.setObj(1,78);
        myArray.setObj(2,99);
        //myArray.setObj(0,"sjd");//传入不是整型的数据,会进行报错
        Integer d = myArray.getPos(2);  //不需要强制类型转化
    }
}


对于上述代码,便是泛型的简单应用,如果您能看懂上述的代码,那么,恭喜你,对于泛型的简单应用,你已经学会了!!


对于泛型,有着下面几个简单的意义:


存储数据的时候,可以帮助我们进行自动的类型检查

获取元素的时候,可以帮助我们进行类型转化

上述的两点意义,是在编译的时候,就进行的,因此,泛型是编译时期的一种机制,在运行的时候,没有泛型的概念!!


下面来带领大家走进泛型的语法!!


语法1:


语法1:


class 泛型类名称 <类型形参列表> {
// 这里可以使用类型参数
}


语法1 的使用情况为


class ClassName<T1,T2,T3…………Tn> {
…………
}


语法2:


class 泛型类名称 <类型形参列表> extends 继承类/* 这里可以使用类型参数 */
{
// 这里可以使用类型参数
}


语法2:


class ClassName<T1,T2,T3…………Tn> extends ParentClass<T1> {
// 可以只使用部分类型参数
}



对于上述的类名后的<T> 代表占位符,表示当前类是一个泛型类!!


了解一下: ;类型形参一般使用一个大写字母表示,常用的占位符有:


E   表示:Element

K   表示:Key

V   表示:Value

N   表示:Number

T   表示:Type

S,U,V等等,第二,第三,第四个类型

在上述占位符中,E , K , V , T 所应用的比较多!!谨记,其实对于上述的用法,笔者也……尴尬了!


值得注意的是:不可以new 一个泛型类型的数组(语法规定)比如:public T[] obj = new T[3]; 这个就是一个错误的做法!因此,泛型当中,不能实列化一个泛型类型的数组!!!


小结一下,瞬间开心:


泛型是将数据类型参数化进行传递

MyArray<Integer> myArray = new MyArray<Integer>();

使用<T>,表示当前类是一个泛型类

泛型目前为止的优点:数据类型参数化,编译时自动进行检查和转化

运行的时候,没有泛型的概念,编译完成之后,泛型被擦除为Object(擦除机制仅作了解即可)

在Java的泛型机制是在编译级别实现的,编译器生成的字节码在运行的期间,并不包含泛型的类型信息


下面笔者就Java当中,泛型的正确写法,来简单书写一下:(以后将会经常使用)Java官方的写法!


 

public Object[] obj = new Object[3];
    public E getPos(int pos) {
         return (E)obj[pos];
    }

对于上述代码的简单解析:


6de278e6d6694ce5bb08e7e842b7e74b.png


上面笔者简单的介绍了一下泛型,那么,就用泛型来实现一个小小的练习题吧!!


实现一个泛型,泛型类里面写一个方法,来求得数组的最大值??


对于这个方法,我们可以根据最原始的:求数组的最大值的代码,来进行简单改写,然后改编成为我们想要的代码!


抛开泛型,我们在以前在数组中寻找最大值的代码为:


//抛开泛型,我们在以前在数组中寻找最大值的代码为:
class Alg{
    public int findMax(int[] array) {
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (max < array[i]) {
                max = array[i];
            }
        }
        return max;
    }
}

对于上述代码,想必,到目前为止,大家已经了然于胸了吧!!不用在进行讲解了!!


那么,笔者就根据上述的代码进行简单改写一下,然后就出现我们想要的泛型写法了!!请大家仔细对比一下哟!


class Alg<E extends Comparable<E>>{
    public E findMax(E[] array) {
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}
public class Test2 {
    public static void main(String[] args) {
        Alg<Integer> alg = new Alg<>();
        Integer[] array = {1,4,7,29,20,48,21,23};
        Integer val =alg.findMax(array);
        System.out.println(val);
    }
}


上述代码,便是用泛型来实现要求!!代码的运行结果为:


12c3b7f3f8814309a195c64f051d4445.png


简单解析一下吧!:


34e8d716411043c08c7ffba9fbba23de.png


上述代码是一个泛型类,那么有没有泛型方法呢??那么,请看笔者下面的代码吧!来带领大家用泛型方法来实现一下题目需求!!


//泛型方法
class Alg{
    public <E extends Comparable<E>> E findMax(E[] array) {
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}
public class Test2 {
    public static void main(String[] args) {
       Alg alg = new Alg();
        Integer[] array = {1,4,7,29,20,48,21,23};
        Integer val =alg.findMax(array);
        System.out.println(val);
    }
}

上述的代码,就是用泛型方法来实现,求得数组中的最大值!


代码的运行结果也是正确的!!


92ba0822ed0b46e1ae72df8a17d3a45b.png


对于这个方法,必须通过对象的引用才能调用!!


思考一下,如果我们不想通过对象的引用,那么我们应该怎么办??


很简单,将其改为静态(static)修饰的的不就行了吗??


请看笔者代码:


//泛型的静态方法
class Alg{
    public static  <E extends Comparable<E>> E findMax(E[] array) {
        E max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}
public class Test2 {
    public static void main(String[] args) {
        Integer[] array = {1,4,7,29,20,48,21,23};
        Integer val =Alg.findMax(array);
        System.out.println(val);
    }
}


上述代码,就是用静态(static)来修饰的!!


静态方法不依赖于对象,可以通过类名进行访问!!


对于此篇博客,有不懂的各位老铁,欢迎来咨询


相关文章
|
9月前
|
存储 编译器 C语言
c++的学习之路:5、类和对象(1)
c++的学习之路:5、类和对象(1)
76 0
|
9月前
|
存储 编译器 C++
c++的学习之路:6、类和对象(2)
c++的学习之路:6、类和对象(2)
55 0
|
9月前
|
C++
c++的学习之路:7、类和对象(3)
c++的学习之路:7、类和对象(3)
63 0
|
3月前
|
设计模式 监控 算法
Python编程中的设计模式应用与实践感悟###
在Python这片广阔的编程疆域中,设计模式如同导航的灯塔,指引着开发者穿越复杂性的迷雾,构建出既高效又易于维护的代码结构。本文基于个人实践经验,深入探讨了几种核心设计模式在Python项目中的应用策略与实现细节,旨在为读者揭示这些模式背后的思想如何转化为提升软件质量的实际力量。通过具体案例分析,展现了设计模式在解决实际问题中的独特魅力,鼓励开发者在日常编码中积极采纳并灵活运用这些宝贵的经验总结。 ###
|
3月前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践感悟####
本文作为一篇技术性文章,旨在深入探讨Python编程中设计模式的应用价值与实践心得。在快速迭代的软件开发领域,设计模式如同导航灯塔,指引开发者构建高效、可维护的软件架构。本文将通过具体案例,展现设计模式如何在实际项目中解决复杂问题,提升代码质量,并分享个人在实践过程中的体会与感悟。 ####
|
4月前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践###
【10月更文挑战第18天】 本文深入探讨了Python编程中设计模式的应用与实践,通过简洁明了的语言和生动的实例,揭示了设计模式在提升代码可维护性、可扩展性和重用性方面的关键作用。文章首先概述了设计模式的基本概念和重要性,随后详细解析了几种常用的设计模式,如单例模式、工厂模式、观察者模式等,在Python中的具体实现方式,并通过对比分析,展示了设计模式如何优化代码结构,增强系统的灵活性和健壮性。此外,文章还提供了实用的建议和最佳实践,帮助读者在实际项目中有效运用设计模式。 ###
40 0
|
7月前
|
设计模式 安全 Java
技术成神之路:设计模式(一)单例模式
【7月更文挑战第3天】技术成神之路:设计模式(一)单例模式
53 1
|
9月前
|
存储 算法 程序员
C++模板编程与泛型技术探秘
这篇文章探讨了C++中的模板编程和泛型技术,这两种技术增强了代码复用和抽象能力。文章介绍了函数模板和类模板的概念,通过示例展示了如何定义和使用它们。泛型技术是一种编程范式,强调编写与类型无关的代码,提高代码复用性和灵活性。C++11后的版本通过类型萃取和变长模板参数进一步扩展了模板功能。模板和泛型广泛应用在数据结构、算法、库和框架的开发中,如STL。掌握这些技术有助于编写更高效、灵活的代码,并推动软件开发的创新和进步。
|
8月前
|
存储 Java 编译器
Java核心技术第八章-泛型
Java核心技术第八章-泛型
|
9月前
|
安全 Java 程序员
Java泛型编程:技巧与实践
Java泛型编程:技巧与实践
110 1