目录
1.泛型续
2.线性表初
一,泛型续
(1).泛型的擦除机制
概念:在编译时,Java编译器会将泛型类型信息从代码中移除,这个过程就叫做类型擦除。 擦除后,泛型类型会被替换为其边界类型(通常是Object)或者指定的类型。
擦除过程:将泛型参数替换为其边界或Object。在必要的地⽅插⼊类型转换以保持类型安全。 生成桥接方法以保持多态性。
擦除前:
class MyArray<T> {
public Object[] array = new Object[10];
public T getPos(int pos) {
return (T)this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] = val;
}
}
擦除后:
class MyArray {
public Object[] array = new Object[10];
public Object getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos, Object val) {
this.array[pos] = val;
}
}
关于桥接方法:泛型类型擦除可能导致⼦类⽅法和⽗类⽅法的签名不⼀致。 为了维护Java的多态性,需要桥接⽅法来确保⼦类⽅法能够正确覆盖⽗类⽅法。当你泛型类擦除后变成object类,但你方法使用的时候传入的是string类,虽然string继承了object,但是他们始终类型不同,所以编译器会自己生成一个桥接方法来强转实现方法的正常使用,保证多态性
(2).泛型的上界
用extends关键字来实现
// T 必须是 Number 的子类,并且实现 Comparable 接口
public class SortableNumberNode<T extends Number & Comparable<T>> {
T data;
public int compareTo(SortableNumberNode<T> other) {
return this.data.compareTo(other.data);
}
}
这里extends不是继承的意思,是来规定泛型数据的范围和实现特定的接口,比如要比较大小就可以实现Comparable接口,这个很常用,不写一般默认是object
(3).泛型方法
泛型方法的书写格式
// 声明泛型参数 <E> → 返回值类型 → 方法名(参数列表)
public <E> void 方法名(E 参数) {
// 方法体
}
用一个数组找最大值的方法来举例子
public class DataStructureUtils {
// 泛型方法:T 必须实现 Comparable 接口
public static <T extends Comparable<T>> T findMax(T[] array) {
if (array == null || array.length == 0) {
return null;
}
T max = array[0];
for (T element : array) {
if (element.compareTo(max) > 0) {
max = element;
}
}
return max;
}
}
// 使用
public class Test {
public static void main(String[] args) {
Integer[] nums = {3, 1, 4, 1, 5};
System.out.println(DataStructureUtils.findMax(nums)); // 输出 5
String[] strs = {"banana", "apple", "cherry"};
System.out.println(DataStructureUtils.findMax(strs)); // 输出 cherry
}
}
这不仅使用泛型来实现类型的多样,还是先比较接口来进行比较
(4).泛型通配符
和上面所讲的T类似但是不能用来定义变量,也就不能当成具体的某种类型来写,一般用?
注意:1.通配符 ?不能用来定义泛型类 / 接口 / 方法的「类型参数」
2.?只能用在「使用泛型的地方」,比如变量声明、方法参数
1.通配符的上界(?extends)
我用Food-Fruit-Apple,Banana和一个装特殊类型的Box来举例子
class Food{ }
class Fruit extends Food{}
class Apple extends Fruit{}
class Banana extends Fruit{}
class Box<T>{
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public class TestDemo {
public static void main(String[] args) {
Box<Apple> box=new Box<>();
box.setData(new Apple());
func(box);
Box<Banana> box2=new Box<>();
box2.setData(new Banana());
func(box2);
}
public static void func(Box<?extends Fruit>box){
box.setData(new Banana());//error
box.setData(new Apple());//error
System.out.println(box.getData());
}
}
因为通配符不能用来定义类,所以上面Box得用T来定义,下面func方法里面是参数类型所以可以来使用?,并且这个Box是Fruit或者Fruit的子类的一个特定的盒子,为什么不可以get但是可以set:因为这个box是很多个地方特定东西的盒子们,所以当你放入banana或者Apple的时候,是不一定能放在你对应要放入的盒子里的,除非你像main方法里面一样new一个特定的盒子,但是你拿东西肯定就只需要拿到Fruit或者Fruit的子类就行了,当你extends Fruit的时候,Box类里getdata里的T就会直接替换成Fruit,所以就可以拿了
2.通配符的下界(?super)
public static void func2(Box<?super Fruit>box){
box.setData(new Banana());
box.setData(new Apple());
System.out.println(box.getData());
Fruit fruit = box.getData();//error
}
public static void main(String[] args) {
Box<Fruit> plate1 = new Box<>();
plate1.setData(new Fruit());
func2(plate1);
Box<Food> plate2 = new Box<>();
plate2.setData(new Food());
func2(plate2);
}
用大白话来解释一下为什么这里就可以set,但是不能get,可以理解为extends是很多个装特定水果的小盒子,super是两个大盒子,一个是fruit一个是food,在extends里你放进水果不能保证你就一定放在了特定的盒子里,但是你拿的话都是水果,所以可以拿不能放,super时候你不确定你拿的是哪一个盒子,拿到food就错误了,但是你放各种水果的时候,不管你放在fruit里面还是food里面都是可以的,因为那种水果都是水果也都是食物
3.总结一下

二,初识线性表(ArrayList与顺序表)

这是一张Java 集合框架(Java Collections Framework)的核心继承关系图,它把 Java 里所有常用的「数据容器」的关系、分类和特点
数据结构说白了,就是数据的「组织 / 摆放方式」,包括两个层面:
- 物理上的 “摆放”:数据在内存里实际怎么存
- 逻辑上的 “摆放”:数据之间的关系怎么定(谁先谁后、谁和谁关联、有没有顺序)
(我们先从线性的摆放开始学起,也就是线性表)
(1)List初识
介绍:List就是⼀个线性表,即n个具有相同类型元素的有限序列,在该序列上可 以执行增删改查以及变量等操作。
方法:

1773



被折叠的 条评论
为什么被折叠?



