一天一个Java基础——泛型
这学期的新课——设计模式,由我仰慕已久的老师传授,可惜思维过快,第一节就被老师挑中上去敲代码,自此在心里烙下了阴影,都是Java基础欠下的债
这学期的新课——算法设计与分析,虽老师不爱与同学互动式的讲课,但老师讲的挺好,不过由于数据结构欠缺课听的有点烧脑,都是数据结构欠下的债
这学期的新课——英语口语,虽外教老师风骚逗趣浪荡不羁爱自由,但我辈词汇量欠缺,表明淡定说yeah,但心中一万匹草泥马策马奔腾,都是英语欠下的债
1.泛型类
实体类(容器类),经常重用的类,下面是一个没有用泛型的实体类:
1 public class User{ 2 private String username; 3 private int number; 4 public String getUsername() { 5 return username; 6 } 7 public void setUsername(String username) { 8 this.username = username; 9 } 10 public int getNumber() { 11 return number; 12 } 13 public void setNumber(int number) { 14 this.number = number; 15 } 16 public String toString() { 17 return "User [username=" + username + ", number=" + number + "]"; 18 } 19 public User(String username, int number) { 20 super(); 21 this.username = username; 22 this.number = number; 23 } 24 public User() { 25 super(); 26 } 27 }
属性number可以作为存放学生的证件号码,如果是int类型,11位的学号是够用了,但如果是身份证呢,一是长度不够,二是存在字符X,所以就需要重定义,那么这样这个实体类的重用性就很低了。
但如果用上泛型,就是这样的:
1 public class User<K,V> { 2 private K usrename; 3 private V number; 4 public K getUsrename() { 5 return usrename; 6 } 7 public void setUsrename(K usrename) { 8 this.usrename = usrename; 9 } 10 public V getNumber() { 11 return number; 12 } 13 public void setNumber(V number) { 14 this.number = number; 15 } 16 public String toString() { 17 return "User [usrename=" + usrename + ", number=" + number + "]"; 18 } 19 public User(K usrename, V number) { 20 super(); 21 this.usrename = usrename; 22 this.number = number; 23 } 24 public User() { 25 super(); 26 } 27 }
这样的好处就是:
1 public class Test1 { 2 public static void main(String[] args) { 3 User<String,Integer> u = new User<String,Integer>(); 4 u.setUsrename("zhengbin"); 5 u.setNumber(2013734217); 6 User<String,String> u1 = new User<String,String>(); 7 u1.setUsrename("zhengbin"); 8 u1.setNumber("4*****19951029****"); 9 System.out.println(u); 10 System.out.println(u1); 11 } 12 }
运行结果:
User [usrename=zhengbin, number=2013734217]
User [usrename=zhengbin, number=41****19951029****]
注意:
(1) 按照惯例,像E或T这样的单个大写字母用于表示一个形式泛型类型
(2) 泛型类型必须是引用类型。不能用像int、double或char这样的基本类型来替换泛型类型
2.泛型接口
定义一个生成器的接口:
1 package Entity; 2 3 public interface Generator<T> { 4 public T next(); 5 }
实现这个接口:
1 package Test; 2 import java.util.Random; 3 import Entity.Generator; 4 public class FruitGenerator implements Generator<String> { 5 private String[] fruits = new String[]{"Apple", "Banana", "Pear"}; 6 public String next() { 7 Random rand = new Random(); 8 return fruits[rand.nextInt(3)]; 9 } 10 }
测试类:
1 package Test; 2 public class Main { 3 public static void main(String[] args) { 4 FruitGenerator generator = new FruitGenerator(); 5 System.out.println(generator.next()); 6 System.out.println(generator.next()); 7 System.out.println(generator.next()); 8 System.out.println(generator.next()); 9 } 10 }
运行结果:
Banana
Apple
Apple
Pear
3.泛型方法
从jdk 1.5开始,可以定义泛型接口,和泛型类,还可以使用泛型类型来定义泛型方法
1 public class Test2 { 2 public static void main(String[] args) { 3 Integer[] integers = {1,2,3,4,5}; 4 String[] strings = {"London","Paris","New York","Austin"}; 5 //为了调用泛型方法,需要将实际类型放在尖括号内作为方法名的前缀(不加也行) 6 Test2.<Integer>print(integers); 7 Test2.<String>print(strings); 8 } 9 10 public static <E> void print(E[] list){ 11 for(int i = 0;i < list.length;i++){ 12 System.out.print(list[i]+"-"); 13 } 14 System.out.println(); 15 } 16 }
可以看到方法的参数彻底泛化了,这个过程涉及到编译器的类型推导和自动打包,也就说原来需要我们自己对类型进行的判断和处理,现在编译器帮我们做了
这样在定义方法的时候不必考虑以后到底需要处理哪些类型的参数,大大增加了编程的灵活性
4.通配泛型
通配泛型类型有三种形式:
(1)? ,称为非受限通配,它和? extends Object 是一样的
(2)? extends T 称为受限通配
(3)? super T 称为下限通配,表示T或T的一个未知父类型