>[success] # java 泛型 -- 广泛的参数类型
1. 以集合为例,可以存放不同类型的对象,是因为将所有对象都看做`Object`类型放入的,因此从集合中取出元素时也是`Object`类型,为了表达该元素真实的数据类型,则需要**强制类型转换**,而强制类型转换可能会引发类型**转换异常**
~~~
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// 1.创建一个list 集合
List ls = new ArrayList();
// add 向集合中添加元
ls.add("1"); // 末尾插入
ls.add(11111);
// 获取元素
Object str = ls.get(0); // 获取Object 类型
Integer i = (Integer) ls.get(1); // 强制类型转换获取 int 类型
System.out.println(str); // 1
System.out.println(i); // 11111
}
}
~~~
2. 从Java5开始增加**泛型机制**,也就是在集合名称的右侧使用的方式来明确要求该集合中**可以存放的元素类型**,若放入其它类型的元素则**编译报错**,Java7开始的新特性: 菱形特性 **就是后面<>中的数据类型可以省略**,实际上**泛型只在编译时期有效,在运行时期不区分是什么类型**
~~~
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// 1.创建一个list 集合
List<Integer> ls = new ArrayList<Integer>();
// List<Integer> ls = new ArrayList<>(); // 缩写 Java7开始的新特性: 菱形特性 就是后面<>中的数据类型可以省略
// add 向集合中添加元
// ls.add("1"); // 报错
ls.add(11111);
}
}
~~~
3. 不能将不同泛型 互相赋值
~~~
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// 1.创建一个list 集合
List<Integer> ls = new ArrayList<Integer>();
List<String> ls1 = new ArrayList<>();
// ls1 = ls; // Type mismatch: cannot convert from List<Integer> to List<String>Java(16777233)
}
}
~~~
4. 以集合为例 没特意指定泛型其实默认泛型为`Object`
![](https://img.kancloud.cn/69/0a/690a9c7dc2ee51b755550f3d541281e5_655x147.png)
![](https://img.kancloud.cn/25/9e/259ea27d43a4802d0363a8d124de48b9_687x172.png)
>[danger] ##### 泛型的本质
1. 泛型的本质就是**参数化类型**,让**数据类型作为参数传递**,声明泛型时候规定占位符相当于形参,实际使用时候传入泛型类型相当于实参,使得实际参数可以传递各种各样广泛的数据类型,因此得名为泛型
* 以List 为例 E 其实就是泛型的形参,类型完全取决于使用时候传入的实参决定的
~~~
public interface List<E> extends Collection<E>
List<String> ls = new ArrayList<>();
~~~
>[info] ## 泛型接口
1. 泛型接口和普通接口的区别就是后面添加了**类型参数列表**,可以有多个类型参数,如:`<E, T, .. >`
~~~
public interface List<E> extends Collection<E>
~~~
>[info] ## 自定义泛型类
1.泛型类和普通类的区别就是类名后面添加了**类型参数列表**,可以有多个类型参数,:`<E, T, .. >`
2. 实例化泛型类时应该指定具体的数据类型(没有指定则默认为Object),并且是**引用数据类型**而不是基本数据类型
* 默认泛型
![](https://img.kancloud.cn/85/2d/852dbca3630ac94558e2429d34eed32f_1019x121.png)
![](https://img.kancloud.cn/e9/0b/e90beb2d59f32d78baf0845de43573d3_710x136.png)
* 指定泛型
![](https://img.kancloud.cn/75/1b/751b74b5bb139d6fcc04481268108d27_821x162.png)
~~~
public class PersonTest<T> {
private int age;
private String name;
private T gender;
public PersonTest() {
}
public PersonTest(int age, String name, T gender) {
this.age = age;
this.name = name;
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getGender() {
return gender;
}
public void setGender(T gender) {
this.gender = gender;
}
@Override
public String toString() {
return "PersonTest [age=" + age + ", name=" + name + ", gender=" + gender + "]";
}
public static void main(String[] args) {
// 声明使用
PersonTest per = new PersonTest(1, "w", '男');
per.setGender('女');
System.out.println(per); // PersonTest [age=1, name=w, gender=女]
// 指定泛型类型
PersonTest<Integer> per1 = new PersonTest<>(1, "w", 0);
per1.setGender(null); // 可以赋值null
per1.setGender(1);
System.out.println(per1); // PersonTest [age=1, name=w, gender=1]
}
}
~~~
3. 父类有泛型,子类可以选择**保留泛型**也**可以选择指定泛型类型**,子类除了指定或保留父类的泛型,还可以增加自己的泛型
~~~
//public class SubPerson extends PersonTest { // 不保留泛型并且没有指定类型,此时Person类中的T默认为Object类型 擦除
//public class SubPerson extends PersonTest<String> { // 不保留泛型但指定了泛型的类型,此时Person类中的T被指定为String类型
// public class SubPerson<T> extends PersonTest<T> { // 保留父类的泛型 可以在构造对象时来指定T的类型
public class SubPerson<T, T1> extends PersonTest<T> { // 保留父类的泛型,同时在子类中增加新的泛型
T1 z;
public static void main(String[] args) {
// 第一种默认是Object 泛型
// SubPerson sp1 = new SubPerson();
// sp1.setGender("女");
// 第二种默认是String 泛型
// SubPerson sp2 = new SubPerson();
// sp1.setGender("女");
// 第三种 可以指定类型依次从子=》父
// SubPerson<String> sp3 = new SubPerson<String>();
// sp1.setGender("女");
// 第四种 指定了父子 类型
SubPerson<String, Boolean> sp4 = new SubPerson<>();
sp4.setGender("女");
}
}
~~~
>[info] ## 自定义泛型方法
1. 泛型方法就是我们输入参数的时候,输入的是泛型参数,而不是具体的参数。我们在调用这个泛型方法的时需要对泛型参数进行实例化
2. 泛型方法的格式:`[访问权限] <泛型> 返回值类型 方法名([泛型标识 参数名称]) { 方法体; }`
~~~
public class PersonTest<T> {
private T name;
// 不属于泛型方法
public T getName() {
return name;
}
// 不属于泛型方法
public void setName(T name) {
this.name = name;
}
// 定义一个泛型方法,打印任意类型数组中每一个值
public <E> void getArrayItem(E[] arr) {
for (E item : arr) {
System.out.println(item);
}
}
// 定义一个泛型方法,返回原数组
public <E> E[] getArray(E[] arr) {
return arr;
}
// 定义一个静态泛型方法
public static <E> E[] getSArray(E[] arr) {
return arr;
}
public static void main(String[] args) {
PersonTest<String> pt = new PersonTest<>();
Integer[] arr = { 1, 2, 3, 4, 5, 6 };
// int[] arr = { 1, 2, 3, 4, 5, 6 }; // 泛型不能是基本类型 否则报错
Integer[] getLs = pt.getArray(arr);
pt.getArrayItem(arr);
PersonTest.getSArray(arr);
}
}
~~~
>[info] ## 通配符的使用
1. `<?>` 无限制通配符:表示我们可以传入任意类型的参数,但任意类型集合是不能进行添加操作,任意类型可以接受其他泛型集合,可进行获取操作(获取是Object)
~~~
// 1.声明两个List类型的集合进行测试
List<Animal> lt1 = new LinkedList<>();
List<Dog> lt2 = new LinkedList<>();
// 试图将lt2的数值赋值给lt1,也就是发生List<Dog>类型向List<Animal>类型的转换
//lt1 = lt2; Error: 类型之间不具备父子类关系
System.out.println("---------------------------------------------");
// 2.使用通配符作为泛型类型的公共父类
List<?> lt3 = new LinkedList<>();
lt3 = lt1; // 可以发生List<Animal>类型到List<?>类型的转换
lt3 = lt2; // 可以发生List<Dog>类型到List<?>类型的转换
// 向公共父类中添加元素和获取元素
//lt3.add(new Animal()); Error: 不能存放Animal类型的对象
//lt3.add(new Dog()); Error: 不能存放Dog类型的对象, 不支持元素的添加操作
Object o = lt3.get(0); // ok,支持元素的获取操作,全部当做Object类型来处理
~~~
2. `<? extends E>` 表示类型的上界是E,只能是E或者是E的子类,集合类型不支持元素的添加操作,可进行获取操作(获取是E类型)
~~~
// 3.使用有限制的通配符进行使用
List<? extends Animal> lt4 = new LinkedList<>();
// 不支持元素的添加操作
//lt4.add(new Animal());
//lt4.add(new Dog());
//lt4.add(new Object());
// 获取元素
Animal animal = lt4.get(0);
~~~
3. `<? super E>` 表示类型的下界是E,只能是E或者是E的父类。(获取是Object)
~~~
List<? super Animal> lt5 = new LinkedList<>();
lt5.add(new Animal());
lt5.add(new Dog());
//lt5.add(new Object()); Error: 超过了Animal类型的范围
Object object = lt5.get(0);
~~~
- windows -- 环境变量
- Vscode -- 编写java
- 初始java
- java -- 关键字
- 编写第一个java程序
- java -- 注释
- 计算机存储 -- 进制
- java -- 类型
- java -- 变量
- 数字类型
- 布尔类型
- 字符类型
- 类型转换
- 双等比较是什么
- java -- 运算符
- 算数运算符
- 字符串拼接
- 关系/比较运算符
- 自增减运算符
- 逻辑运算符
- 三目运算
- 赋值运算符
- 移位运算符
- 位运算符
- 运算符优先级
- java -- 流程控制语句
- if /else if /if -- 判断
- switch case分支结构
- for -- 循环
- 用双重for循环
- while -- 循环
- do while -- 循环
- 案例练习
- java -- 数组
- 数组的存储
- 数组的增删改查
- 数组的特点
- 数组案例
- 二维数组
- 数组的工具方法
- java -- 方法
- java -- 方法的重载
- java -- 方法的调用流程
- java -- 类方法传参注意事项
- java -- 方法练习案例
- 对比 return break continue
- for each循环
- java -- 基础练习
- java -- 面向对象
- java -- 创建类和对象
- java -- 访问控制符
- java -- 类成员方法
- java -- 构造方法
- java -- this
- java -- 封装
- java -- 对象内存图
- java -- 创建对象案例
- java -- static
- java -- 继承
- super -- 关键字
- java -- 构造块和静态代码块
- java -- 重写
- java -- final
- java -- 多态
- java -- 抽象类
- java -- 接口
- 引用类型数据转换
- 综合案例
- java -- 内部类
- java -- 回调模式
- java -- 枚举类型
- java -- switch 使用枚举
- java -- 枚举方法使用
- java -- 枚举类实现接口
- java -- javaBean
- java -- package 包
- java -- import
- java -- 递归练习
- java -- 设计模式
- 单例模式
- java -- 注解
- java -- 元注解
- Java -- 核心类库
- java -- 处理字符串
- Java -- String
- String -- 常用方法
- String -- 正则
- Java -- StringBuilder 和 StringBuffer
- 知识点
- Java -- StringJoiner 字符串拼接
- 练习题
- 字符串的总结
- Java -- 包装类
- Integer
- Double
- Boolean
- Character
- java -- 集合类
- java -- util.Collection
- Iterator接口
- java -- util.List
- java -- ArrayList
- java -- util.Queue
- java -- util.Set
- java -- util.Map
- java -- util.Collections
- Java -- Math
- Java -- java.lang
- Java -- Object
- Java -- 获取当前时间戳
- Java -- 异常
- Java -- java.util
- java -- Date
- java -- Calender
- Java -- java.text
- Java -- SimpleDateFormat
- Java -- java.time
- Java -- java.io
- java -- io.File
- java -- 泛型
- IDEA -- 用法