java泛型

什么是泛型?

泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

我们为什么要使用泛型?

我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类型不同。然而,泛型可以很轻松的解决这个问题。

用一个小小的例子简单看看:

public class Point <T>{
    private T var;
    public T getVar(){
        return var;
    }
    public void setVar(T var){
        this.var=var;
    }

}
public class test {

    public static void main(String[] args) {
        Point<String> p1 = new Point<String>();
        p1.setVar(30 + "");
        Point<Integer> p2 = new Point<Integer>();
        p2.setVar(30);
        System.out.println(p1.getVar());
        System.out.println(p2.getVar());
    }

}

运行结果如下:

从代码中可以很明显的看出泛型的优势。

同时,泛型可以使程序操作更加安全,可以避免发生类转换异常。当然还可以提高代码重用率。

泛型的基本应用

 泛型的定义:

类定义:

  【访问权限】 class 类名称 <泛型类型标识1,泛型类型标识2,……,泛型类型标识n>{

  【访问权限】 泛型类型标识 变量名称;

  【访问权限】 泛型类型标识 方法名称(){};

  【访问权限】 返回值类型声明 方法名称(泛型类型标识 变量名称){};

}

对象定义:

类名称<具体类> 对象名称=new 类名称<具体类>();

注意:

  1. 在上面的例子中,Point类中使用了"<T>",T表示此类型是由外部调用本类时指定的,使用任意字母均可,如<A>、<Y>都可以,为了突出type(表示类型)才使用的T。
  2. 另外,泛型是无法指定基本数据类型的,必须设置成一个类,因此在设置一个数字时就必须使用包装类。
  3. 如果设置的内容与泛型所指定的类型不一致,则会在编译时出错。
  4. 可以在声明类时指定多个泛型类型。如class A<K,V>{}
  5. 在泛型应用中最好在声明类对象时指定好其内部的数据类型,如Info<String>,否则在使用时会出现不安全操作的警告信息。(不影响程序运行)

通配符的使用:

在泛型类的操作中,在进行引用传递时,泛型类型必须匹配才可以传递。

例如将上面的例子改成:

public class test {

    public static void main(String[] args) {
        Point<String> p1 = new Point<String>();
        p1.setVar(30 + "");
        fun(p1);
    }

    private static void fun(Point<Object> p1) {
        System.out.println(""+p1.getVar());        
    }

}

会有如下的错误提示:

另外,我们还可以直接去掉<Object>,可正常运行。但是,不指定泛型类型不符合习惯,因此引入了通配符“?”,表示接收此类型的任意泛型对象。修改如下:

public class test {

    public static void main(String[] args) {
        Point<String> p1 = new Point<String>();
        p1.setVar(30 + "");
        fun(p1);
    }

    private static void fun(Point<?> p1) {
        System.out.println(""+p1.getVar());        
    }

}

注意:如果使用"?"接收泛型对象时,则不能设置被泛型指定的内容。如:Point<?> p1 = new Point<String>();

受限泛型:

泛型上限使用extends关键字声明,表示泛型的类型可能是所指定的类型或者是此类型的子类。

泛型下限使用super进行声明,表示泛型的类型可能是所指定的类型,或者是此类的父类,或是Object类。

具体格式:

设置上限:(声明对象)类名称<? extends 类> 对象名称      (定义类)[访问权限] 类名称<泛型标识 extends 类>

设置下限:(声明对象)类名称<? super 类> 对象名称    (定义类)[访问权限] 类名称<泛型标识 super 类>

同样以最上面的例子做修改:

public class test {

    public static void main(String[] args) {
        Point<Integer> p1 = new Point<Integer>();
        p1.setVar(30 );
        fun(p1);
    }

    private static void fun(Point<? extends Number> p1) {
        System.out.println(""+p1.getVar());        
    }

}

运行结果如下:(可正常运行)

注意:

一个类的子类可以通过对象的多态性为其父类实例化,但是在泛型操作中,子类的泛型类型是无法使用父类的泛型类型接收的,

如:

public static void main(String[] args) {
        Point<Integer> p1 = new Point<Integer>();
        Point<Number> p2 = new Point<Number>();
        p2=p1;
    }

编译时会出错:

这里为什么不能向上转型呢?

如果将子类泛型变为父类泛型,则表示扩大了子类的内容。打个比方:p1和p2由于类型的不同,p2相当于商场的全部商品,p1相当于个人购买的商品,如果p2=p1就相当于在个人购买商品中加入了商城的全部商品,这是基本不可能的。

泛型接口:

格式:【访问权限】 interface 接口名称 <泛型标识>

interface info<T>{
    public T getVar();
}

泛型接口的实现方式有两种:

  1. 在子类的定义上声明泛型类型
  2. 直接在接口中指定具体类型

下面分别实现(第一种)

interface info<T>{
    public T getVar();
}

class Point <T> implements info <T>{
    private T var;
    public Point(T var){
        this.setVar(var);
    }
    public T getVar(){
        return var;
    }
    public void setVar(T var){
        this.var=var;
    }

}
public class test {

    public static void main(String[] args) {
        info<String> i=null;
        i=new Point<String>("hehe");
        System.out.println(""+i.getVar());
        
    }

}

运行结果:

(第二种)

interface info<T>{
    public T getVar();
}

class Point implements info<String>{
    private String var;
    public Point(String var){
        this.setVar(var);
    }
    public String getVar(){
        return var;
    }
    public void setVar(String var){
        this.var=var;
    }

}
public class test {

    public static void main(String[] args) {
        info<String> i=null;
        i=new Point("hehe");
        System.out.println(""+i.getVar());
        
    }

}

运行结果:

泛型方法

泛型方法的定义与其所在的类是否是泛型类是没有任何关系的。

定义:【访问权限】<泛型标识> 泛型标识 方法名称(【泛型标识 参数名称】)

如:public<T> T fun(T t){ return t;}

个人感觉泛型方法的使用与一般方法的使用并无太大的区别。

泛型的嵌套

 简单的讲就是在一个类的泛型中指定另外一个类的泛型。用一个简单的实例就能明白了。

class info<T,V>{
    private T var;
    private V value;
    public info(T var,V vanue){
        this.setVar(var);
        this.setValue(vanue);
    }
    public T getVar(){
        return var;
    }
    public void setVar(T var){
        this.var=var;
    }
    public V getValue(){
        return value;
    }
    public void setValue(V value){
        this.value=value;
    }
}

class Demo <S>{
    private S info;
    public Demo(S info){
        this.setInfo(info);
    }
    public S getVar(){
        return info;
    }
    public void setInfo(S info){
        this.info=info;
    }

}
public class test {

    public static void main(String[] args) {
        Demo<info<String,Integer>> d=null;//将info作为泛型类型
        info<String,Integer> i=null;//info要指定两个两个泛型类型
        i=new info<String,Integer>("123",456);
        d=new Demo<info<String,Integer>>(i);//在demo类中设置info类对象
        System.out.println(""+d.getVar().getVar());
        System.out.println(""+d.getVar().getValue());
        
    }

}

运行结果:

原文地址:https://www.cnblogs.com/scetopcsa/p/3819000.html