泛型的基本概念

1.什么时候使用泛型:泛型在Java中有着至关重要的作用,Java中所有的集合都需要使用到泛型。只要在使用类或者接口时,该类或者接口在api文档描述时都带着<>,就需要在使用时定义泛型。其实,泛型无非就是通过<>定义了一个形式参数,专门用于接收具体的引用类型。在使用时,一定要传递对应的实际参数类型。

2.泛型的檫除:泛型是JDK1.5之后出现的,所以为了避免修改JVM,就多了一个泛型的檫除,泛型是之出现在编译期的,运行是并没有泛型,也就是说,编译器会按照<>中的指定类型对元素进行检查,检查不匹配,就编译失败,匹配,就编译通过,通过后,产生的class文件中是没有泛型的,这就成为泛型的擦除

3.泛型的补偿:运行时,可以根据具体的元素对象获取其具体的类型,并用该类型对元素进行自动转换。

泛型的基本使用

 * T--Type -> 通常在比较器上面见到


 * E--Element -> 通常在集合上面见到,或者是自定义的集合


 * K,v--Key,Value —> Map<K,V

泛型分为三种类型:
  • 类的泛型

类的泛型比如在自定义一个集合的使用就需要使用到:class MySet<E>{ ... },下面来个简单的例子

class Myset<E>{
List<E> list = new ArrayList<E>();
public boolean add(E e){
return list.add(e);
}
public boolean delete(E e){
return list.remove(e);
}
public boolean replace(E e1,E e2){
if(!list.contains(e1)){
return false;
}
for (int i = 0; i < list.size(); i++) {
if(list.get(i).equals(e1)){
list.remove(i);
list.add(i, e2);
break;
}
}
return true;
}
public Object[] toArray(){
return list.toArray();
}
public int size(){
return list.size();
}
public E get(int index){
return list.get(index);
}
}
@Test
public void test2(){
Myset<String>set = new Myset<String>();
set.add("老干妈");
set.add("保济丸");
set.add("炸牛奶");
set.delete("aa");
set.delete("保济丸");
for (int i = 0; i < set.size(); i++) {
System.out.println(set.get(i));
}
System.out.println("--------");
set.replace("老干妈", "老干爹");
set.replace("炸牛奶", "炸地瓜");
for (int i = 0; i < set.size(); i++) {
System.out.println(set.get(i));
}
/*
老干妈
炸牛奶
--------
老干爹
炸地瓜
*/
}



  • 方法上的泛型

方法上的泛型也细分为三种,与类捆绑的泛型(相当于前面的类的泛型)、独立于类的泛型、静态方法的泛型

class Show<E>{
//与类捆绑的泛型
public void print(E e){
System.out.println(e);
}
//独立与类的泛型
public <T> void qq(T t){
System.out.println("qq:"+t);
}
//静态方法泛型的使用,不能与类的泛型一致,因为静态是类模板,不能调用对象的实例
public static <T> void yy(T y){
System.out.println("yy:"+y);
}
}
@Test
public void test1(){
Show<String> show = new Show<String>();
show.print("123");
}

@Test
public void test3(){
Show<Integer>show = new Show<Integer>();
show.qq("二手苹果");
}

@Test
public void test4(){
Show.yy("石头蚊帐二叉树");
}
  • 接口中的泛型

接口中的泛型使用与前面的使用也差不多,就是在实现类的时候也需要给一个泛型

public class InteGT {
public static void main(String[] args) {
Bill<Integer> b = new billImp<Integer>();
b.showBill(100);
/*
以上操作相当于
List<Integer>list = new ArrayList<Integer>();
list.add(10);
*/
}
}
//接口
interface Bill<E>{
void showBill(E e);
}
//实现类
class billImp<E> implements Bill<E>{
@Override
public void showBill(E e) {
System.out.println("下一站:茶山刘"+e);
}
}

泛型的高级应用

高级泛型使用通配符?来表示

当操作的不同容器中的类型都不确定的时候,而且使用的都是元素从Object类中继承的方法, 这时泛型就用通配符?来表示即可。(助理解的比方: 泛型中的多态应用)

@Test
public void test2(){
Set<Integer>set1 = new HashSet<Integer>();
set1.add(1);
set1.add(2);
set1.add(3);
set1.add(4);

Set<String>set2 = new HashSet<String>();
set2.add("闪电侠");
set2.add("蝙蝠侠");
set2.add("钢铁侠");
set2.add("蜘蛛侠");

printAllSet(set1);
printAllSet(set2);
}
/**
* 兼容所有,相当于多态中的Object
* @param set
*/
public void printAllSet(Set<?>set){
for (Object object : set) {
System.out.println(object);
}
}

泛型的上下兼容:泛型有上限和下限之分

对操作的类型限制在一个范围之内。比如:定义一个功能,只操作Person类型或者Person的子类型。这时可以用:  
? extends E:接收E类型或者E的子类型。这就是上限。

? super E:   接收E类型或者E的父类型。 这就是下限。

这里就演示一下泛型的上限

@Test
public void test1(){
Set<Person>set = new HashSet<Person>();
set.add(new Student("Bally", 18, "计算机"));
set.add(new Student("Sammi", 19, "商务英语"));
set.add(new Student("Oliv", 20, "射箭"));

set.add(new Worker("老干爹", 53, "卖老干妈"));
set.add(new Worker("老干妈", 52, "卖老干爹"));
set.add(new Worker("老王", 54, "吃老干妈"));

print(set);
}
class Person{
public String name;
public int age;

public Person(String name,int age){
this.name = name;
this.age = age;
}
}
class Student extends Person{
String specialty;
public Student(String name, int age,String specialty) {
super(name, age);
this.specialty = specialty;
}
}
class Worker extends Person{
String job;
public Worker(String name, int age,String job) {
super(name, age);
this.job = job;
}
}