泛型: 参数化的类型, 即把数据类型当做参数来传递
有的地方又称为泛化的类型, 用一个单个大写字母, 例如 < T > 来代表任意类型, 这个 T 就是泛化的类型.
泛型的好处:
(1)表示某个变量的类型更灵活
(2)安全: 有了泛型, 在编译期间就可以避免不符合类型的数据赋值
(3)避免数据类型转换
泛型类或泛型接口
[修饰符] class 类名<类型变量列表 / 泛型类型形参列表>{
}
[修饰符] interface 接口名<类型变量列表 / 泛型类型形参列表>{
}
使用
(1)创建对象时
在创建类的对象时指定类型变量对应的实际类型参数, 指定泛型实参时, 必须左右两边一致, 不存在多态现象
(2)继承, 实现接口
在继承泛型类或实现泛型接口时, 指定类型变量对应的实际类型参数
注意
(1)<类型变量列表 / 泛型类型形参列表>: 使用单个的大写字母表示, 例如:<T>,<E>,<R>...
(2)<类型变量列表 / 泛型类型形参列表>: 可以多个, 每个之间使用, 分割, 例如:<K,V>
(3)如果要指定 <类型变量列表 / 泛型类型形参列表> 的实际类型, 必须是引用数据类型, 不能是基本数据类型
(4)类和接口上的类型形参不能用于静态方法中
(5)<类型变量列表 / 泛型类型形参列表>可能有上限,<T extends 上限 1>
类型变量的上限
当在声明类型变量时, 如果不希望这个类型变量代表任意引用数据类型, 而是某个系列的引用数据类型, 那么可以设定类型变量的上限.
<T extends 上限 1 & 上限 2 ...>
上限中类只能有一个, 如果有必须在最左边, 接口的话可以多个. 多个上限之间是 &(与)的关系.
如果在声明 <类型变量> 时没有指定任何上限, 默认上限是 java.lang.Object.
泛型擦除
当使用参数化类型的类或接口时, 如果没有指定泛型, 会发生泛型擦除, 泛型的类型就会自动按照最左边的第一个上限处理. 如果没有指定上限, 上限即为 Object.
泛型方法
如果我们定义类, 接口时没有使用 <类型变量>, 但是某个方法定义时或静态方法定义时, 想要自己定义<类型变量> 就可定义泛型方法
语法:
[修饰符] <类型变量列表 / 泛型类型形参列表> 返回值类型 方法名([数据形参列表] )[throws 异常列表]
使用:
方法被调用时, 根据方法的实参的类型自动推断.
注意:
泛型方法的定语与泛型类的定义注意点相同, 并且泛型方法可定义静态方法
每一个泛型方法的 <类型变量列表 / 泛型类型形参列表> 是独立的, 和别的方法无关, 和类上面的泛型也无关
类型通配符
当我们声明一个方法时, 某个形参的类型是一个参数化的泛型类或泛型接口类型(Map<K,V>), 但是在声明方法时, 又不确定该泛型实际类型, 我们可以考虑使用类型通配符.
形式:
(1)泛型类 / 接口名<?> ? 代表任意引用数据类型
(2)泛型类 / 接口名<? extends 上限> ? 代表的是该上限或上限的子类类型
(3)泛型类 / 接口名<? super 下限> ? 代表的是该下限或下限的父类类型
注意:
- <?>: 不可变, 因为 <?> 类型不确定, 编译时, 任意类型都是错
- <? extends 上限>: 不可变, 因为 <? extends 上限> 的? 可能是上限或上限的子类, 即类型不确定, 编译按任意类型处理都是错.
- <? super 下限>: 可以将值修改为下限或下限子类的对象, 因为<? super 下限>? 代表是下限或下限的父类, 那么设置为下限或下限子类的对象是安全的.
泛型的其他小问题
1,<>在左右两边 类型必须一致
2,JDK1.7 之后允许右边 <> 里面空着, 根据左边的自动推断
3,try...catch 的 catch 里面不能使用 T 这种来代表任意异常类型.
4, 泛型类不能创建数组对象
5, 泛型可用于可变形参列表(T... t)
数组算法升华
1, 数组的反转
方法一:
1, 借助一个新数组
2, 首尾对应位置交换
缺点: 需要借助一个数组, 浪费额外空间, 原数组需要垃圾回收
方法二:
数组对称位置的元素互换.
或
2, 数组的扩容
(1)先创建一个新数组, 可以扩容为原来的 1.5 倍, 2 倍等
(2)把旧数组的数据赋值到新数组中
(3)把新元素添加到 newArr 的最后
(4)如果下面继续使用 arr, 可以让 arr 指向新数组
数组扩容太多会造成浪费, 太少会导致频繁扩容, 效率低下
3, 数组元素的插入
(1)判断数组是否需要扩容
如果需要, 先扩容
(2)把 [index] 位置和它后面的元素往右移动
(3)在 [index] 位置放入新元素
4, 数组元素的删除
(1)把 [index+1] 位置和它后面的元素往左移动
(2)把当前数组的最后一个元素还原(0/null)
5, 数组的二分查找
二分查找: 对折对折再对折
要求: 要求数组元素必须支持比较大小, 并且数组中的元素已经按大小排好序
6, 数组的直接选择排序
- int[] arr = {....};
- // 轮数 = arr.length-1
- for(int i=0; i<arr.length-1; i++){
- //(1)找出本轮最小值
- int minIndex = i;
- for(int j=i+1; j<arr.length-1; j++){
- if(arr[minIndex]> arr[j]){
- minIndex = j;
- }
- }
- //(2)如果本轮最小值不在它应该在的位置
- if(minIndex != i){
- int temp = arr[minIndex];
- arr[minIndex] = arr[i];
- arr[i] = temp;
- }
- }
来源: https://www.cnblogs.com/Open-ing/p/11965940.html