Day19——泛型

泛型

1、什么是泛型?

所谓的泛型就是指类型参数化。

通俗的来说,就是将类型定义成一个变量并进行参数声明,在使用时传入类型实参来明确具体的类型。

public class Demo {
	public <E> void method(E e) {
		//这是一个泛型方法,它包含一个类型变量E
		System.out.println(e);
	}
}
		Demo demo = new Demo();
		//我们调用method的时候必须传入类型实参来明确变量E
		demo.<String>method("hello");

2、为什么要定义泛型?

在JDK1.5以前,想要接收或返回多种类型,只能接收或返回它们的父类(比如集合的接收类型为Object)。这样在使用对象时就要在必要的地方加上强制转型代码,容易在运行时期出现类型转换异常(ClassCastException)。

	List list = new ArrayList();
		list.add("abc");
		// 因为接收类型为Object,所以我们有可能误装入了Integer对象
		list.add(4);
		for (Object obj : list) {
			//在迭代过程中,我们不知道有Integer对象,进行了向下转型
			//这里会发生ClassCastException
			String str = (String) obj;
			System.out.println(str.length());
		}
而有了泛型,它允许将类型定义成一个变量。那么,对于接收或返回多种类型的情况,我们可以把接收或返回的类型定义成变量,在具体使用时再传入类型实参来明确。比如,当我们给List<E>中传入了具体实参String后,List<String>就明确了其add方法为add(String e)。
		//在使用List的时候,我们传入了参数String。那么其add方法也由add(E e),变为add(String e)
		List<String> list = new ArrayList<String>();
		list.add("abc");
		// 由于add方法的接收类型变成了String,此时添加Integer对象就会出现编译报错
		list.add(4);

3、泛型与函数的对比

函数→要处理的数据值不确定→定义成一个变量并进行参数声明→调用函数时必须传递实际参数

泛型→要操作的数据类型不确定→定义成一个变量并进行参数声明→使用泛型类、接口、方法时必须传递实际参数

注意:泛型同函数一样,传入的实际参数可以是一个确定的类型,也可以是一个类型变量。

public interface List<E> extends Collection<E> 
//向Collection中传入的时List的类型变量E

4、泛型的通配符

同一个类的泛型类之间是没有继承关系的,比如List<String>和List<Object>是两个不同的类,而且并没有继承关系。

如果我们想定义一个引用来接收不同泛型类的对象(类似与父类接收子类对象),可以使用通配符 ?。

比如List<?>可以接收List的所有泛型类对象,其中 ?  表示任意类型。

通配符在使用的过程中可以进行上限和下限的限定,几种写法对比如下:

List<Person>				//只能接收一种类型的对象
List<?>					//可以接收所有泛型类的对象
List<? extends Person>			//可以接收所有是Person子类的对象(包括Person)
List<? super Person>			//可以接收所有是Person父类的对象(包括Person)

5、泛型的擦除

泛型实际上是Java的一颗语法糖,它在运行时期并不存在,仅仅是Java在编译时期的行为。

Java在编译期认为List<String>和List<Integer>是两个不同的类,然后进行了相关代码的检查。在编译通过后,Java编译器就自动在对象进入和离开方法的边界处添加了强制类型转换。而在运行时期,所谓的List<String>,List<Integer>类,以及类型变量,都是不存在的。List<String>,List<Integer>的对象在运行时期是相同的类型(都是List类),而类型变量都会被相应的具体类型(比如Object)替换掉。

所以在我们使用时,从List<String>对象中取出的是String,只是因为编译器添加了强制转换代码。

6、泛型类,泛型接口,泛型方法

a) 泛型类

所谓的泛型类,就是把泛型定义在类上,在继承或者实例化类的时候,由使用者来传入类型实参。

//用<>在类上声明,类中有一个类型变量E
class Tool<E>{
    private E e;
    public E getE() {
        return e;
    }
    public void setE(E e) {
        this.e = e;
    }
}
Tool<String> tool = new Tool<String>();
注意:静态变量与静态方法不能调用类上的泛型。

如果静态方法需要定义泛型,泛型只能定义在方法上。

b) 泛型方法

泛型类存在一个问题,就是其传参过程发生在实例化时期。一旦对象实例化完成,类中的类型变量就被固定不再改变。如果想再次传参只能重新实例化对象。

class Demo<E>{
	public void show1(E e) {
		System.out.println(e);
	}

	public void show2(E e) {
		System.out.println(e);
	}
}
Demo<String> d1 = new Demo<String>();
d1.show1("abc");
//编译失败,无法传入4,因为d1中类型变量已经定为String了
d1.show2(4);
Demo<Integer> d2 = new Demo<Integer>();
//只能通过重新实例化对象来重新传参
d2.show2(4);
而泛型方法解决了这个问题,泛型方法的传参过程是方法的调用时期。

class Demo<E>{
    public void show1(E e) {
        System.out.println(e);
    }

    public <T>void show2(T e) {
        //这是一个泛型方法,类型变量为T
        System.out.println(e);
    }
}
Demo<String> d1 = new Demo<String>();
d1.show1("abc");
//show2调用时才进行单独的传参
d1.<Integer>show2(4);

c) 泛型接口

将泛型定义在接口上。

在实现接口的时候进行传参。

interface Inter<E>{
	public void show(E e);
}

class Demo1 implements Inter<String>{
	//传递一个具体类型作为实参
}

class Demo2<T> implements Inter<T>{
	//传递一个类型变量作为实参
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值