public <T> void show(T t) { }
所谓泛型方法,就是在声明方法时定义一个或多个类型形参。 泛型方法的用法格式以下:ide
修饰符<T, S> 返回值类型 方法名(形参列表){ 方法体 }
注意要点:this
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) ; // 输出内容 } };
先来看一个案例设计
/** * 泛型接口的定义格式: 修饰符 interface 接口名<数据类型> {} */ public interface Inter<T> { public abstract void show(T t) ; } /** * 子类是泛型类 */ public class InterImpl<E> implements Inter<E> { @Override public void show(E t) { System.out.println(t); } } Inter<String> inter = new InterImpl<String>() ; inter.show("hello") ;
而后看看源码中泛型的使用,下面是JDK 1.5 之后,List接口,以及ArrayList类的代码片断。code
//定义接口时指定了一个类型形参,该形参名为E public interface List<E> extends Collection<E> { //在该接口里,E能够做为类型使用 public E get(int index) {} public void add(E e) {} } //定义类时指定了一个类型形参,该形参名为E public class ArrayList<E> extends AbstractList<E> implements List<E> { //在该类里,E能够做为类型使用 public void set(E e) { ....................... } }
这就是泛型的实质:容许在定义接口、类时声明类型形参,类型形参在整个接口、类体内可当成类型使用,几乎全部可以使用普通类型的地方均可以使用这种类型形参。对象
泛型类派生子类继承
public class A extends Container<K, V>{}
public class A extends Container<Integer, String>{}
public class A extends Container{}
定义一个容器类,存放键值对key-value,键值对的类型不肯定,可使用泛型来定义,分别指定为K和V。接口
public class Container<K, V> { private K key; private V value; public Container(K k, V v) { key = k; value = v; } public K getkey() { return key; } public V getValue() { return value; } public void setKey() { this.key = key; } public void setValue() { this.value = value; } }
在使用Container类时,只须要指定K,V的具体类型便可,从而建立出逻辑上不一样的Container实例,用来存放不一样的数据类型。字符串
public static void main(String[] args) { Container<String,String> c1=new Container<String ,String>("name","hello"); Container<String,Integer> c2=new Container<String,Integer>("age",22); Container<Double,Double> c3=new Container<Double,Double>(1.1,1.3); System.out.println(c1.getKey() + " : " + c1.getValue()); System.out.println(c2.getKey() + " : " + c2.getValue()); System.out.println(c3.getKey() + " : " + c3.getValue()); }
在JDK 1.7 增长了泛型的“菱形”语法:Java容许在构造器后不须要带完成的泛型信息,只要给出一对尖括号(<>)便可,Java能够推断尖括号里应该是什么泛型信息。 以下所示:get
Container<String,String> c1=new Container<>("name","hello"); Container<String,Integer> c2=new Container<>("age",22);
public class Person { public <T> Person(T t) { System.out.println(t); } }
public static void main(String[] args){ //隐式 new Person(22); //显示 new<String> Person("hello"); }
这里惟一须要特殊注明的就是:编译器
若是构造器是泛型构造器,同时该类也是一个泛型类的状况下应该如何使用泛型构造器:由于泛型构造器能够显式指定本身的类型参数(须要用到菱形,放在构造器以前),而泛型类本身的类型实参也须要指定(菱形放在构造器以后),这就同时出现了两个菱形了,这就会有一些小问题,具体用法再这里总结一下。
如下面这个例子为表明
public class Person<E> { public <T> Person(T t) { System.out.println(t); } }
这种用法:Person<String> a = new <Integer>Person<>(15);这种语法不容许,会直接编译报错!
通配符的设计存在必定的场景,例如在使用泛型后,首先声明了一个Animal的类,然后声明了一个继承Animal类的Cat类,显然Cat类是Animal类的子类,可是List却不是List的子类型,而在程序中每每须要表达这样的逻辑关系。为了解决这种相似的场景,在泛型的参数类型的基础上新增了通配符的用法。
上界通配符顾名思义,<? extends T>表示的是类型的上界【包含自身】,所以通配的参数化类型多是T或T的子类。
它表示集合中的全部元素都是Animal类型或者其子类 List<? extends Animal>
这就是所谓的上限通配符,使用关键字extends来实现,实例化时,指定类型实参只能是extends后类型的子类或其自己。
//Cat是其子类 List<? extends Animal> list = new ArrayList<Cat>();
下界通配符<? super T>表示的是参数化类型是T的超类型(包含自身),层层至上,直至Object
它表示集合中的全部元素都是Cat类型或者其父类 List <? super Cat>
这就是所谓的下限通配符,使用关键字super来实现,实例化时,指定类型实参只能是extends后类型的子类或其自己。
例如:
//Shape是其父类 List<? super Cat> list = new ArrayList<Animal>();
当声明泛型类的实例时,传递的类型参数必须是引用类型,不能使用基本类型
User<int,double> user=new User<>(1,10,0);
如何解决