二十三、泛型语法基础详解

泛型概述

一般的类和方法,只能使用具体的类型,如基本类型(int,double等),或者自定义的类。如果想要编写更为通用的代码,这种形式会带来一定的束缚。

Java 中的多态实际上已经可以实现一些场景下的通用代码编写,但是多态必须基于继承体系,这使得它也会受一定束缚。一个方法参数为某个接口,那么我们可以将这个接口实现的所有类的对象作为参数,而其他没有实现这个接口的类则无法作为参数。

Java SE5 引入了泛型概念,通过解耦类或方法与所使用的类型之间的约束实现,简单的说就是将类型参数化了。使代码可以应用于多种类型。

泛型可以应用于类(包括内部类,匿名类等)、接口和方法。

简单泛型

对于容器类而言,泛型很好的解决了容器类的类型问题,因为容器类需要能够持有所有对象类型,虽然 Object 可以表示任何对象,但是从容器中取出对象时需要进行类型转换,而泛型可以事先声明容器类的存储对象类型,因此不需要再考虑类型问题。

class SimpleList<T> {
    private T[] arr;
    private int count;
    
    public SimpleList(T[] arr) {
        this.arr = arr;
        this.count = arr.length;
    }
    
    public void print() {
        for(T t : arr) {
            System.out.println(t.toString());
        }
    }
    public T get(int i) {
    	if(i < count) {
			return arr[i];
		}
		return null;
    }
    
    public void add(T t) {
        this.arr[count++] = t;
    }
}

public class Test {
    public static void main(String[] args) {
        Integer[] arr1 = new Integer[]{1,2,3,4,5,6,7};
        SimpleList<Integer> list = new SimpleList<Integer>(arr1);
        list.add(10);
        list.print();
        
        String[] arr2 = new String[]{"abc", "sij", "soie"};
        SimpleList<String> list1 = new SimpleList<String>(arr2);
        list.add("ssade");
        list1.print();
    }
}

上例中实现了一个简单的集合类,可以接受任何类型的数组对象。并且提供add()方法添加元素。

在实际开发过程中,会不可避免的遇到想要一个返回多个值的方法,但是作为方法返回值却只能有一个,具体的类虽然可以创建包含多个数据的对象,但是不够通用,而泛型类可以解决这个问题,我们可以创建一个具有多个类型参数的泛型类作为返回对象的类型,这被叫做元组

例如,我们要创建一个可以返回两个参数的二维元组,和一个继承自该二维元组的三维元组,理论上元组的维数是没有限制的。任何方法只要想要返回两个或者三个结果值的,都可以使用下面这两个元组。

class Two<T, K> {
    public final T first;
    public final K scond;
    public Two(T t, K k) {
        first = t;
        scond = k;
    }
    @Override
    public String toString() {
        return "Two [first=" + first + ", scond=" + scond + "]";
    }
}

class Three<T, K, L> extends Two<T, K> {
    public final L three;
    public Three(T t, K k, L l) {
        super(t, k);
        three = l;
    }
    @Override
    public String toString() {
        return "Three [three=" + three + "]";
    }
}

可以观察到在这两个元组中,成员变量都是public final公共的不可变的,由于final保证了值的不可变,因此我们不需要像 javabean 那样将成员变量私有化。

泛型接口

泛型除了在类上的应用外,同样可以应用于接口。生成器,是工厂方法设计模式的一种应用,工厂方法设计模式通常需要批量生产不同类型的对象。

现在尝试来编写一个生成器接口以及实现一个具体的生成器,为了验证生成器的作用,额外编写需要被生成器使用的类。并且这个生成器还需要能够使用foreach语法。

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Random;

/**
 * 生成器接口
 * @author Alan
 *
 * @param 
 */
interface Generator<T> {
    T next();
}

class PersonGenerator implements Generator<Person>, Iterable<Person>{

    private Class<?>[] types = {Student.class, Teacher.class};
    private static Random rand = new Random(100);
    //Foreach语法中结束标志
    private int size;
    
    public PersonGenerator() {
    }

    public PersonGenerator(int size) {
        this.size = size;
    }

    
    @Override
    public Iterator<Person> iterator() {
        return new Iterator<Person>() {
            int count = size;
            @Override
            public boolean hasNext() {
                return count > 0;
            }

            @Override
            public Person next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
                count--;
                return PersonGenerator.this.next();
            }
            
        };
    }

    @Override
    public Person next() {
        try {
            return (Person) types[rand.nextInt(1)].newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
    
}

/**
 * 需要生成对象的类
 * @author Alan
 *
 */
class Person{
    private static int counter = 0;
    private final int id = counter++;
    @Override
    public String toString() {
        return "Person [id=" + id + "]";
    }
}

class Teacher extends Person { }
class Student extends Person { }

public class Test {
    public static void main(String[] args) {
        PersonGenerator p = new PersonGenerator(10);
        for(Person s : p) {
            System.out.println(s);
        }
    }
}

Java中的泛型无法使用基本类型,如int类型在泛型中必须使用Integer,Java SE5 中的自动装箱拆箱使得我们在使用时可以直接使用int,例如下面这个生成斐波那契数列的类,同样是生成器的一个实现。

public class Fibonacci implements Generator<Integer> {
    private int count = 0;
    public Integer next() {
        return fib(count++);//fib方法返回值为int,此处通过自动装箱将int转换为Integer
    }
    private int fib(int n) {
        if(n < 2) {
            return 1;
        }
        return fib(n-1) + fib(n-2);
    }
    
    public static void main(String[] args) {
        Fibonacci f = new Fibonacci();
        for(int i=0; i< 10; i++) {
            System.out.println(f.next());
        }
    }
}

泛型方法

泛型也可以作用于方法上,并且泛型方法与其所在的类并没有关系,也就是说不管类是不是泛型的,其中的方法都可以是泛型的,创建一个泛型方法只需要在返回参数前声明类型参数即可,如下:

public class Test {
    
    public <T> T fun(T obj) {
        System.out.println(obj);
        return obj;
    }
    
}

值得注意的是,在一个泛型类中的静态方法是不能使用泛型类的类型参数的,因此静态类需要使用泛型能力,那么必须使其成为泛型类。

在使用泛型方法时,方法返回的类型会根据接收对象类型进行判断,但是如果没有接收对象而是将返回值作为参数传递给其他方法,那么参数推断就会失效,这时候必须显示声明返回类型。

class Person{}
class Pet{}

class ListUtil {
    public static <T> List<T> list() {
        return new ArrayList<T>();
    }
}

public class Test{
    public void fun(ArrayList<Integer> list) {
        for(Integer i : list) {
            System.out.println(i);
        }
    }
    
    public static void main(String[] args) {
        List<String> list = ListUtil.list();//具有参数推断,无需声明返回类型
        
        fun(ListUtil.<Integer>>list());//需要声明返回类型
    }
}

利用静态泛型方法,我们可以编写一个所有类型通用的生成器。

public class BasicGenerator<T> implements Generator<T> {
    Class<T> type;
    public BasicGenerator(Class<T> type) {
        this.type = type;
    }
    
    @Override
    public T next() {
        try {
            return type.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public static <T> BasicGenerator<T> create(Class<T> type) {
        return new BasicGenerator<T>(type);
    }
}

class Person{
    private static int count=0;
    private int id = count++;
    public String toString(){
        return id+" ";
    }
}

public class Test{
    public static void main(String[] args) {
        BasicGenerator<Person> gen = BasicGenerator.create(Person.class);
        for(int i=0; i<10; i++) {
            System.out.println(gen.next());
        }
    }
}

内部类中的泛型

泛型同样可以应用于内部类以及匿名内部类中,还是以生成器接口为例。

interface Generator<T> {
    T next();
}

class Custom {
    private static int count = 1;
    private int id = count++;
    
    private Custom(){}//构造函数为私有,在其他类中无法直接new对象
    
    public String toString() {
        return "Custom " + id;
    }
    
    public static Generator<Custom> generator() {
        return new Generator<Custom>() {
            public Custom next() {
                return new Custom();
            }
        };
    }
}

你可能感兴趣的:(《Java编程思想》新知,泛型,泛型类,泛型接口,泛型方法)