泛型
认识
我们在集合中使用过泛型,泛型可以指定集合中的数据类型。在没有泛型的情况下,我们只能使用Object类型。泛型就是可以动态的指定类型的范围。
看一个案例:
我们自己实现一个队列:
没有泛型:
/**
* @author 戴着假发的程序员
* @TODO
* @organization 飞虎队
* 2020年8月31日 上午11:37:21
*/
public class ObjectQueue {
private LinkedList objs = new LinkedList();
//出队
public Object pop() {
return objs==null || objs.isEmpty()?null:objs.removeLast();
}
//入队
public void push(Object obj) {
objs.addFirst(obj);
}
}
public static void main(String[] args) {
ObjectQueue queue = new ObjectQueue();
//入队(可以放入任何类型)
queue.push("一");
queue.push(2);
queue.push('三');
//出队
while(true) {
//取出的是Object类型
Object obj = queue.pop();
if(obj==null){
break;
}
System.out.println(obj);
}
}
/**
* @author 戴着假发的程序员
* @TODO 使用泛型动态的指定这个队列中存储的数据的类型
* @organization 飞虎队
* 2020年8月31日 上午11:41:45
*/
public class StQueue<T> {
//将泛型类型作为其他类型的泛型
private LinkedList<T> objs = new LinkedList<T>();
private T t;//申明泛型的成员变量
//出队 返回泛型类型返回值
public T pop() {
return objs==null || objs.isEmpty()?null:objs.removeLast();
}
//入队 将泛型类型作为参数
public void push(T obj) {
objs.addFirst(obj);
}
}
泛型类的使用:
/**
* @author 戴着假发的程序员
* @TODO
* @organization 飞虎队
* 2020年8月31日 上午11:43:26
*/
public class Test1 {
public static void main(String[] args) {
//JDK7之后,就不需要指定new后面的类型的泛型,会自动识别
//动态的指定T是String
StQueue<String> queue = new StQueue<>();
//入队时必须使用指定的类型
queue.push("哈哈");
queue.push("嘻嘻");
//出队时是类型安全的
String value = queue.pop();
//动态指定T是Integer
StQueue<Integer> queue1 = new StQueue<Integer>();
queue1.push(1);
queue1.push(new Integer(2));
Integer v = queue1.pop();
}
}
泛型类
所谓泛型类,就是在申明类的时候指定一个不确定的类型。在类中就可以将这个泛型作为类型使用。
指定的泛型在类内部的使用:
申明泛型成员:
在方法内部申明对象:
作为参数的类型或者方法的返回值类型:
作为其他类型的泛型使用:
tips:不能使用泛型创建对象。
泛型方法
我们可以在申明一个方法的时候指定一个泛型,这时这个方法内部就可以使用这个泛型。
泛型方法的申明:
/**
* @author 戴着假发的程序员
* @TODO
* @organization 飞虎队
* 2020年8月31日 下午2:21:16
*/
public class ParadigmMethod {
public static <T> T stMethod(T t) {
System.out.println(t);
return t;
}
public <E> List<E> method(E e,int x){
List<E> es = new ArrayList<E>();
for(int i = 0;i<x;i++) {
es.add(e);
}
return es;
}
}
泛型方法的使用:
/**
* @author 戴着假发的程序员
* @TODO
* @organization 飞虎队
* 2020年8月31日 下午2:24:10
*/
public class Test {
public static void main(String[] args) {
//没有指定泛型,jvm会根据传入的参数判断泛型的类型
String str = ParadigmMethod.stMethod("str");
Integer v = ParadigmMethod.stMethod(12);
ParadigmMethod pm = new ParadigmMethod();
List<String> es = pm.method("abc", 3);
List<Double> ds = pm.method(12.5, 3);
//指定泛型
String str1 = ParadigmMethod.<String>stMethod("哈哈");
Float f = ParadigmMethod.<Float>stMethod(12.0F);
List<String> es1 = pm.<String>method("十二", 3);
List<Double> ds1 = pm.<Double>method(12.5, 3);
}
}
泛型方法调用时可以不指定泛型,JVM会根据传入的参数的类型自动判断泛型。
如果指定了泛型,则必须按照泛型指定的类型传入参数和处理返回值。
类继承和接口实现之后的泛型处理
父类有泛型或者接口有泛型,子类和实现类应该如何处理。
父子类关系:
/**
* @author 戴着假发的程序员
* @TODO
* @organization 飞虎队
* 2020年8月31日 下午2:30:52
*/
public class A <T>{
public void show(T t) {
System.out.println(t);
}
public static void main(String[] args) {
A a = new B();
a.show(new String[] {"1"});
A c = new C();
c.show(123);
D<Integer> d = new D<>();
d.show(123);
}
}
//不指定A类的繁星 默认是Object
class B extends A{
}
//指定父类的泛型
class C extends A<Integer>{
public void show(Integer t) {
super.show(t);
}
}
//不指定父类泛型,子类就要添加泛型
class D<T> extends A<T>{
}
接口实现和继承中的泛型
/**
* @author 戴着假发的程序员
* @TODO
* @organization 飞虎队
* 2020年8月31日 下午2:37:26
*/
public interface P<T> {
}
//不指定就是Object
interface M extends P{}
//指定父接口泛型
interface N extends P<String>{}
//不指定,指定自己的泛型
interface H<T> extends P<T>{}
//实现类 没有泛型,就是Object
class U implements P{}
//指定接口泛型
class S implements P<Thread>{}
//不指定,但是指定自己的
class Z<T> implements P<T>{}
泛型的类型限定
泛型的类型可以通过继承等方式实现类型限定。
案例:指定类型的子类型
public class A {
}
public class B extends A {
}
public class C extends A {
}
//泛型类:
/**
* @author 戴着假发的程序员
* @TODO
* @organization 飞虎队
* 2020年8月31日 下午2:42:35
*/
//这里的泛型T必须是A类型的子类或者A接口的的子接口或者实现类。
public class Demo1<T extends A> {
}
测试: