泛型(一)
在学习树结构中遇到了一种叫做函数对象的东西,是基于泛型来实现的,本着解决依赖的原则,回到《java编程思想》中把泛型这个章节读了一遍。所幸在章节最后有提到这个设计理念。
泛型基本用法
简单的泛型
泛型最常用的形式就是在定义一个类的时候添加一个类型变量,该变量用尖括号包起来;这个变量可以在该类中使用:1. 作为域的类型申明;2. 作为方法的返回值;3. 作为方法的参数
泛型的最主要的使用场景就是容器,当用一个类来持有特定类型的对象的时候,在使用泛型之前,我们是使用Object类型来实现这个功能,使用Object的缺点是:
- 这个容器不能持有特定类型的对象
- 取出被持有的对象时需要向上转型
package generics;
class Apple{}
class Orange{}
public class HolderUseObject{
private Object[] items = new Object[2];
public void put(int index, Object item){
if(index>2)
throw new RuntimeException();
items[index-1] = item;
}
public Object get(int index){
if(index>2)
throw new RuntimeException();
return items[index-1];
}
public HolderUseObject(){
}
public static void main(String[] args){
HolderUseObject holderUseObject = new HolderUseObject();
holderUseObject.put(1, new Apple());
holderUseObject.put(2, new Orange()); // 放入了不是苹果的对象
//Apple apple = holderUseObject.get(1); error: incompatible types: Object cannot be converted to Apple
Apple apple = (Apple)holderUseObject.get(1);//需要向下转型
}
}
而使用泛型可以避免这些问题:
package generics;
import java.lang.reflect.*;
public class HolderUseGenerics<T>{
private T[] items;
public void put(int index, T item){//使用类型变量作为类型参数
if(index>2)
throw new RuntimeException();
items[index-1] = item;
}
public T get(int index){//使用类型变量作为返回值
if(index>2)
throw new RuntimeException();
return items[index-1];
}
public HolderUseGenerics(){
items = (T[]) new Object[2]; //泛型数组的建立 "unchecked"
}
public static void main(String[] args){
HolderUseGenerics<Apple> holderUseGenerics = new HolderUseGenerics<>();//java8可以使用菱形运算符避免重复的类型变量申明
holderUseGenerics.put(1, new Apple());
//holderUseGenerics.put(2, new Orange());incompatible types: Orange cannot be converted to Apple 不再可以放入其他类型的对象
Apple apple = holderUseGenerics.get(1);//不需要向下转型
}
}
泛型接口
泛型接口的使用和泛型在类型中的使用差不多,我们在定义这个接口的时候添加一个类型参数,在使用这个接口的时候给出类型参数
接口可以: 1. 被类实现; 2. 做为变量的类型申明; 3. 方法的输入参数; 4. 方法的返回参数;
package generics;
public interface GenericsInterface<T>{
T next();
}
class AInterfaceCat implements GenericsInterface<String>{
public String next(){
return "hello";
}
public static void main(String[] args){
AInterfaceCat a = new AInterfaceCat();
System.out.println(a.next());
}
}
class BInterfaceCat{
GenericsInterface<String> aInterface = new AInterfaceCat();//作为变量的类型申明
public static void asInput(GenericsInterface<String> input){//方法的输入参数
}
public static GenericsInterface<String> asOutput(){//方法的返回参数
return new AInterfaceCat();
}
}
泛型方法
泛型方法是独立于类存在的,和类本身有没有类型参数没关系,当一个方法是静态的时候,他将无法访问类型变量,这个时候泛型方法显得尤为重要,书中范例:
public class GenericMethods {
public <T> void f(T x) {//泛型方法f
System.out.println(x.getClass().getName());//打印类全名
}
public static void main(String[] args) {
GenericMethods gm = new GenericMethods();
gm.f("");
gm.f(1);
gm.f(1.0);
gm.f(1.0F);
gm.f('c');
gm.f(gm);
}
}
/*输出:
java.lang.String
java.lang.Integer
java.lang.Double
java.lang.Float
java.lang.Character
GenericMethods
*/
类型参数推断
当使用泛型方法执行赋值操作的时候,可以不添加对应的类型参数,直接使用方法名,编译器会对类型参数自动推断