八、泛型
集合中的泛型
不适用泛型,容器里默认放的类型为Object,所有类型都可以放,但是在取出时需要强制转换
使用泛型后,不仅可以放置该泛型类型的数据,还可以放置其子类的数据。
设计这个类的时候,在类的声明上,加上一个,表示该类支持泛型,在实例化是指定泛型类型。
通配符
? extends T 不能add对象,只能get对象,而且get到的对象类型为T
import java.util.ArrayList;
import java.util.List;
class Fruit { }
class Apple extends Fruit { }
class Banana{ }
public class txt {
public static void main(String[] args){
List<Fruit> list = new ArrayList<Fruit>();//它可以add自身或子类对象
list.add(new Fruit());//自身
list.add(new Apple());//子类
list.add(new Banana());//其他不相关类 报错
List<Fruit> list1 = new ArrayList<Banana>();//报错--不同泛型的容器不能相互引用,除非使用通配符
List<? extends Fruit> list2 = new ArrayList<Banana>();//报错--不是子类不能引用
List<? extends Fruit> list3 = new ArrayList<Apple>();//是子类可以引用
list3.add(new Fruit());//报错--不能add任何东西
Fruit fruit = list3.get(0);//可以get,返回的类型为Fruit
}
}
? super T
import java.util.ArrayList;
import java.util.List;
class Fruit { }
class Apple extends Fruit { }
class RedApple extends Apple{}
class Banana{ }
public class txt {
public static void main(String[] args){
List<? super Apple> list1 = new ArrayList<Fruit>();//是父类可以引用
list1.add(new Apple());//可以放自身
list1.add(new RedApple());//可以放子类
Object object = list1.get(0);//取出对象类型是Object,但这样的话, 元素的类型信息就全部丢失
List<? super Apple> list3 = new ArrayList<Banana>();//报错--不是父类不能引用
}
}
泛型通配符?
泛型通配符? 代表任意泛型
既然?代表任意泛型,那么换句话说,这个容器什么泛型都有可能
所以只能以Object的形式取出来
并且不能往里面放对象,因为不知道到底是一个什么泛型的容器
总结:
如果希望只取出,不插入,就使用? extends Hero
如果希望只插入,不取出,就使用? super Hero
如果希望,又能插入,又能取出,就不要用通配符?
泛型转型
根据面向对象学习的知识,子类转父类 是一定可以成功的
那么子类泛型转父类泛型能成功吗?答案肯定是失败的
练习
1)练习-泛型
根据数字类的知识,设计一个集合,这个集合里即可以放整数,也可以放浮点数,但是不能放字符串
import java.util.ArrayList;
import java.util.List;
public class Exercise {
public static void main(String[] args) {
List<Number> list =new ArrayList<>();
list.add(123);
list.add(1.23f);
list.add("123");//报错
}
}
2)练习-支持泛型的二叉树
把二叉树中的Node类,改造成支持泛型
public class PersonNode<T> {
private PersonNode<T> leftNode;
private PersonNode<T> rightNode;
private T value;
public void add(T t ){
if(this.value == null){
this.value = t;
}else {
if((Integer)this.value > (Integer) t){
if(this.leftNode == null){
this.leftNode = new PersonNode<T>();
}
this.leftNode.add(t);
}else {
if(this.rightNode == null){
this.rightNode = new PersonNode<T>();
}
this.rightNode.add(t);
}
}
}
public PersonNode<T> getLeftNode() {
return leftNode;
}
public PersonNode<T> getRightNode() {
return rightNode;
}
public T getP() {
return value;
}
}
3)练习- extends
如代码所示,为了遍历不同泛型的3种集合,需要设计3个方法
借助? extends, 把代码减肥到只是用一种方法
import java.util.ArrayList;
import java.util.List;
class Fruit { }
class Apple extends Fruit { }
class Banana extends Fruit{ }
public class Exercise {
public static void main(String[] args) {
List<Fruit> list =new ArrayList<>();
List<Apple> list1 =new ArrayList<>();
List<Banana> list2 =new ArrayList<>();
list.add(new Fruit());
list1.add(new Apple());
list2.add(new Banana());
traversal(list);
traversal(list1);
traversal(list2);
}
public static void traversal(List<? extends Fruit> list){
for (Fruit f : list) {
System.out.println(f);
}
}
}
4)练习-二叉树
把练习-支持泛型的二叉树改造成 支持泛型 ,并在比较的时候使用compare方法
public class PersonNode<T extends Comparable> {
private PersonNode<T> leftNode;
private PersonNode<T> rightNode;
private T value;
public void add(T t ){
if(this.value == null){
this.value = t;
}else {
if(this.value.compareTo(t) > 0){
if(this.leftNode == null){
this.leftNode = new PersonNode<T>();
}
this.leftNode.add(t);
}else {
if(this.rightNode == null){
this.rightNode = new PersonNode<T>();
}
this.rightNode.add(t);
}
}
}
public PersonNode<T> getLeftNode() {
return leftNode;
}
public PersonNode<T> getRightNode() {
return rightNode;
}
public T getP() {
return value;
}
}
5)练习-父类泛型能否转换为子类泛型?
那么父类泛型又能否转换成子类泛型? 为什么?
import java.util.ArrayList;
import java.util.List;
class Fruit { }
class Apple extends Fruit { }
class Banana extends Fruit{ }
public class Exercise {
public static void main(String[] args) {
List<Fruit> list =new ArrayList<>();
List<Apple> list1 =new ArrayList<>();
List<Banana> list2 =new ArrayList<>();
/***
* 假设允许转型
* list指向了list2容器
* 由于list泛型为Fruit,所以可以放Apple
* 这样就导致一个Banana容器放置了一个Apple
* 不符合逻辑
*/
list = list2;//子类泛型转父类失败
/***
* 假设允许转型
* list2指向了list容器
* 当list2需要出去对象时,容器里面放的都是Fruit
* 把Banana的类型指向Fruit的类型是不和逻辑的
*/
list2 = list;//父类泛型转子类失败
}
}