30-泛型
package generics; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class GenericsDemo1 { public static void main(String[] args){ // 创建对象 // 不写泛型,默认为Object类型,可以存储任意类型的数据 // 格式:集合类 对象名 = new 集合类(); ArrayList list1 = new ArrayList(); list1.add("abc"); list1.add(1); list1.add(true); System.out.println(list1); // 迭代器不适用泛型 System.out.println("=================迭代器遍历(不使用泛型)=================="); Iterator it1 = list1.iterator(); while(it1.hasNext()){ // 取出的元素是Object类型 Object obj = it1.next(); System.out.println(obj); } // 泛型只能是引用类型,不能是基本类型 // 格式:集合类<泛型> 对象名 = new 集合类<泛型>(); ArrayList<String> list2 = new ArrayList<String>(); list2.add("张三"); list2.add("李四"); list2.add("王五"); System.out.println(list2); // 迭代器使用泛型 System.out.println("=================迭代器遍历(使用泛型)=================="); Iterator<String> it2 = list2.iterator(); while(it2.hasNext()){ // 取出的元素是String类型 String s = it2.next(); System.out.println(s); } } }
泛型类
常见的泛型标识符:E、T、K、V
1)E:Element 元素
2)T:Type 类型
3)K:Key 键
4)V:Value 值
package generics; /* * 常见的泛型标识符:E、T、K、V * E:Element 元素 * T:Type 类型 * K:Key 键 * V:Value 值 * * 清楚不同的泛型,在什么时机确定到具体的类型 * * 泛型类的使用场景,创建对象的时候 * * */ public class GenericsDemo2 { public static void main(String[] args){ Student<String> stu = new Student<>("张三", "23"); System.out.println(stu.getName() + "," + stu.getAge()); } } class Student<E>{ private E name; private E age; public E getName() { return name; } public void setName(E name) { this.name = name; } public E getAge() { return age; } public void setAge(E age) { this.age = age; } public Student(E name, E age){ this.name = name; this.age = age; } }
泛型方法
1)非静态方法:内部的泛型,会根据类的泛型去匹配
2)静态方法:静态方法中,如果加入了泛型,必须声明出自己独立的泛型
package generics; /* * 泛型方法: * 1. 非静态的方法:内部的逻辑,会根据类的泛型去匹配 * 2. 静态的方法:静态方法中,如果加入了泛型,必须声明出自己独立的泛型 * * */ public class GenericsDemo3 { public static void main(String[] args){ // 创建工具类对象 Tool<String> tool = new Tool<>(); // 非静态的方法:内部的逻辑,会根据类的泛型去匹配 tool.show("马铃薯"); // 静态的方法:静态方法中,如果加入了泛型,必须声明出自己独立的泛型 String[] s = new String[]{"马铃薯", "土豆", "洋芋"}; tool.print(s); // 这里注意,静态方法也可以直接用类名调用,不需要创建对象 Tool.print(s); } } class Tool<T>{ // 非静态的方法:内部的逻辑,会根据类的泛型去匹配 public void show(T t){ System.out.println(t); } // 静态方法:不会根据类的泛型去匹配,要自己声明泛型 // 这是因为静态方法是通过类名调用的,不需要创建对象去调用方法,因此必须声明出自己独立的泛型 public static <T> void print(String[] t){ System.out.print("["); for(int i = 0; i < t.length; i++){ if(i == t.length - 1){ System.out.println(t[i] + "]"); }else{ System.out.print(t[i] + ", "); } } } }
这里需要注意:泛型是对引用数据类型来讲的,因此上面的案例如果使用整型、浮点数要使用 Integer[]、Double[]
String[] s = new String[]{"马铃薯", "土豆", "洋芋"}; Integer[] i = new Integer[]{1, 2, 3}; Double[] d = new Double[]{1.1, 2.2, 3.3};
泛型接口
1)实现类实现接口的时候,可以指定泛型的类型
2)实现类实现接口的时候,如果没有指定泛型的类型,那么就让接口的泛型跟着类的泛型匹配
package generics; /* * 泛型接口: * 1. 实现类实现接口的时候,可以指定泛型的类型 * 2. 实现类实现接口的时候,如果没有指定泛型的类型,那么就让接口的泛型跟着类的泛型匹配 * * */ public class GenericDemo4 { public static void main(String[] args){ // 创建工具类对象 InterAImpl inter1 = new InterAImpl(); inter1.show("马铃薯"); InterBImpl<String> inter2 = new InterBImpl<>(); inter2.show("马铃薯"); } } interface Inter<E>{ void show(E e); } // 实现类实现接口的时候,可以指定泛型的类型 class InterAImpl implements Inter<String>{ @Override public void show(String s) { System.out.println(s); } } // 实现类实现接口的时候,如果没有指定泛型的类型,那么就让接口的泛型跟着类的泛型匹配 class InterBImpl<E> implements Inter<E>{ @Override public void show(E e) { System.out.println(e); } }
泛型通配符
1)? :代表任意的数据类型
2)? extends E:向下限定,E及其子类
3)? super E:向上限定,E及其父类
package generics; import java.util.ArrayList; public class GenericsDemo5 { public static void main(String[] args){ /* * 泛型通配符 * ? :代表任意的数据类型 * ? extends E:向下限定,E及其子类 * ? super E:向上限定,E及其父类 * * */ ArrayList<Coder> list1 = new ArrayList<>(); list1.add(new Coder("张三", 10000)); // 输出时,默认调用Objec类toString()方法 System.out.println(list1); // [Coder{name=张三, salary=10000.0}] ArrayList<Manager> list2 = new ArrayList<>(); list2.add(new Manager("李四", 20000)); // [Manager{name=李四, salary=20000.0}] System.out.println(list2); // ? :代表任意的数据类型 method1(list1); // ? extends Employee:向下限定,Employee及其子类 method2(list1); // ? super Coder:向上限定,Coder及其父类 method3(list1); } // 泛型通配符 // ?:代表任意的数据类型 public static void method1(ArrayList<?> list){ for(Object o:list){ // 这里注意,o对象不能明确是什么类型,所以不能调用子类特有的方法 // 因此通过向下转型,将o对象转换为Employee类型 Employee e = (Employee)o; e.work(); } } // ? extends E:向下限定,E及其子类 public static void method2(ArrayList<? extends Employee> list){ for(Object o:list){ Employee e = (Employee)o; e.work(); } } // ? super E:向上限定,E及其父类 public static void method3(ArrayList<? super Coder> list){ for(Object o:list){ // 这里注意,o对象不能明确是什么类型,所以不能调用子类特有的方法 // 因此通过向下转型,将o对象转换为Employee类型 Coder e = (Coder)o; e.work(); } } } abstract class Employee{ private String name; private double salary; public Employee(){ // System.out.println("父类Employee()的无参构造方法"); } public Employee(String name, double salary){ this.name = name; this.salary = salary; // System.out.println("父类Employee()的有参构造方法"); } // 抽象方法 public abstract void work(); public String getName() { return name; } public void setName(String name) { this.name = name; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public String toString(){ return "Employee{name=" + name + ", salary=" + salary + "}"; } } class Coder extends Employee{ public Coder(){ // System.out.println("子类Coder()的无参构造方法"); } public Coder(String name, double salary){ super(name, salary); // System.out.println("子类Coder()的有参构造方法"); } @Override public String toString(){ return "Coder{name=" + getName() + ", salary=" + getSalary() + "}"; } public void work(){ System.out.println("程序员敲代码..."); } } class Manager extends Employee{ public Manager(){ // System.out.println("子类Manager()的无参构造方法"); } public Manager(String name, double salary){ super(name, salary); // System.out.println("子类Manager()的有参构造方法"); } @Override public String toString(){ return "Manager{name=" + getName() + ", salary=" + getSalary() + "}"; } public void work(){ System.out.println("项目经理分配任务..."); } }