Java 泛型方法/接口、泛型限定

Java 泛型方法/接口、泛型限定文章目录

 文章目录
     一、为什么要定义泛型方法
     1、从泛型类到泛型方法的演变过程
     2、定义泛型方法的好处
     二、创建一个泛型方法格式
     常用的形式
     三、泛型接口
     1、格式
     2、例子
    四、类型通配符(泛型的高级应用)
     1、什么是通配符 (?)
     2、类型通配符上限定(? extends T =>可以接收T类型或者T的子类型)
     3、类型通配符下限定 (? super T => 可以接收T类型或者T父类型)

一、为什么要定义泛型方法

1、从泛型类到泛型方法的演变过程
我们先来看个例子

//定义一个泛型类,并定义如下两个方法
class Test<T>
{
	public  void show(T t){
		System.out.println(t);
	}
     public void print(T t){
    	System.out.println(t);
  }	
  /*  以前是这样定义,现在一个方法搞定
  	public void show(String t){	
	}
	public void show(Integer t){	
	}
	或者
	public void show(Object obj){	
	}
  */
}

//在manin方法代码如下
	public static void main(String[] args) {
	   
		Test<String> d = new Test<String>();
		d.show("java");
		d.print("Object-C");
		
		Test<Integer> e = new Test<Integer>();
		e.show(2);
		e.print(new Integer(5));	
	}

上面是一个简单的代码demo,运行没问题,正常输出。但是你会发现,其实代码有点冗余。我们定义了一个泛型类,并定义了 show(T t)print(T t)方法。发现: 泛型类定义的泛型,在整个类中有效如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所要操作的类型已经固定了。就像上面main方法中。对象d,只能操作String类型,如果你要操作其他类型,只能额外去创建其他泛型对象e

设想下,如果我能把泛型定义在方法上,这样不就可以优雅解决问题。于是变化代码如下

//定义一个类,并定义如下两个泛型方法
class Test
{
	public <T>  void show(T t){
		System.out.println(t);
	}
	
    public <T> void print(T t){
    	System.out.println(t);
  }	
   public <U,T> void sum(U u,T t){
	   System.out.println(u+" version is "+t);
   }
}
// main方法如下
public static void main(String[] args) {
		Test d = new Test();
		d.show("java");
		d.print(5);
		d.sum("java", new Double(8));
	}

Test不再是泛型类,泛型方法show(T t)print(T t)sum(U u,T t) 更具有扩展性。

2、定义泛型方法的好处

泛型方法可以让不同方法操作不同类型,且类型还不确定。
与泛型类不同,泛型方法的类型参数只能在它锁修饰的泛型方法中使用。

二、创建一个泛型方法格式

1、常用的形式

访问修饰符 [static][final] <类型参数列表> 返回值类型 方法名([形式参数列表])

备注:[] 代可有可无的意思,泛型方法可以是实例方法或静态方法,类型参数可以在静态方法中,这是与泛型类最大的区别

三、泛型接口

1、格式

interface 接口名<类型参数表>

2、例子

定义一个泛型接口

interface showInterface<T>
{
	public void show(T t);
	
}

(1) 实现类确定了类型

class ShowClass implements showInterface<String>{
	public void show(String t){
		System.out.println("show:"+t);
	}
}

(2) 实现类类型不确定

class ShowClass<T> implements showInterface<T>{
	public void show(T t){
		System.out.println("show:"+t);
	}
}

main方法

	public static void main(String[] args) {
	
		ShowClass<Integer> obj = new ShowClass<Integer>();
		obj.show(6);
        /*
		ShowClass obj = new ShowClass();
		obj.show("java");
	    */
	}

四、类型通配符(泛型的高级应用)

1、什么是通配符 (?)
看个例子就明白了。定义两个集合,分别输出两个集合的元素。

	public static void main(String[] args) {

		ArrayList<String> a1 = new ArrayList<String>();
		a1.add("a");
		a1.add("b");
		a1.add("c");
		
		ArrayList<Integer> a2 = new ArrayList<Integer>();
		a2.add(1);
		a2.add(2);
		a2.add(3);
	}

在我们没学习泛型之前,我们会封装静态方法如下:

	public static void printList(ArrayList list){
	  for (Iterator iterator = list.iterator(); iterator.hasNext();) 
	  {
		Object object = (Object) iterator.next();
		System.out.println(object);	
	   }
	}

代码买啥毛病,运行也正确。会有一个疑问。为什么参数没定义泛型,但是却可以接受泛型呢?泛型是jdk1.5出来的,老版本肯定要兼容新版本。

在我们学习泛型方法后,我们进一步将代码修改如下:

	public static <T>void vistor(ArrayList<T> a){
		Iterator<T> iterator = a.iterator();
	    while(iterator.hasNext()){
	    	T t = iterator.next(); 
	    	System.out.println(t);
	    }
	}

定义一个泛型方法。如果是泛型类,是不允许泛型定义在static上面的

如果不想定义泛型方法,又能够解决问题呢?这就要用到一个通配符的玩意

	//占位符,也称为通配符。表示元素类型可以匹配任意类型
	public static void sop(ArrayList<?> a){
		for(Iterator<?> it = a.iterator();it.hasNext();){
			System.out.println(it.next());
		}
	}

泛型方法T如果是具体类型的话,可以接收T t = iterator.next();。?是占位符,不明确具体类型,无法接收。

这种带通配符ArrayList<?> aList 仅仅表示他是各种泛型的父类,并不能把元素添加到其中。

我做了奇怪的例子

 ArrayList<?> list = new ArrayList<String>();
list.add(null);

上面说,带通配符ArrayList<?> aList 仅仅表示他是各种泛型的父类,并不能把元素添加到其中。是不是想违背了?仔细想想,null是任意引用类型的实例。这比较特殊。

2、类型通配符上限定(? extends T)

同样看一个例子. 定义一个集合,遍历元素的方法并输出。

//定义一个Person类
class Person
{
	private String name;
	public Person(String name){
		this.name = name;
	}
	public String getNmae(){
		return this.name;
	}
}
// 定义一个Student 并继承 Person
class Student extends Person
{
	Student(String name){
		super(name);
	}
}

main方法如下
public static void main(String[] args) {
		
		ArrayList<Person> a1 = new ArrayList<Person>();
		a1.add(new Person("abc1"));
		a1.add(new Person("abc2"));
		a1.add(new Person("abc3"));

		printMethod(a1);
		
		
		// 下面是错误的。a2存的是Person,存在继承的话,也能放worker。但是等号右边只能存Student,存不进worker.类型安全问题。左右两边要一致
		ArrayList<Student> a2 = new ArrayList<Student>();
		a2.add(new Student("abc--1"));
		a2.add(new Student("abc--2"));
		a2.add(new Student("abc--3"));
		printMethod(a2); // ArrayList<Person> a2 = new ArrayList<Student>();
		//如果我想调用也printMethod(a2);没毛病。怎么做?。 第一想法直接给占位符。但是带来一问题,不能调用具体方法。
	}
	
	// 与main方法同级的静态工具类方法
	public static void printMethod(ArrayList< Person> a1){
		Iterator<Person> it = a1.iterator();
		while(it.hasNext()){
			System.out.println(it.next().getNmae());
		}
	}

如果我想调用也printMethod(a2);没毛病。怎么做?。 第一想法直接给占位符。但是带来一问题,不能调用具体方法。泛型也是一样的。如果我们想两者兼得,既能打印Stuednt,也能打印 Person,我们将printMethod修改如下

	public static void printMethod(ArrayList<? extends Person> a1){
		Iterator<? extends Person> it = a1.iterator();
		while(it.hasNext()){
			System.out.println(it.next().getNmae());
		}
	}

我们称? extends T 为 泛型上限定: 可以接收T和T的子类

3、类型通配符下限定<? super T>

接收T类型或者T的父类型
在这里插入图片描述
从集合TreeSet的构造方法我们可以看到 下限定的运用。我们也可以集合实际例子。

TreeSet<Person> ts = new TreeSet<Person>();  //Comparator<? super E> comparator
ts.add(new Person("d"));
ts.add(new Person("f"));
ts.add(new Person("g"));	

比较器如下

// 这边的T写Student和Person都是可以的
class comp implements Comparator<Person>
{
	public int compare(Person s1,Person s2){
		return s1.getNmae().compareTo(s2.getNmae());
	}
}

其实限定的目的是为了扩展指定类型。

通过上面比较器参数和我们实现的比较器。如果我们比较器的泛型为 Student,那么只能比较Student。当未来某一天,Person有新子类出现的话,那么该比较器就不适用了。所以Java 的API 的考虑扩展性的同时,已经设置了泛型下限定,你可以传T类型或者T的父类型。

在这里插入图片描述

今天的文章Java 泛型方法/接口、泛型限定分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/6873.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注