泛型接口
泛型也可以应用于接口,例如生成器,一种专门负责创建对象的类。这其实是工厂方法设计模式的一种应用。不过使用生成器创建对象时,不需要参数。而工厂方法一般是需要参数的。
- package?tik4.generic;??
- ??
- public?interface?Generator<T>?{??
- ????T?next();??
- }??
?一个Fibonacci数列实现
- package?tik4.generic;??
- ??
- public?class?Fibonacci?implements?Generator<Integer>?{??
- ????private?int?count;??
- ??
- ????//?参数类型用Integer,使用int将不能编译??
- ????//?public?int?next()?{??
- ????//?return?0;??
- ????//?}??
- ????public?Integer?next()?{??
- ????????return?fib(count++);??
- ????}??
- ??
- ????private?int?fib(int?n)?{??
- ????????if?(n?<?2)?return?1;??
- ????????return?fib(n?-?2)?+?fib(n?-?1);??
- ????}??
- ??
- ????public?static?void?main(String[]?args)?{??
- ????????Fibonacci?gen?=?new?Fibonacci();??
- ????????for?(int?i?=?0;?i?<=?17;?i++)??
- ????????????System.out.print(gen.next()?+?"?");??
- ????}??
- ????/*?
- ?????*?Output:?1?1?2?3?5?8?13?21?34?55?89?144?233?377?610?987?1597?2584?
- ?????*/??
- }??
?
泛型方法
可以在类中包含参数化方法,而这个方法所在的类可以是泛型类,也可以不是泛型类。是否拥有泛型方法,和所在的类是否泛型没有关系。泛型方法使得该方法能够独立于类而产生变化。以下是一个基本原则:如果泛型方法可以取代整个类的泛型化,就应该只使用泛型方法。另外,对于一个static方法而言,无法访问泛型
类的参数类型,所以static方法需要使用泛型能力,就必须成为泛型方法
- package?tik4.generic;??
- ??
- public?class?GenericMothod?{??
- ????public?<T,M,N>?void?getTType(T?t,M?m,N?n){??
- ????????/*?
- ?????????*?传入int,long?,double等基本类型时,自动打包机制?
- ?????????*?会将基本类型包装成相应的对象?
- ?????????*/??
- ????????System.out.println(t.getClass().getName());??
- ????????System.out.println(m.getClass().getName());??
- ????????System.out.println(n.getClass().getName());??
- ????}??
- ????public?static?void?main(String[]?args)?{??
- ????????//泛型类在创建对象时必须指定参数类型,而泛型方法则不需要在创建对象时指定参数类型T??
- ????????GenericMothod?gm?=?new?GenericMothod();??
- ????????gm.getTType("",?1,?1.0);??
- ????????gm.getTType(1.0F,?‘c‘,?gm);??
- ????}/*?
- ?????*Output:??
- ????java.lang.String?
- ????java.lang.Integer?
- ????java.lang.Double?
- ????java.lang.Float?
- ????java.lang.Character?
- ????tik4.generic.GenericMothod?
- ????*/??
- }??
?
利用参数类型推断
问题:很烦这种写法是不是,老子在声明变量的的时候已经指明了参数类型,为毛还要在初始化对象时再指定?
- Map<Integer,?List<??extends?Set<String>>>?map?=???
- ????new?HashMap<Integer,?List<??extends?Set<String>>>();??
解决:搞一个工具类
- package?tik4.generic;??
- ??
- import?java.util.HashMap;??
- import?java.util.List;??
- import?java.util.Map;??
- import?java.util.Set;??
- ??
- public?class?New?{??
- ????public?static?<K,?V>?Map<K,?V>?hashMap()?{??
- ????????return?new?HashMap<K,?V>();??
- ????}??
- ??
- ????public?static?void?main(String[]?args)?{??
- ????????Map<Integer,?List<??extends?Set<String>>>?map?=?New.hashMap();??
- ????}??
- }??
?注意:
类型推断只对赋值操作有效,其他时候不起作用。如果你使用泛型方法调用的结果(例如:New.hashMap())作为参数,传递给其他方法,此时编译器不会执行类型推断。编译器认为,调用泛型方法之后,其返回值被赋给一个Object类型的变量。上代码:
- package?tik4.generic;??
- ??
- import?java.util.List;??
- import?java.util.Map;??
- import?java.util.Set;??
- ??
- public?class?LimitsOfInference?{??
- ????static?void?f(Map<Integer,?List<??extends?Set<String>>>?map){};??
- ????public?static?void?main(String[]?args)?{??
- ????????/*?
- ?????????*?the?mothed?f(Map<Integer,?List<??extends?Set<String>>>?
- ?????????*?is?not?applicable?for?arguments?(Map<Object,Object>)?
- ?????????*?不能编译?
- ?????????*/??
- //??????f(New.hashMap());??
- ????}??
- }??
?
显示类型说明?? think in java4中是这么写的,但是我的机器上不能编译,难道书上是在扯淡
?在泛型方法中,可以显示的指定参数类型。在 点操作符 和 方法名之间插入尖括号,然后将类型置于括号内。如果是在定义该方法的类的内部,则在点操作符之前使用this关键字如果使用static方法,必须在点操作符之前加上类名。这种语法,可以解决LimitsOfInference.java中的问题。
- package?tik4.generic;??
- ??
- import?java.util.List;??
- import?java.util.Map;??
- import?java.util.Set;??
- ??
- public?class?ExplicitTypeSpecification?{??
- ????static?void?f(Map<Integer,?String>?map){};??
- ??????
- ????public?static?void?main(String[]?args)?{??
- ????????????????//java?5和java6?中均不能编译。??
- ????????f(New.<Map<Integer,?String>>hashMap());???
- ????}??
- }??
?
?泛型推导在java7中已经实现了。
- List<String>?list?=?new?ArrayList<>();??
? ? ?因为编译器可以从前面(List)推断出推断出类型参数,所以后面的ArrayList之后可以不用写泛型参数了,只用一对空着的尖括号就行。当然,你必须带着”菱形”<>,否则会有警告的。?
? ? ?Java SE7 只支持有限的类型推断:只有构造器的参数化类型在上下文中被显著的声明了,你才可以使用类型推断,否则不行。 看代码:
- List<String>?list?=?new?ArrayList<>();??
- list.add("A");??
- ??
- //这个不行??
- list.addAll(new?ArrayList<>());??
- ??
- //?这个可以??
- List<??extends?String>?list2?=?new?ArrayList<>();??
- list.addAll(list2); ?
1.1泛型接口的基本概念
1.2泛型接口实现的两种方式
interface Info<T>{ // 在接口上定义泛型 public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型 } class InfoImpl<T> implements Info<T>{ // 定义泛型接口的子类 private T var ; // 定义属性 public InfoImpl(T var){ // 通过构造方法设置属性内容 this.setVar(var) ; } public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } }; public class GenericsDemo24{ public static void main(String arsg[]){ Info<String> i = null; // 声明接口对象 i = new InfoImpl<String>("李兴华") ; // 通过子类实例化对象 System.out.println("内容:" + i.getVar()) ; } };如果现在实现接口的子类不想使用泛型声明,则在实现接口的时候直接指定好其具体的操作类型即可:
interface Info<T>{ // 在接口上定义泛型 public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型 } class InfoImpl implements Info<String>{ // 定义泛型接口的子类 private String var ; // 定义属性 public InfoImpl(String var){ // 通过构造方法设置属性内容 this.setVar(var) ; } public void setVar(String var){ this.var = var ; } public String getVar(){ return this.var ; } }; public class GenericsDemo25{ public static void main(String arsg[]){ Info i = null; // 声明接口对象 i = new InfoImpl("李兴华") ; // 通过子类实例化对象 System.out.println("内容:" + i.getVar()) ; } };
2、泛型方法
2.1定义泛型方法
class Demo{ public <T> T fun(T t){ // 可以接收任意类型的数据 return t ; // 直接把参数返回 } }; public class GenericsDemo26{ public static void main(String args[]){ Demo d = new Demo() ; // 实例化Demo对象 String str = d.fun("李兴华") ; // 传递字符串 int i = d.fun(30) ; // 传递数字,自动装箱 System.out.println(str) ; // 输出内容 System.out.println(i) ; // 输出内容 } };
2.2通过泛型方法返回泛型类的实例
class Info<T extends Number>{ // 指定上限,只能是数字类型 private T var ; // 此类型由外部决定 public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆写Object类中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo27{ public static void main(String args[]){ Info<Integer> i = fun(30) ; System.out.println(i.getVar()) ; } public static <T extends Number> Info<T> fun(T param){ Info<T> temp = new Info<T>() ; // 根据传入的数据类型实例化Info temp.setVar(param) ; // 将传递的内容设置到Info对象的var属性之中 return temp ; // 返回实例化对象 } };
2.3使用泛型统一传入参数的类型
class Info<T>{ // 指定上限,只能是数字类型 private T var ; // 此类型由外部决定 public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆写Object类中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo28{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; Info<String> i2 = new Info<String>() ; i1.setVar("HELLO") ; // 设置内容 i2.setVar("李兴华") ; // 设置内容 add(i1,i2) ; } public static <T> void add(Info<T> i1,Info<T> i2){ System.out.println(i1.getVar() + " " + i2.getVar()) ; } };如果add方法中两个泛型的类型不统一,则编译会出错。
class Info<T>{ // 指定上限,只能是数字类型 private T var ; // 此类型由外部决定 public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆写Object类中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo29{ public static void main(String args[]){ Info<Integer> i1 = new Info<Integer>() ; Info<String> i2 = new Info<String>() ; i1.setVar(30) ; // 设置内容 i2.setVar("李兴华") ; // 设置内容 add(i1,i2) ; } public static <T> void add(Info<T> i1,Info<T> i2){ System.out.println(i1.getVar() + " " + i2.getVar()) ; } };
3、泛型数组
public class GenericsDemo30{ public static void main(String args[]){ Integer i[] = fun1(1,2,3,4,5,6) ; // 返回泛型数组 fun2(i) ; } public static <T> T[] fun1(T...arg){ // 接收可变参数 return arg ; // 返回泛型数组 } public static <T> void fun2(T param[]){ // 输出 System.out.print("接收泛型数组:") ; for(T t:param){ System.out.print(t + "、") ; } } };
4、泛型的嵌套设置
class Info<T,V>{ // 接收两个泛型类型 private T var ; private V value ; public Info(T var,V value){ this.setVar(var) ; this.setValue(value) ; } public void setVar(T var){ this.var = var ; } public void setValue(V value){ this.value = value ; } public T getVar(){ return this.var ; } public V getValue(){ return this.value ; } }; class Demo<S>{ private S info ; public Demo(S info){ this.setInfo(info) ; } public void setInfo(S info){ this.info = info ; } public S getInfo(){ return this.info ; } }; public class GenericsDemo31{ public static void main(String args[]){ Demo<Info<String,Integer>> d = null ; // 将Info作为Demo的泛型类型 Info<String,Integer> i = null ; // Info指定两个泛型类型 i = new Info<String,Integer>("李兴华",30) ; // 实例化Info对象 d = new Demo<Info<String,Integer>>(i) ; // 在Demo类中设置Info类的对象 System.out.println("内容一:" + d.getInfo().getVar()) ; System.out.println("内容二:" + d.getInfo().getValue()) ; } };