JavaSE-泛型

为什么要使用泛型?

泛型类:

解决参数转换的问题

在不泛型的时候。我们定义一个Point类,如果无法确定成员变量的类型。我们会像下面这样写

class Point{
    private Object x;
    private Object y;
public Point(Object x, Object y){
    this.x = x;
    this.y = y;
}
}
当我们使用的时候,可以用一下方式创建一个Point对象。

Point p0 = new Point(5, 6);
Point p1 = new Point("115.3'C", 60);
Point p2 = new Point(5.4f, 6);

第一个是正确的,但是其他的两个参数类型不一样,所以使用的时候会出很多问题。这个时候就需要用到泛型。

泛型在使用的时候才指定参数类型。有了泛型,代码就可以像下面这样写:

class Point<T>{
    private T x;
    private T y;
    public Point(T x, T y){
        this.x = x;
        this.y = y;
}
}

使用的时候只需要指定一下类型。x y类型就统一了,也不会出现类型转换错误。

Point<Integer> p = new Point<>(5, 6);
这样,x和y就只能是整型了。

当规定为整形而参数列表中使用了其他类型时,就会在编译阶段就爆出错误。

泛型方法:

泛型不仅可以用来定义类,还可以定义方法。如下定义:

public <T> void fun(T arg){
	System.out.println(arg);
}

泛型类和泛型方法不冲突:

方式一:

class Point<T>{
    private T x;
    private T y;
    public Point(T x, T y){
        this.x = x;
        this.y = y;
}
public <V> V void fun(V arg)
{
	System.out.println(arg);
}
}

方式二:

class Point<T>{
    private T x;
    private T y;
    public Point(T x, T y){
        this.x = x;
        this.y = y;
}
public <T> T void fun(T arg)
{
	System.out.println(arg);
}
}


两种方式都是可以的,互不冲突,但是避免混淆,应该使用方式1.

通配符:

泛型一经过定义就限制了参数的类型。

这样有好处也有坏处。

例如下面的代码会出错:

Point<String> p = new Point<>(5, 6);
或者:

Caculate<Integer> caculate = new Caculate<>();
caculate.add(5, 6);

对于一个计算类来说,是不可能只有整形的。我们需要是所有的Number类型都可以被计算。

通配符就是用来解决上述的缺点的。

通配符有三种:

? : 匹配所有类型

? extends String :匹配以String及其子类。由于String是final类,所以String只能匹配String。

? super String :匹配以String及其父类。String类直接继承Object类,所以只能匹配String和Object类


例子:? : 匹配所有类型

 
 
class Message<T>{
	private T t;
	public Message(T t) {
		this.t = t;
	}
	
	public void setT(T t) {
		this.t= t;
	}
	public void print() {
		System.out.println(this.t);
	}
}

public class Test {
	public static void main(String[] args) {
		Message<String> m = new Message("4545");
		fun(m);
		
		Message<Integer> m1 = new Message(5);
		fun(m1);
		
		Message<Double> m2 = new Message(5.5);
		fun(m2);
	}
	public static void fun(Message<?> m) {
		// m.setT("1234");  //写这句会出错,通配符为?时无法修改使用了通配符属性的值
		m.print();
	}
}


例子:?extends 上限类

class Message<T>{
	private T t;
	public Message(T t) {
		this.t = t;
	}
	
	public void setT(T t) {
		this.t= t;
	}
	public void print() {
		System.out.println(this.t);
	}
}

public class Test {
	public static void main(String[] args) {
		//出错,Number的子类为Integer Byte Double Float Character Short
//		Message<String> m = new Message("4545");
//		fun(m);
		
		//这两句会出错,因为<? super String>只能匹配String和Object
//		Message<Object> m1 = new Message<Object>(new Object());
//		fun(m1);
		
		
		Message<Double> m2 = new Message(5.5);
		fun(m2);
		
		Message<Double> m3 = new Message('c');
		fun(m3);
		
	}
	public static void fun(Message<? extends Number> m) {
//		m.setT(8);  //写这句会出错,通配符为?时无法修改使用了通配符属性的值
		m.print();
	}
}


例子:?super 下限类

 
 
class Message<T>{
	private T t;
	public Message(T t) {
		this.t = t;
	}
	
	public void setT(T t) {
		this.t= t;
	}
	public void print() {
		System.out.println(this.t);
	}
}

public class Test {
	public static void main(String[] args) {
		Message<String> m = new Message("4545");
		fun(m);
		Message<Object> m1 = new Message<Object>(new Object());
		fun(m1);
		
		
		
	}
	public static void fun(Message<? super String> m) {
		m.setT("5");  //写这句不会出错,通配符为<? super 下限类>时可以修改使用了通配符属性的值
		m.print();
	}
}

类型擦除:

类型擦除是指,泛型只存在于代码编译阶段,在进入JVM之前,与泛型相关的类型会被替换成相应的类型,对于虚拟机来说,泛型类和普通类没有任何区别。

如果未设置泛型上限。

class Point<T>{
	T x;
	T y;
}

会变成

class Point{
	Object x;
	Object y;
}

设置了泛型上限就会被替换成相应的泛型上限。



猜你喜欢

转载自blog.csdn.net/bugggget/article/details/80092059