免费书画网站怎么做的,设计网站推荐外网,成都网站设计网站制作公司,迅捷在线图片编辑文章目录 泛型一、概述二、泛型的使用1、类2、方法3、接口 三、泛型通配符1、?2、? extends T3、? super T 四、泛型的擦除1、泛型的擦除2、泛型边界的擦除3、无法实例化泛型类型 泛型
一、概述
泛型#xff08;Generic#xff09;是一种机制?2、? extends T3、? super T 四、泛型的擦除1、泛型的擦除2、泛型边界的擦除3、无法实例化泛型类型 泛型
一、概述
泛型Generic是一种机制允许你编写与数据类型无关的代码增加代码的灵活性和可重用性。
泛型在定义的时候不具体使用的时候才变得具体。在使用的时候确定泛型的具体数据类型。
泛型的作用
安全性编译时检查类型将运行时期的ClassCastException转移到编译时期的编译失败。灵活性使类型参数化可以预先地使用未知的类型让设计的代码更通用灵活。重用性一个泛型类或方法可以处理多种数据类型减少代码重复。维护性泛型代码通常更清晰容易理解和维护。
注意事项
泛型只能在编译阶段起作用到了运行阶段就会被擦除。泛型只能是引用数据类型不能是 基本数据类型。泛型在使用时指定实际的类型如果不指定默认为Object类型。
二、泛型的使用
1、类
定义类名之后
// 泛型一般用大写的单个字母表示可以定义多个泛型使用逗号分隔。
修饰符 class 类名A, B, C {}使用在类中使用可以作为 实例方法 的 参数 和 返回值静态方法不支持
class ExampleT {// 作为实例方法的参数类型public void show(T t) {System.out.println(t);}// 作为实例方法的返回值类型public T get(int index) {return null;}// 静态方法 不能使用 类上定义的泛型// public static void test1(T t) {...}// public static T test2(int index) {...}
}指定类型创建对象时
public class Test {public static void main(String[] args) {// 在创建对象时根据需要指定泛型的类型DataShowString ds new DataShow();ds.show(Hello); }
}2、方法
定义返回值之前
修饰符 T 返回值类型 方法名(T t) {}使用在方法内部使用
class Example {public static T void show(T t) {// 在方法内部使用System.out.println(t t);}// 不同方法的泛型名称可以一致public static T void show2(T t) {}
}指定类型调用方法时根据传参的类型
public class Test {public static void main(String[] args) {show(100); // T - Integershow(Hello); // T - String}
}3、接口
定义接口名之后
public interface 接口名E {}使用作为 接口方法 的 参数 或 返回值
public interface ExampleT {void method1(T t);T method2();
}指定类型
1、定义接口的实现类时确定泛型的类型
public class ExampleChild1 implements ExampleString{Overridepublic void method1(String s) {System.out.println(s);}Overridepublic String method2() {return null;}
}2、定义接口的实现类时继续沿用泛型
public class ExampleChild2T implements ExampleT {Overridepublic void method1(T t) {System.out.println(t);}Overridepublic T method2() {return null;}
}在创建接口的实现类对象时确定泛型的类型
public class Test {public static void main(String[] args) {ExampleChild2String exampleChild2 new ExampleChild2();exampleChild2.method1(hello);String str exampleChild2.method2();}
}三、泛型通配符 泛型通配符? 常用于泛型方法和类中帮助实现更加灵活和通用的类型操作。 1、?
?表示任意类型适用于我们不关心具体类型的场景。只能使用Object类中的共性方法
public void printList(List? list) {for (Object obj : list) {System.out.println(obj);}
}使用举例
public class Test {public static void main(String[] args) {ListInteger integerList new ArrayList();integerList.add(1);integerList.add(2);// 使用泛型方法printList(integerList);}public static void printList(List? list) {for (Object obj : list) {System.out.println(obj);}}
}2、? extends T
? extends T表示 T 或 T 的子类型适用于读取操作。可以使用父类T 中的公共方法
public void processNumbers(List? extends Number numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a 1L; // Long extends Numbernumbers.add(a); // errorJava 的泛型系统为了类型安全不允许向这样的列表中添加特定类型的元素除 null 外。
}public T extends Number void processNumbers(ListT numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a 1L; // Long extends Numbernumbers.add(a); // error
}使用举例
public class Test {public static void main(String[] args) {ListInteger integerList new ArrayList();integerList.add(1);integerList.add(2);// 使用泛型方法printNumbers(integerList);}public static T extends Number void printNumbers(ListT list) {for (T number : list) {System.out.println(number);}}
}3、? super T
? super T表示 T 或 T 的父类型适用于写入操作。
public void addNumbers(List? super Integer list) {list.add(1); // 可以安全地添加 Integer 类型的元素list.add(2); // 也可以添加其他 Integer 类型的元素
}// 编译错误! super 只能用在 泛型方法 或 类中的方法参数 中来指定一个类型范围。
public T super Integer void addNumbers(ListT list) {...}使用举例
public class Test {public static void main(String[] args) {ListNumber numbers new ArrayList();// 使用泛型方法addNumbers(numbers);System.out.println(numbers);}public static void addNumbers(List? super Integer list) {list.add(1); // 可以添加 Integer 类型的对象list.add(2); // 可以添加 Integer 类型的对象}
}四、泛型的擦除
泛型的擦除是指在编译期间Java 编译器会将泛型信息擦除掉泛型类型参数会被替换为其限定类型。
默认情况下泛型类型参数会被替换为 Object如果泛型有上限如 T extends Number擦除后会使用上限类型Number。
例如
ListString 和 ListInteger 在编译后都会被擦除为 List。ListT extends Number 会擦除为 ListNumber。
泛型擦除的主要目的是为了 兼容 Java 的早期版本 和 简化虚拟机的实现。
泛型擦除将泛型类型转换为 Object 或其超类从而使得 泛型代码 可以与 旧版本的 Java 代码 相互操作。泛型擦除意味着 泛型的具体类型T在字节码中不可见保持向后兼容性的同时避免对字节码格式进行重大修改。
但是这也会导致一些泛型相关的信息在运行时不可用需要在编写泛型代码时注意擦除造成的影响。
1、泛型的擦除
public class GenericMethodExample {// 泛型方法 在擦除后会变成 print(Object data) public T void print(T data) {System.out.println(data);}// 原始类型的方法 - 编译错误因为与擦除后的泛型方法冲突了public void print(Object data) {System.out.println(data);}
}public class GenericMethodExample {// 泛型方法 在擦除后会变成 print(Object data) public T void print(T data) {System.out.println(data);}// 原始类型的方法 - 编译通过因为泛型默认擦除为 Object这里是 String重载public void print(String data) {System.out.println(data);}
}2、泛型边界的擦除
public void processNumbers(List? extends Number numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a 1L; // Long extends Numbernumbers.add(a); // error
}ListT extends Number 在编译后会被擦除为 ListNumber。
public T extends Number void processNumbers(ListT numbers) {for (Number number : numbers) {System.out.println(number.intValue());}Long a 1L; // Long extends Numbernumbers.add(a); // error
}泛型参数 T 在运行时被擦除为 Number 类型。
3、无法实例化泛型类型
public class GenericInstantiationExampleT {private T instance;public GenericInstantiationExample() {// 编译错误无法直接实例化泛型类型// instance new T(); // 错误}public GenericInstantiationExample(ClassT clazz) {try {instance clazz.getDeclaredConstructor().newInstance();} catch (Exception e) {e.printStackTrace();}}
}new T() 在编译时会引发错误因为 T 的实际类型在运行时未知。可以使用反射通过传递 ClassT 对象来实例化对象。