Java泛型方法与泛型类的使用------------(五)
泛型的本质就是将数据类型也参数化, 普通方法的输入参数的值是可以变的,但是类型(比如: String)是不能变的,它使得了在面对不同类型的输入参数的时候我们要重载方法才行. 泛型就是将这个数据类型也搞成跟参数的值一样可以变的.
泛型分为泛型接口,泛型类和泛型方法. 泛型接口,泛型类大家都比较熟悉了,应该都用过List, ArrayList. List就是泛型接口,ArrayList就是泛型类,我们经常看到List <E>的声明, new ArrayList<E>()的定义, 这里面的E可以是String, 也可以自己定义的类. 我感觉泛型类就JDK提供的就基本够用了,自定义使用的场景非常少了. 反而是泛型方法,对与解析自定义数据结构非常有用, 类似于toString这种场景是百试不爽.
-----------------------------------------------------------泛型方法应用实例--------------------------------------------
泛型方法不一定要在泛型类里面
定义:
1. 函数上的泛型定义 当函数中使用了一个不明确的数据类型,那么在函数上就可以进行泛型的定义。 public <泛型的声明> 返回值类型 函数名( 泛型 变量名 ){ }
例如:
package Test; import org.junit.Test; public class fanxing { /** * 定义一个泛型方法,泛型方法也可以声明为static *@param t1 */ // public static <T> void testFanxing(T t1){ public <T> void testFanxing(T t1){ System.out.println(t1); } //测试泛型类 @Test public void test1(){ fanxing fx=new fanxing(); fx.testFanxing(2); fx.testFanxing("字符串"); fx.testFanxing(new User("1", "QLQ")); } } //用于测试泛型类的类 class User{ private String id; private String name; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } protected User(String id, String name) { super(); this.id = id; this.name = name; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
结果:
-----------------------------------------------------------泛型类应用实例--------------------------------------------
package Test; import org.junit.Test; //可以有一个,也可以有多个 public class fanxinglei<T, T2> { // 泛型属性 private T t1; public T getT1() { return t1; } public void setT1(T t1) { this.t1 = t1; } // 泛型方法 public void testFanxing(T2 t2) { System.out.println(t2); System.out.println(this.getT1()); } public static void main(String[] args) { fanxinglei<String, Integer> fanxinglei = new fanxinglei<String, Integer>(); fanxinglei.setT1("泛型类"); fanxinglei.testFanxing(4); } }
测试:
-----------------------------------泛型接口应用实例------------
public class Demo8 { public static void main(String[] args) { MyInter<String> my = new MyInter<String>(); my.print("泛型"); MyInter2 my2 = new MyInter2(); my.print("只能传字符串"); } } interface Inter<T> { void print(T t); } // 实现不知为何类型时可以这样定义 class MyInter<T> implements Inter<T> { public void print(T t) { System.out.println("myprint:" + t); } } //使用接口时明确具体类型。 class MyInter2 implements Inter<String> { @Override public void print(String t) { System.out.println("myprint:" + t); } }
-----------------------------------泛型通配符应用实例------------------------
需求:
定义一个方法,接收一个集合对象(该集合有泛型),并打印出集合中的所有元素。
例如集合对象如下格式:
Collection<Person> coll = new ArrayList<Person>(); coll.add(new Person("jack", 20)); coll.add(new Person("rose", 18)); Collection<Object> coll2 = new ArrayList<Object>(); coll2.add(new Object()); coll2.add(new Object()); coll2.add(new Object()); Collection<String> coll3 = new ArrayList<String>(); coll3.add("abc"); coll3.add("ddd"); coll3.add("eee");
分析,集合对象中的元素的类型是变化的,方法的形参的那么泛型类型就只能定义为Object类型.
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; public class Demo9 { public static void main(String[] args) { ArrayList<Object> arr = new ArrayList<Object>(); arr.add(new Object()); arr.add("String"); print(arr); //将集合的泛型设置类String类型,是Object子类 HashSet<String> hs = new HashSet<String>(); hs.add("hello"); hs.add("jack"); //由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过 //print(hs); } public static void print(Collection<Object> coll) { Iterator<Object> it = coll.iterator(); while (it.hasNext()) { Object next = it.next(); System.out.println(next); } } }
但是,由于print方法接收的集合进行了元素限定,只接受限定为Object类型的集合,编译不通过该问题如何解决?
可以把方法的形参的泛型去掉,那么方法中就把集合中的元素当做Object类型处理.
也可以使用使用泛型通配符
public class Demo9 { public static void main(String[] args) { ArrayList<Object> arr = new ArrayList<Object>(); arr.add(new Object()); arr.add("String"); print(arr); // 将集合的泛型设置类String类型,是Object子类 HashSet<String> hs = new HashSet<String>(); hs.add("hello"); hs.add("jack"); // 使用泛型通配符,编译通过。 print(hs); } public static void print(Collection<?> coll) { Iterator<?> it = coll.iterator(); while (it.hasNext()) { Object next = it.next(); System.out.println(next); } } }
上述就使用了泛型通配符
通配符:? public void show(List<?> list) { } 可以对类型进行限定范围。 ?extends E: 接收E类型或者E的子类型。 ? super E: 接收E类型或者E的父类型。
限定泛型通配符的边界
限定通配符的上边界:
extends
接收Number 类型或者Number的子类型
正确:Vector<? extends Number> x = new Vector<Integer>(); 错误:Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界
super
接收Integer 或者Integer的父类型
正确:Vector<? super Integer> x = new Vector<Number>(); 错误:Vector<? super Integer> x = new Vector<Byte>();
总结:
JDK5中的泛型允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定
注意:
泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
泛型的基本术语,以ArrayList<E>为例:<>念着typeof
ArrayList<E>中的E称为类型参数变量
ArrayList<Integer>中的Integer称为实际类型参数
整个称为ArrayList<E>泛型类型
整个ArrayList<Integer>称为参数化的类型ParameterizedType