泛型

  • 泛型
  • 概述
  • 泛型类
  • 泛型方法
  • 泛型接口
  • 泛型的限制
  • 无界通配符
  • 有界通配符


泛型

概述

泛型:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。

泛型的特点:

  • 提高了程序的安全性
  • 将运行期遇到的问题转移到了编译期
  • 省去了类型强转的麻烦
  • 泛型类的出现优化了程序设计

泛型的格式:

  • 通过<>来定义要操作的引用数据类型
import java.util.*;
class Demo2
{
	public static void main(String[] args) 
	{
		TreeSet<String> ts = new TreeSet<String>(new LenComparator());

		ts.add("abcd");
		ts.add("cc");
		ts.add("cba");
		ts.add("aaa");
		ts.add("z");
		ts.add("hahaha");

		Iterator<String> it = ts.iterator();
		while(it.hasNext())
		{
			String s = it.next();
			System.out.println(s);
		}
	}
}

class LenComparator implements Comparator<String> //比较器也需要泛型
{
	public int compare(String o1,String o2)
	{
		int num = new Integer(o1.length()).compareTo(new Integer(o2.length()));
		//倒序int num = new Integer(o2.length()).compareTo(new Integer(o1.length()));
		if(num==0)
			return o1.compareTo(o2);
		return num;
	}
}

如果想要容器倒序,只需要将调用比较方法的对象和比较对象互换位置。

泛型类

  • 格式 class 类名称<T>
    T为泛型,它可以是任意的对象或接口,但不能是基本类型
  • 什么时候定义泛型类?
    当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展。
    现在定义泛型来完成扩展。

示例:

class Demo
{
	public static void main(String[] args){
		Person<Student> s=new Person<Student>(); //泛型类为
		s.setT(new Student());
		System.out.println(s.getT(new Student()));
	}
}

class Person<T> //T可以是任意对象或接口,它就是代表一个参数
{
	private T t;
	public void setT(T t){
		this.t=t;
	}
	public T getT(T t){
		return t;
	}
}

class Student
{
}

用Object类实现:

class Demo
{
	public static void main(String[] args){
		ObjectDemo o=new ObjectDemo();
		o.setObj(new Student());
		Student s2=(Student)o.getObj();//需要将返回的Obj类型强制转换成对应的类型
	}
}

class ObjectDemo
{
	private Object o;
	public void setObj(Object o)
	{
		this.o=o;
	}
	public Object getObj(){
		return o;
	}
}

class Student
{
}

但我们如果将强制转换改成:

String s2=(String)o.getObj();

在编译时期不会出错,但是在运行时就会报错。
这是因为编译器在编译时不知道你传进去的是什么类型,且getObj方法返回的是Object类型,所以将Object转换为String类型是可以的。但是在运行时,我们是将Student类型的对象通过setObj方法传递给了o,再通过setObj返回了一个Student类型对象,而此时再将Student类型转换为String类型是不可能通过的。

而使用泛型,就不再需要强制转换,且如果传入类型不对,在编译时期就会报错。

泛型方法

泛型类定义的泛型,在整个类中有效。如果被方法使用,那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。

为了让不同方法可以操作不同类型,而且类型还不确定。那么可以将泛型定义在方法上。

class Demo
{
	public static void main(String[] args){
		//泛型类只能使用声明的类型
		Person<String> p=new Person<String>();
		p.print("haha");
		//p.print(123); 

		//泛型方法可以操作不同的类型
		People p2=new People();
		p2.print("haha");
		p2.print(123);
	}
}

class Person<T>
{
	public void print(T t){
		System.out.println(t);
	}
}

class People
{
	public <T> void print(T t){
		System.out.println(t);
	}
}

泛型类上也能定义泛型方法,效果也是一样的。


对于静态方法,它不可以访问类上定义的泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

class Person
	{
		public static <T> void print(T t){...}
	}

泛型接口

将泛型定义在接口上:

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

//该类不属于泛型类,并将泛型变量T填充为String类型
class InterImplFixed implements Inter<String> 
{
	public void show(String t)
	{
		System.out.println("show :"+t);
	}
}

//用泛型类实现泛型接口
class InterImpl<T> implements Inter<T>
{
	public void show(T t)
	{
		System.out.println("show :"+t);
	}
}

class Demo
{
	public static void main(String[] args) 
	{
		//非泛型类
		InterImplFixed inf=new InterImplFixed();
		inf.show("4");

		//泛型类
		InterImpl<Integer> i = new InterImpl<Integer>();
		i.show(4);
	}
}

使用泛型类来继承泛型接口的作用就是让用户来定义接口所使用的变量类型,而不是像方法一那样,在类中写死。

泛型的限制

无界通配符

无界通配符:类型通配符一般使用?代替具体的类型实参。当操作类型时不需要使用类型的具体功能时,只使用Object类中的功能,那么可以用 ? 通配符来表未知类型。

  • 类型参数<T>主要用于声明泛型类或泛型方法。 无界通配符<?>主要用于使用泛型类或泛型方法。
public class Test1 {
     public <T> void test1(List<T> list){
        System.out.println("list length: " + list.size());  
        if (!list.isEmpty()) {
            T t = list.get(0); //list中的元素为T类型
            System.out.println("t = " + t);
        }
    }
 
    public void test2(List<?> list){
        System.out.println("list length: " + list.size());
        if (!list.isEmpty()) {
            Object o = list.get(0);//list中的元素为Object
            System.out.println("o = " + o);
        }
    }
}

<?>代表任意java类型,只有在不关心数据的具体类型下才使用通配符表示,但在一些情况下,需要将<?>传入的数据进行强转,但这样不如直接传入。


有界通配符

  • 上界通配符
    ?extends E:可以接收E类型或者E的子类型。代表上限。
  • 下界通配符
    ? super E:可以接收E类型或者E的父类型。代表下限。

示例:

在TreeSet构造方法中,有带比较器参数的构造方法:

java interface 泛型属性_泛型

import java.util.*;
class GenericDemo7 
{
	public static void main(String[] args) 
	{
		TreeSet<Student> ts = new TreeSet<Student>(new Comp());
		
		ts.add(new Student("abc03"));
		ts.add(new Student("abc02"));
		ts.add(new Student("abc06"));
		ts.add(new Student("abc01"));
		
		Iterator<Student> it = ts.iterator();

		while(it.hasNext())
		{
			System.out.println(it.next().getName());
		}

		TreeSet<Worker> ts1 = new TreeSet<Worker>(new Comp());

		ts1.add(new Worker("wabc--03"));
		ts1.add(new Worker("wabc--02"));
		ts1.add(new Worker("wabc--06"));
		ts1.add(new Worker("wabc--01"));

		Iterator<Worker> it1 = ts1.iterator();

		while(it1.hasNext())
		{
			System.out.println(it1.next().getName());
		}
	}
}

class Comp implements Comparator<Person>
{
	public int compare(Person p1,Person p2)
	{
		return p2.getName().compareTo(p1.getName());
	}
}

class Person
{
	private String name;
	Person(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
	public String toString()
	{
		return "person :"+name;
	}
}

class Student extends Person
{
	Student(String name)
	{
		super(name);
	}
}

class Worker extends Person
{
	Worker(String name)
	{
		super(name);
	}
}