Java泛型

Java泛型

 

 

 

 

泛型介绍

  • Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
  • 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

假定我们有这样一个需求:写一个排序方法,能够对整形数组、字符串数组甚至其他任何类型的数组进行排序,该如何实现?

  • 答案是可以使用 Java 泛型。

使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序。然后,调用该泛型方法来对整型数组、浮点数数组、字符串数组等进行排序。

 

 

泛型方法

你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

下面是定义泛型方法的规则:

  • · 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
  • · 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • · 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • · 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

 

泛型作用

  1. 提高了程序的安全性
  2. 将运行期遇到的问题转移到了编译期
  3. 省去了类型强转的麻烦
  4. 泛型类的出现优化了程序设计
  5. 泛型在集合中得到了广泛应用

 

泛型类

单参数:

public class Genericity<T> {
    private T t;

    //空参构造函数
    public Genericity() {

    }
    //带有T类型参数的构造函数
    public Genericity(T t) {
        this.t = t;
    }
    //打印
    public void print(T t){
        System.out.println(t);
    }

    public static void main(String[] args) {
        //打印Integer类型
        Genericity<Integer> intGen = new Genericity<Integer>();
        intGen.print(360);

        //打印String类型
        Genericity<String> strGen = new Genericity<String>();
        strGen.print("Hello World");
    }
}


多参数:

public class Genericity<T,V> {

    //空参构造函数
    public Genericity() {

    }

    //打印
    public void print(T t, V v){
        System.out.println(t + " : " + v);
    }

    public static void main(String[] args) {
        //打印<Integer,String>类型
        Genericity<Integer,String> intGen = new Genericity<Integer,String>();
        intGen.print(360,"Hello World");
    }
}


 

泛型接口

//泛型接口
interface InterfaceGen<T> {
     T getT();
     void setT(T t);
}

public class Genericity implements InterfaceGen<Integer> {

    private Integer t;
    //空参构造函数
    public Genericity() {

    }
    //获取值
    public Integer getT(){
        return t;
    }
    //设置t的值
    public void setT(Integer t) {
        this.t = t;
    }

    public static void main(String[] args) {
        Genericity gen = new Genericity();
        gen.setT(18);
        System.out.println(gen.getT());
    }
}


 

类型通配符

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

public class Genericity  {
    public static void main(String[] args) {
        ArrayList<Worker> workers = new ArrayList<>();
        workers.add(new Worker("zhangsan", 18));
        workers.add(new Worker("lisi", 22));
        workers.add(new Worker("wangwu", 31));
        printList(workers);

        ArrayList<Integer> integers = new ArrayList<>();
        integers.add(3);
        integers.add(9);
        integers.add(81);
        printList(integers);
    }

    public static void printList(List<?> list) {
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

class Worker {
    String name;
    int age;

    public Worker(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Worker{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

打印结果:

Worker{name='zhangsan', age=18}

Worker{name='lisi', age=22}

Worker{name='wangwu', age=31}

3

9

81


 

 

泛型方法

/**
 * 在我们类中方法上定义泛型
 * 1、如果类上面定义了泛型,可以直接使用类上面定义的泛型
 * 2、如果方法有返回值,而且返回值不确定是什么类型,我们也可以使用泛型来作为方法的返回值
 * 返回值的类型不一定和我们类上面的泛型一直
 * 3、如果方法是静态方法的时候,那么就需要在static和返回值中间指定要使用的泛型
 * 我们发现,泛型也是有局限性的:一旦指定类上的泛型之后,在方法调用的时候就只能使用指定类型
 *
 * @param <T>
 */
class Tool<T> {

    public void print(T t) {
        System.out.println("print :" + t);
    }

    /**
     * 方法的泛型,避免了和类上面定义的泛型的一致,做到了调用的灵活性
     *
     * @param <E>
     * @param e
     */
    public <E> void show(E e) {
        System.out.println("show :" + e);
    }

    /**
     * 定义了有返回值的方向方法
     *
     * @param <E>
     * @param e
     * @return
     */
    public <E> E show1(E e) {
        return e;
    }

    /**
     * 如何在没有返回值的静态方法上定义泛型
     *
     * @param <T>
     * @param t
     */
    public static <T> void show2(T t) {
        System.out.println("show2 :" + t);
    }

    /**
     * 如何在静态有返回值的方法上定义泛型
     *
     * @param <T>
     * @param t
     * @return
     */
    public static <T> T show3(T t) {
        return t;
    }
}

 

 

类型通配符限定

向上限定

 ? extends E:接收E类型或者E的子类型

程序示例:

/**
 * 在我们类中方法上定义泛型
 * 1、如果类上面定义了泛型,可以直接使用类上面定义的泛型
 * 2、如果方法有返回值,而且返回值不确定是什么类型,我们也可以使用泛型来作为方法的返回值
 * 返回值的类型不一定和我们类上面的泛型一直
 * 3、如果方法是静态方法的时候,那么就需要在static和返回值中间指定要使用的泛型
 * 我们发现,泛型也是有局限性的:一旦指定类上的泛型之后,在方法调用的时候就只能使用指定类型
 *
 * @param <T>
 */
class Tool<T> {

    public void print(T t) {
        System.out.println("print :" + t);
    }

    /**
     * 方法的泛型,避免了和类上面定义的泛型的一致,做到了调用的灵活性
     *
     * @param <E>
     * @param e
     */
    public <E> void show(E e) {
        System.out.println("show :" + e);
    }

    /**
     * 定义了有返回值的方向方法
     *
     * @param <E>
     * @param e
     * @return
     */
    public <E> E show1(E e) {
        return e;
    }

    /**
     * 如何在没有返回值的静态方法上定义泛型
     *
     * @param <T>
     * @param t
     */
    public static <T> void show2(T t) {
        System.out.println("show2 :" + t);
    }

    /**
     * 如何在静态有返回值的方法上定义泛型
     *
     * @param <T>
     * @param t
     * @return
     */
    public static <T> T show3(T t) {
        return t;
    }
}


向下限定

 ? super E:接收E类型或E的超(父|基)类

//使用上例的Animal和Dog类

public class Genericity {
    public static void main(String[] args) {
        ArrayList<Animal> animals = new ArrayList<Animal>();
        animals.add(new Animal());
        animals.add(new Animal());
        sop(animals);
    }

    //这里使用了泛型中类型通配符的向下限定 :? 对应的类型必须为Dog类或Dog的父类
    public static void sop(List<? super Dog> list){
        for (int i = 0; i < list.size(); i++) {
            Object o = list.get(i);
        }
    }
}


 

 

 

 

你可能感兴趣的:(java,编程语言,面向对象)