https://www.nowcoder.com/tutorial/94/ae05554a3ad84e42b6f9fc4d52859dc4
https://how2j.cn/frontroute
https://how2j.cn/k/generic/generic-generic/373.html
目录
1 集合泛型
1.1 泛型的便利
不用泛型:
public static void main(String[] args) {
ArrayList heros = new ArrayList();
heros.add(new APHero());
heros.add(new ADHero());
APHero apHero = (APHero) heros.get(0);
ADHero adHero = (ADHero) heros.get(1);
ADHero adHero2 = (ADHero) heros.get(0);
}
ADHero adHero2 = (ADHero) heros.get(0);
就会报错
使用泛型:
public static void main(String[] args) {
ArrayList<APHero> heros = new ArrayList<APHero>();
//只有APHero可以放进去
heros.add(new APHero());
//ADHero甚至放不进去
//heros.add(new ADHero());
//获取的时候也不需要进行转型,因为取出来一定是APHero
APHero apHero = heros.get(0);
}
1.2 子类对象
public static void main(String[] args) {
ArrayList<Hero> heros = new ArrayList<Hero>();
//只有作为 Hero 的子类可以放进去
heros.add(new APHero());
heros.add(new ADHero());
//和 Hero 无关的类型 Item 放不进去
//heros.add(new Item());
}
1.3 简写
public static void main(String[] args) {
ArrayList<Hero> heros = new ArrayList<Hero>();
//后面可以只用<>
ArrayList<Hero> heros2 = new ArrayList<>();
}
1.4 练习
设计集合,可以放整数,也可以放浮点数,但不能放字符串
package 第16个程序_泛型.a1_集合泛型.练习;
import java.util.ArrayList;
import java.util.List;
public class test {
public static void main(String[] args) {
List<Number> list = new ArrayList<>();
list.add(1);
list.add(12.2);
// list.add("12");
System.out.println(list);
}
}
2 泛型的类
比较【不能泛型】和【泛型】的好处
2.1 不能泛型
package 第16个程序_泛型.a2_泛型的类.s1_比较.不可泛型;
public class Hero {
String name;
float hp; //血量
float armor; //护甲
int moveSprrd; //速度
public Hero(String name){
this.name = name;
}
}
package 第16个程序_泛型.a2_泛型的类.s1_比较.不可泛型;
// 物品
public class Item {
String name;
int price;
public Item(String name){
this.name = name;
}
}
package 第16个程序_泛型.a2_泛型的类.s1_比较.不可泛型;
import java.util.LinkedList;
public class HeroStack {
LinkedList<Hero> heros = new LinkedList<>();
//进栈
public void push(Hero hero){
heros.addLast(hero);
}
//出栈
public Hero pull(){
return heros.removeLast();
}
//获取栈顶元素
public Hero peek(){
return heros.getLast();
}
public static void main(String[] args) {
HeroStack stack = new HeroStack();
for (int i = 0;i < 10; i++){
Hero h = new Hero("hero " + i);
System.out.println("进栈: " + h.name);
stack.push(h);
}
System.out.println("\n出栈:");
for (int i = 0; i < 10; i++){
Hero h = stack.pull();
System.out.println(h.name);
}
}
}
package 第16个程序_泛型.a2_泛型的类.s1_比较.不可泛型;
import java.util.LinkedList;
public class ItemStack {
LinkedList<Item> items = new LinkedList<>();
public void push(Item item){
items.addLast(item);
}
//出栈
public Item pull(){
return items.removeLast();
}
//取栈顶元素
public Item peek(){
return items.getLast();
}
public static void main(String[] args) {
ItemStack stack = new ItemStack();
for (int i = 0;i < 10; i++){
Item item = new Item("item " + i);
System.out.println("进栈: " + item.name);
stack.push(item);
}
System.out.println("\n出栈:");
for (int i = 0; i < 10; i++){
Item item = stack.pull();
System.out.println(item.name);
}
}
}
2.2 可以泛型
package 第16个程序_泛型.a2_泛型的类.s1_比较.可以泛型;
public class Hero {
String name;
float hp; //血量
float armor; //护甲
int moveSprrd; //速度
public Hero(String name){
this.name = name;
}
public Hero() {
}
}
package 第16个程序_泛型.a2_泛型的类.s1_比较.可以泛型;
// 物品
public class Item {
String name;
int price;
public Item(String name){
this.name = name;
}
}
package 第16个程序_泛型.a2_泛型的类.s1_比较.可以泛型;
import java.util.LinkedList;
public class MyStack<T> {
LinkedList<T> list = new LinkedList<>();
int length = 0;
//进栈
public void push(T t){
list.addLast(t);
length++;
}
//出栈
public T pull(){
return list.removeLast();
}
//获取栈顶元素
public T peek(){
return list.getLast();
}
public static void main(String[] args) {
MyStack<Hero> heroMyStack = new MyStack<>();
System.out.println("进栈 heroMyStack :");
heroMyStack.push(new Hero("hero " + 1));
heroMyStack.push(new Hero("hero " + 2));
System.out.println("出栈 :");
for (int i = 0; i < heroMyStack.length; i++){
System.out.println(heroMyStack.pull().name);
}
MyStack<Item> itemMyStack = new MyStack<>();
System.out.println("\n进栈 itemMyStack :");
itemMyStack.push(new Item("item " + 1));
itemMyStack.push(new Item("item " + 2));
System.out.println("出栈:");
for (int i= 0; i < itemMyStack.length; i++){
System.out.println(itemMyStack.pull().name);
}
}
}
2.3 练习
二叉树的 Node 改成泛型
package 第16个程序_泛型.a2_泛型的类.练习_二叉树;
public class Hero {
String name;
float hp; //血量
float armor; //护甲
int moveSprrd; //速度
public Hero(String name){
this.name = name;
}
}
package 第16个程序_泛型.a2_泛型的类.练习_二叉树;
import 第15个程序_集合框架.a4_其他.s2_比较器.排序Comparable.Hero;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Node<T extends Comparable<T>> {
public Node<T> left;
public Node<T> right;
public T value;
//插入
public void add(T e){
if (value == null)
value = e;
else {
if (e.compareTo(value) <= 0){
if (left == null)left = new Node<>();
left.add(e);
} else{
if (right == null)right = new Node<>();
right.add(e);
}
}
}
public List<T> values(){
List<T> list = new ArrayList<>();
if (left != null){
list.addAll(left.values());
}
list.add(value);
if (right != null){
list.addAll(right.values());
}
return list;
}
public static void main(String[] args) {
Node<Integer> node = new Node<>();
node.add(1);
node.add(2);
node.add(3);
node.add(4);
System.out.println("输出 Node<Integer> node :");
System.out.println(node.values());
Random r = new Random();
Node<Hero> node1 = new Node<>();
for (int i = 0; i < 5; i++){
node1.add(new Hero("hero " + r.nextInt(100)));
}
System.out.println("\nNode<Hero> node1");
System.out.println(node1.values());
}
}
3 通配符
先总结:
只取 不插,用? extends Hero
只插 不取,用? super Hero
又能插入,又能取出,不要用通配符?
3.1 ? extends
ArrayList heroList<? extends Hero>
:这是 Hero 泛型或其子类泛型
heroList 的泛型可能是Hero
heroList 的泛型可能是APHero
heroList 的泛型可能是ADHero
从 heroList 取出的对象,一定可以转成 Hero 的
但不能往里面放东西
3.2 ? super
ArrayList heroList<? super Hero>
:这是 Hero 泛型或其父类泛型
heroList 的泛型可能是 Hero
heroList 的泛型可能是 Object
可以往里面插入 Hero 以 Hero 子类
但取元素有风险,因为不确定取出来是 Hero 还是 Object
3.3 泛型通配符 ?
? 代表任意泛型,这个容器什么泛型都有可能
只能以 Object 的取出来
不能往里放对象,因为不知道这是什么泛型的容器
3.4 练习1
如下代码所示,遍历不同泛型的 3 种集合,要设计 3 个方法
借助? extends
, 把代码减到只用 1 种方法
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 第16个程序_泛型.a3_通配符.练习;
import java.util.ArrayList;
import java.util.List;
public class test {
public static void iterate(List<? extends Hero> list){
System.out.println("遍历:");
for (Hero hero:list){
System.out.println(hero.name);
}
System.out.println();
}
public static void main(String[] args) {
ArrayList<Hero> hs = new ArrayList<>();
ArrayList<ADHero> adhs = new ArrayList<>();
ArrayList<APHero> aphs = new ArrayList<>();
hs.add(new Hero("hero 1"));
hs.add(new Hero("hero 2"));
adhs.add(new ADHero("adhero 1"));
adhs.add(new ADHero("adhero 2"));
aphs.add(new APHero("aphero 1"));
aphs.add(new APHero("aphero 2"));
iterate(hs);
iterate(adhs);
iterate(aphs);
}
}
3.5 练习2
二叉树改造成 支持泛型 <T extends Comparable>
比较时,用 compare 方法
package 第16个程序_泛型.a3_通配符.练习2;
public class Hero implements Comparable<Hero> {
String name;
float hp; //血量
float armor; //护甲
int moveSprrd; //速度
public Hero(String name){
this.name = name;
}
@Override
public int compareTo(Hero o) {
if(hp > o.hp)
return 1;
else
return -1;
}
}
package 第16个程序_泛型.a3_通配符.练习2;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Node<T extends Comparable<T>> {
public Node<T> left;
public Node<T> right;
public T value;
//插入
public void add(T e){
if (value == null)
value = e;
else {
if (e.compareTo(value) <= 0){
if (left == null)left = new Node<>();
left.add(e);
} else{
if (right == null)right = new Node<>();
right.add(e);
}
}
}
//中序遍历
public List<T> inOder(){
List<T> list = new ArrayList<>();
if (left != null){
list.addAll(left.inOder());
}
list.add(value);
if (right != null){
list.addAll(right.inOder());
}
return list;
}
public static void main(String[] args) {
Node<Integer> node = new Node<>();
node.add(1);
node.add(2);
node.add(3);
node.add(4);
System.out.println("输出 Node<Integer> node :");
System.out.println(node.inOder());
Random r = new Random();
Node<Hero> node1 = new Node<>();
for (int i = 0; i < 5; i++){
node1.add(new Hero("hero " + r.nextInt(100)));
}
System.out.println("\nNode<Hero> node1");
for (Hero hero: node1.inOder()){
System.out.println(hero.name);
}
}
}
4 泛型转型
4.1 对象转型 可行
子类转父类 = 父 = 子
= Hero h = new ADHero();
= 中国人 a = new 湖北人();
4.2 子类泛型 转 父类泛型 不可行
public static void main(String[] args) {
ArrayList<Hero> heros = new ArrayList<>();
ArrayList<ADHero> adHeroes = new ArrayList<>();
heros = adHeroes;
}
会报错!
假设转型成功
ArrayList<Hero> heros
可以放入 APHero
ArrayList<ADHero> adHeroes
又当成 ArrayList<Hero> heros
相当于 ArrayList<ADHero> adHeroes
中放入了 APHero,矛盾!
子类泛型 转 父类泛型 不可行
父类泛型 转 子类泛型 不可行(同样)