Java中泛型的详细解析,深入分析泛型的使用方式 (3)

泛型方法使用示例:

public class GenericTest { /* * 下面这个类是一个泛型类 */ public class Generic<T> { private T key; public Generic(T key) { this.key = key; } /* * 这个方法虽然在方法使用了泛型,但是这不是一个泛型方法 * 这只是类中一个普通的成员方法,只不过返回值是在声明泛型类已经声明过的泛型 * 所以在这个方法中才可以继续使用T这个泛型 */ public T getKey() { return key; } /* * 下面的这个方法显然是有问题的,在编译器中就会提示错误"cannot resolve symbol E" * 因为在类的声明中并未声明泛型E,所以在使用E做形参和返回值类型时,编译器会无法识别 * * public E setKey(E key) { * this.key = key * } */ } /* * 下面这个方法是一个泛型方法: * 首先在public与返回值之间的<T>必不可少,这个表明这是一个泛型方法,并且声明了一个泛型T * 这个T可以出现在这个泛型方法的任意位置 * 泛型的数量也可以为任意多个 */ public <T> T showKeyName(Generic<T> container) { System.out.println("container key:" + container.getKey()); T test = container.getKey(); return test; } /* * 下面这个方法也不是一个泛型方法 * 这就是一个普通的方法,只是使用了Generic<Number>这个泛型类做形参 */ public void showKeyValue1(Generic<Number> obj) { Log.d("泛型测试", "key value is " + obj.getKey()); } /* * 下面这个方法也不是一个泛型方法 * 这也是一个普通方法,只是使用了泛型通配符 ? * 从这里可以验证: 泛型通配符 ? 是一种类型实参,可以看作是所有类的父类 */ public void showKeyValue2(Generic<?> obj) { Log.d("泛型测试", "key value is" + obj.getKey()); } /* * 下面这个方法是有问题的,在编译器中就会提示错误信息:"Unknown class 'E'" * 虽然声明了 <T>, 也表明这是一个可以处理泛型类型的泛型方法 * 但是只声明了泛型类型T,并未声明泛型类型E,因此编译器不知道如何处理E这个类型 * * public <T> T showKeyName(Generic<E> container) { * ... * } */ /* * 下面这个方法也是有问题的,在编译器中就会提示错误信息:"Unknown class 'T'" * 对于编译器来说 T 这个类型并未在项目中声明过,因此编译器也不知道该如何编译这个类 * 所以这也不是一个正确的泛型方法声明 * * public void showKey(T genericObj) { * ... * } */ public void main(String[] args) { } } 类中的泛型方法

泛型方法可以出现在任何地方任何场景中进行使用

但是,当泛型方法出现在泛型类中时,情况比较特殊:

public class GenericFruit { class Fruit { @Override public String toString() { return "fruit"; } } class Apple extends Fruit { @Override public String toString() { retrun "apple"; } } class Person { @Override public String toString() { return "Person"; } } class GenerateTest<T> { public void show_1(T t) { System.out.println(t.toString()); } /* * 在泛型类中声明一个泛型方法,使用泛型T * 注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一个类型 */ public <T> void show_2(T t) { System.out.println(t.toString()); } /* * 在泛型类中声明一个泛型方法,使用泛型E. 这种泛型E可以为任意类型,可以与类型T相同 * 由于泛型方法在声明的时候会声明泛型 <E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型 */ public <E> void show_3(E t) { System.out.println(t.toString()); } } public void main(String[] args) { Apple apple = new Apple(); Person person = new Person(); GenerateTest<Fruit> generateTest = new GenerateTest<Fruit>(); // apple是Fruit的子类,所以这里可以 generateTest.show_1(apple); /* * 编译器会报错,因为泛型类型实参指定的是Fruit,而传入的实参类是Person * * generateTest.show_1(person); */ /* * 使用两个参数都能成功 */ generateTest.show_2(apple); generateTest.show_2(person); /* * 使用两个参数也都能成功 */ generateTest.show_3(apple); generateTest.show_3(person); } } 泛型方法与可变参数

泛型方法与可变参数:

public <T> void printMsg(T... args) { for (T t : args) { Log.d("泛型测试", "t is" + t); } } 静态方法与泛型

注意在类中的静态方法使用泛型:

静态方法无法访问类上定义的泛型

如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上

如果静态方法要使用泛型的话,必须将静态方法定义成泛型方法:

public class StaticGenerator<T> { ... ... /* * 如果在类中定义使用泛型的静态方法,需要添加额外的泛型声明 - 将这个方法定义成泛型方法 * 否则会报错: StaticGenerator cannot be refrenced from static context */ public static <T> void show(T t) { } } 泛型方法总结

泛型方法能使方法独立于类而产生变化,使用原则:

无论何时,如果能做到,就尽量使用泛型方法

如果使用泛型方法将整个类泛型话,就应该使用泛型方法

对于一个static方法,无法访问泛型类型的参数.如果static方法要使用泛型,就必须使之成为泛型方法

泛型的上下边界

在使用泛型的时候,可以为传入的泛型类型实参进行上下边界的限制:

比如: 类型的实参只准传入某种类型的父类或者某种类型的子类

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzddxj.html