多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
>[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); ~~~