JAVA中级四 泛型

泛型

01集合中的泛型

1.1 泛型的优势

  1. 明确ArraylIst存储的对象类型,避免强制转换对象类型,同是避免遗忘对象所属类型;
  2. 泛型的用法<Type>,Type可以是接口,类,抽象类;
  3. 只能存放该Type,其他放不进去。
  4. 可以存放Type的子类。

1.2 泛型的简写

ArrayList<Hero> heros2 = new ArrayList<>();
后面的泛型用<>代替,可写可不写。
补充作业:
若要设计一个集合,既可以放整数,也可以放浮点数,但不能放字符串。
需要使用到NUmber类。
ArrayList<Number> number = new ArrayList<>();

02 支持泛型的类

2.1 不支持泛型类

以Stack栈为例子,如果不支持泛型
当需要一个只能放Hero的栈的时候,就需要设计一个HeroStack;
当需要一个只能放Item的栈的时候,就需要一个ItemStack;

package generic;
   //HeroStack
import java.util.LinkedList;
 
import charactor.Hero;
   
public class HeroStack {
   
    LinkedList<Hero> heros = new LinkedList<Hero>();
       
    public void push(Hero h) {
        heros.addLast(h);
    }
   
    public Hero pull() {
        return heros.removeLast();
    }
   
    public Hero peek() {
        return heros.getLast();
    }
       
    public static void main(String[] args) {
           
        HeroStack heroStack = new HeroStack();
        for (int i = 0; i < 5; i++) {
            Hero h = new Hero("hero name " + i);
            System.out.println("压入 hero:" + h);
            heroStack.push(h);
        }
        for (int i = 0; i < 5; i++) {
            Hero h =heroStack.pull();
            System.out.println("弹出 hero" + h);
        }
    }
   
}
package generic;
   
import java.util.LinkedList;
 
import property.Item;
   
public class ItemStack {
   
    LinkedList<Item> Items = new LinkedList<Item>();
       
    public void push(Item h) {
        Items.addLast(h);
    }
   
    public Item pull() {
        return Items.removeLast();
    }
   
    public Item peek() {
        return Items.getLast();
    }
       
    public static void main(String[] args) {
           
        ItemStack ItemStack = new ItemStack();
        for (int i = 0; i < 5; i++) {
            Item item = new Item("Item name " + i);
            System.out.println("压入 Item:" + item);
            ItemStack.push(item);
        }
        for (int i = 0; i < 5; i++) {
            Item item =ItemStack.pull();
            System.out.println("弹出 Item" + item);
        }
    }
   
}

2.2 支持泛型的类

设计一个支持泛型的栈MyStack
设计这个类的时候,在类的声明上,加上一个,表示该类支持泛型。
T是type的缩写,也可以使用任何其他的合法的变量,比如A,B,X都可以,但是一般约定成俗使用T,代表类型。

package generic;
   
import java.util.HashMap;
import java.util.LinkedList;
 
import charactor.Hero;
import property.Item;
   
public class MyStack<T> {
   
    LinkedList<T> values = new LinkedList<T>();
       
    public void push(T t) {
        values.addLast(t);
    }
   
    public T pull() {
        return values.removeLast();
    }
   
    public T peek() {
        return values.getLast();
    }
       
    public static void main(String[] args) {
        //在声明这个Stack的时候,使用泛型<Hero>就表示该Stack只能放Hero
        MyStack<Hero> heroStack = new MyStack<>();
        heroStack.push(new Hero());
        //不能放Item
        heroStack.push(new Item());
         
        //在声明这个Stack的时候,使用泛型<Item>就表示该Stack只能放Item
        MyStack<Item> itemStack = new MyStack<>();
        itemStack.push(new Item());
        //不能放Hero
        itemStack.push(new Hero());
    }
   
}

练习-支持泛型的二叉树

package collection;

import java.util.ArrayList;
import java.util.List;

/*
*@Author hmg
*@Description 
*@Time 2019年12月9日下午8:12:08
*@Version1.0
*/
public class Node<T>{
	public Node<T> leftNode;
	public Node<T> rightNode;
	public T value;
	
	public void add(T v) {
		if(null==value) {
			value=v;
		}
		else{
			if((Integer)v-(Integer)value<=0) {
				if(null==leftNode)
					leftNode=new Node<T>();
				leftNode.add(v);
			}
			else {
				if(null==rightNode)
					rightNode=new Node<T>();
				rightNode.add(v);
			}
		}
	}
	
	public List<T> values(){
		List<T> values=new ArrayList<>();
		if(null!=leftNode) {
			values.addAll(leftNode.values());
		}
		values.add(value);
		if(null!=rightNode) {
			values.addAll(rightNode.values());
		}
		return values;
	} 

	public static void main(String[] args) {
		int [] list=new int[] {65,23,67,8,13,456,78,43,56,102};
		Node<Integer> roots=new Node<>();
		for(int i:list) {
			roots.add(i);
		}
		System.out.println(roots.values());
		
		
	}
}

问题:
但是这样的泛型有个弊端,在比较的时候,泛型T被转换为了Integer进行大小比较。换句话说,如果写成非Integer泛型,就会出现类型转换异常。
这个问题的解决,需要用到后面的 ? extends 模式

03 通配符

3.1 ? extends

	ArrayList<APHero> apHeroList = new ArrayList<APHero>();
	apHeroList.add(new APHero());
	ArrayList<? extends Hero> heroList = apHeroList;

ArrayList heroList<? extends Hero> 表示这是一个Hero泛型或者其子类泛型

  1. heroList 的泛型可能是Hero
  2. heroList 的泛型可能是APHero
  3. heroList 的泛型可能是ADHero

所以 可以确凿的是,从heroList取出来的对象,一定是可以转型成Hero的

但是,不能往里面放东西,因为
放APHero就不满足< ADHero >
放ADHero又不满足< APHero >

3.2 ? super

	ArrayList<? super Hero> heroList = new ArrayList<Object>();

ArrayList heroList<? super Hero> 表示这是一个Hero泛型或者其父类泛型

  1. heroList的泛型可能是Hero
  2. heroList的泛型可能是Object

可以往里面插入Hero以及Hero的子类
但是取出来有风险,因为不确定取出来是Hero还是Object(Object是强转Hero会失败)。

3.3 泛型通配符?

	ArrayList<APHero> apHeroList = new ArrayList<APHero>();
	//?泛型通配符,表示任意泛型
	ArrayList<?> generalList = apHeroList;

泛型通配符? 代表任意泛型
既然?代表任意泛型,那么换句话说,这个容器什么泛型都有可能

所以只能以Object的形式取出来
并且不能往里面放对象,因为不知道到底是一个什么泛型的容器

3.4 总结

  1. 如果希望只取出,不插入,就使用? extends Hero
  2. 如果希望只插入,不取出,就使用? super Hero
  3. 如果希望,又能插入,又能取出,就不要用通配符?

3.5 练习- ?extends

减肥前:
为了遍历不同泛型的3种集合,需要设计3个方法

package generic;
 
import java.util.ArrayList;
 
import charactor.ADHero;
import charactor.APHero;
import charactor.Hero;
 
public class TestGeneric {
 
    public static void iterate(ArrayList<Hero> list) {
        for (Hero hero : list) {
            System.out.println(hero.name);
        }
    }
 
    public static void iterateAP(ArrayList<APHero> list) {
        for (Hero hero : list) {
            System.out.println(hero.name);
        }
    }
 
    public static void iterateAD(ArrayList<ADHero> list) {
        for (Hero hero : list) {
            System.out.println(hero.name);
        }
    }
 
    public static void main(String[] args) {
        ArrayList<Hero> hs = new ArrayList<>();
        ArrayList<APHero> aphs = new ArrayList<>();
        ArrayList<ADHero> adhs = new ArrayList<>();
 
        iterate(hs);
        iterateAP(aphs);
        iterateAD(adhs);
    }
 
}

减肥后:
只要一个方法

package generic;
  
import java.util.ArrayList;
  
import charactor.ADHero;
import charactor.APHero;
import charactor.Hero;
  
public class TestGeneric {
  
    public static void iterate(ArrayList<? extends Hero> list) {
        for (Hero hero : list) {
            System.out.println(hero.name);
        }
    }
  
    public static void main(String[] args) {
        ArrayList<Hero> hs = new ArrayList<>();
        ArrayList<APHero> aphs = new ArrayList<>();
        ArrayList<ADHero> adhs = new ArrayList<>();
  
        iterate(hs);
        iterate(aphs);
        iterate(adhs);
    }
  
}

3.6 练习- 二叉树

package collection;

import java.util.ArrayList;
import java.util.List;

import charactor.GiantDragon;
import charactor.Hero;
//把Node设计为
public class Node<T extends Comparable<T>> {
//表示只能使用那些实现了Comparable接口的泛型,比如Integer,Hero
   public Node<T> leftNode;

   public Node<T> rightNode;

   public T value;

   public void add(T t) {

       if (null == value)
           value = t;

       else {

           //t和value都是T 类型,而T类型extends Comparable,所以必然提供compare接口
           if (t.compareTo(value) <= 0) {
               if (null == leftNode)
                   leftNode = new Node<T>();
               leftNode.add(t);
           }

           else {
               if (null == rightNode)
                   rightNode = new Node<T>();
               rightNode.add(t);
           }

       }

   }

   public List<T> values() {
       List<T> values = new ArrayList<>();

       if (null != leftNode)
           values.addAll(leftNode.values());

       values.add(value);

       if (null != rightNode)

           values.addAll(rightNode.values());

       return values;
   }

   public static void main(String[] args) {

       int randoms[] = new int[] { 67, 7, 30, 73, 10, 0, 78, 81, 10, 74 };

       Node<Integer> roots = new Node<>();
       for (int number : randoms) {
           roots.add(number);
       }

       System.out.println(roots.values());
        //Integer实现了 Comparable接口,所以可以作为Node的泛型
       //Hero实现了 Comparable接口,所以可以作为Node的泛型
       Node<Hero> heros = new Node<>();
        
       //GiantDragon 没有实现 Comparable接口,所以不能作为Node的泛型
       Node<GiantDragon> dragons = new Node<>();
        
   }
}

04 泛型转型

4.1 子类转父类?

	ArrayList<Hero> hs =new ArrayList<>();
	ArrayList<ADHero> adhs =new ArrayList<>();
	//子类泛型转父类泛型
	hs = adhs;//?

假设可以转型成功
引用hs指向了ADHero泛型的容器
作为Hero泛型的引用hs, 看上去是可以往里面加一个APHero的。
但是hs这个引用,实际上是指向的一个ADHero泛型的容器
如果能加进去,就变成了ADHero泛型的容器里放进了APHero,这就矛盾了

所以子类泛型不可以转换为父类泛型

4.1 父类转子类?

	ArrayList<Hero> hs =new ArrayList<>();
	ArrayList<ADHero> adhs =new ArrayList<>();
	//子类泛型转父类泛型
	adhs = hs;//?

假设能成功
这个时候adhs实际上指向的是泛型是Hero的容器,而这个容器里可能放的是一个APHero
而根据泛型,直接取出来就转型成了ADHero
所以就变成了APHero转型成ADHero,这是矛盾的。
所以反推,父类泛型不能转型为子类泛型

本文学习内容均来自how2j.cn,用于个人笔记和总结,想学习的可以到该网站学习哦,侵删。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值