文章目录
- 什么是泛型
- 为什么需要泛型
- 泛型的使用
- 泛型的上界
- 泛型方法的使用
- 引出泛型方法
- 泛型是如何编译的
- 擦除机制
什么是泛型
首先什么是泛型呢?从字面上我们可以理解为广泛的类型,有一定c++基础的程序猿们应该了解,java中的泛型其实就是c++的模板但是使用起来比模板更加简单,那么没有c++基础的呢也没关系,其实泛型它在我们未来的编程中是经常使用的,我们在未来中呢其实并不知道某个方法或者属性应该用一个什么类型,比如说我要你实现一个类这个类里面要有个数组这个数组可以存储任何类型的变量,你应该怎么存储呢?
为什么需要泛型
正如上面所说我们在实际开发的时候很多时候都无法确定我们需要的类型是什么,这时候就需要使用到泛型了。那么泛型究竟应该如何使用呢?我们按照上面的列子来进行阐述
泛型的使用
class MyClass<T>{
public int a;
public T b;
public MyClass(int p,T b){
a=p;
this.b=b;
}
}
public class Main {
public static void main(String[] args) {
MyClass<Integer>m1=new MyClass<>(10,1);
MyClass<Integer >m2=new MyClass<>(10,2);
MyClass<String>m3=new MyClass<>(10,"hello");
}
}
那么看一下上面的代码我们逐步来进行解析,首先就是泛型的使用格式是
class ClassName<T>{
}
这个T也可以是E或者M任意字符都可以甚至可以是多个字符,这个T就是未来我们要实列化初的类型那么泛型类在实例化对象的时候该怎么实例化呢?
ClassName c<Integer>=new ClassName<>();
那么<>括号括起来的其实就是我们这个T要实例化出的对象名称了。那么有了这些基础我们来写一下上面提出的那个问题那就是写一个类,类中包含一个数组这个数组可以存储任意类型的数据。
class MyArrar<T>{
public Object[] object;
public MyArrar(int n){
object=new Object[n];
}
}
那么上面这个类就是我们实现的可以存储任意类型的数组了那么有些同学可能会有疑惑那这个跟T也没有任何的关系啊说这里用的是Object而不是T,其实这跟编译器运是有关系的我们也可以用T但是用T的话后面会面临很多的问题,因此我们跟源码保持一致就用Object。然后呢构造方法就是为了实列化出我们需要多大的数组空间。然后我们来写一下插入方法。
代码如下
class MyArrar<T>{
public Object[] object;
public MyArrar(int n){
object=new Object[n];
}
public void add(int pos,T value){
object[pos]=value;
}
}
为什么这里直接用一个等于就可以插入成功了呢?因为泛型有个前提条件就是,泛型必须得是一个类,因此我们讲过Objec是所有类的父类因此,这里可以直接进行等于号。
那么现在我又提出一个要求那就是找到这个数组中的最大值该怎么寻找呢?那么这时候就引出我们下一个知识点叫做泛型的上界。
泛型的上界
什么是泛型的上界呢?上界大家其实就可以理解为上行界限我们通过代码来进行描述
class Myclass2<T extends Integer>{
}
其实就是这样在模板后面加上一个extends再加上一个固定的类型即可那么这个表示什么意思呢?其实就是表示这个模板的类型T只能是Integer这个类型或者是继承了这个类型的派生类这个就是泛型的上界,那么回到我们最初的那个问题中,我们应该怎么去找到这个数组中的最大值呢?其实很简单我们既然想找到数组中的最大值也就是说这个类型必须得是可以比较的类型,那么既然可以比较也就是说必须实现了compareTo这个方法,并且我们在写的时候必须指明这个类是comparable(可比较的)。代码如下
class MyArrar<T extends Comparable<T>>{
public Object[] object;
public MyArrar(int n){
object=new Object[n];
}
public void add(int pos,T value){
object[pos]=value;
}
public T findMax(){
T max=(T)object[0];
for(int i=0;i<object.length;i++){
if(compareTo(max,object[i])==-1){
max=(T)object[i];
}
}
return max;
}
public int compareTo(T max,Object object){
return max.compareTo((T)object);
}
}
那么这里的方法调用顺序是什么样子的呢如下图
泛型方法的使用
引出泛型方法
这里给大家出一个问题那就是大家想想有没有这样一个方法就是它可以找到任何数组中的最大值。请记住是任何数组。
那么该怎么去实现这个方法呢?其实就是用泛型方法。那个格式如下
public<T,E,f....> T method_Name(){
}
那么上面那个问题该如何实现呢?我们把这个方法单独放入一个类中来实验一下吧。
class Mytest2{
public<T extends Comparable<T>> T findMax(T[] arg){//这里由于我们要找到一个——
//最大值因此我们传入的泛型中必须满足可以进行比较的。
T max=arg[0];
for(int i=0;i<arg.length;i++){
if(max.compareTo(arg[i])==-1){
max=arg[i];
}
}
return max;
}
}
泛型是如何编译的
擦除机制
这里要将一下擦除机制,泛型的编译时怎么进行的呢?就是擦除机制在编译过程中JVM通过你传入的类型从而将每个T进行一个擦除替代,那么写道这里想必大家也明白了其实为什么我们写一个***extends Comparable <T>***那么这个T就可以使用comapreTo方法了因为这个代码其实就是告诉编译器我这里这个T肯定是实现了comparaTo的。是可以进行比较的。