tags
date
type
status
slug
category
summary
password
icon
泛型程序设计
初识泛型
泛型类
- 在定义一个变量不明确用什么类型时会使用泛型类型,它会在程序编译的时候才使用
- 不能用在静态类中,同时不能直接创建对象和数组,不支持基本类型,只支持引用类型
- 要存放基本数据类型的值,得使用对应的包装类
- 使用泛型类时,实例化时需要传递具体的类型参数。
- 类型参数在编译时会被替换为具体的类型。
权限修饰符 类名<T>{ },对于要使用到T类型的变量都在前面加个T
public class Main { public static void main(String[] args) { System.out.println("Hello world!"); Person<String,Integer,String,Integer> person=new Person<>(); person.setAge(20); person.setName("John"); person.setGender("Male"); person.setHeight(180); System.out.println(person.getAge()+" "+person.getName()+" "+person.getGender()+" "+person.getHeight()); } public static class Person<T,A,B,C>{ private T name; private A age; private B gender; private C height; public A getAge() { return age; } public void setAge(A age) { this.age = age; } public C getHeight() { return height; } public void setHeight(C height) { this.height = height; } public B getGender() { return gender; } public void setGender(B gender) { this.gender = gender; } public T getName() { return name; } public void setName(T name) { this.name = name; } }}
泛型方法
权限修饰符 <T> 返回值类型 方法名(T 参数名){ 方法体}
public class GenericMethodExample { // 泛型方法 public static <T> void printArray(T[] array) { for (T element : array) { System.out.println(element); } } public static void main(String[] args) { Integer[] intArray = {1, 2, 3}; String[] strArray = {"Hello", "World"}; // 调用泛型方法 printArray(intArray); printArray(strArray); }}
- s
泛型与多态
- 泛型接口
interface InterfaceName<T> { void method(T parameter);}
interface Storage<T> { void add(T item); T get(int index);}class StringStorage implements Storage<String> { private String[] items = new String[10]; private int count = 0; @Override public void add(String item) { items[count++] = item; } @Override public String get(int index) { return items[index]; }}
泛型通配符
- 无界通配符
?
—— 表示任何类型,适用于方法参数中使用。 public void method(List<?> list) { // 可以接受任何类型的 List}
- 上界通配符
? extends T
—— 表示泛型类型必须是T
或T
的子类。 public void method(List<? extends Number> list) { // 只允许 Number 及其子类的列表}
- 读取为主:可以安全地读取列表中的元素(例如
Number
类型的元素),但你不能向列表中添加元素,因为编译器无法确定具体类型。
- 下界通配符
? super T
—— 表示泛型类型必须是T
或T
的父类。 public void method(List<? super Integer> list) { // 可以处理 Integer 及其父类(如 Number、Object)}
- 写入为主:你可以向列表中添加
Integer
或其子类的值,但读取时,编译器只能保证返回的是Object
类型,因为列表可能包含比Integer
更高层次的父类。
泛型类型边界
class ClassName<T extends ClassOrInterface> { // T 必须是 ClassOrInterface 或其子类}
class NumberBox<T extends Number> { private T number; public NumberBox(T number) { this.number = number; } public T getNumber() { return number; } public static void main(String[] args) { NumberBox<Integer> intBox = new NumberBox<>(123); NumberBox<Double> doubleBox = new NumberBox<>(45.67); System.out.println("Integer: " + intBox.getNumber()); System.out.println("Double: " + doubleBox.getNumber()); }}
- 这里的
T extends Number
表示泛型类型T
必须是Number
或其子类(如Integer
、Double
泛型类与继承
- 泛型类可以继承其他泛型类或普通类,并且子类可以指定自己的泛型参数,也可以直接使用父类的泛型参数。
// 定义一个泛型类 Parent,具有泛型参数 Tclass Parent<T> { private T data; public Parent(T data) { this.data = data; } public T getData() { return data; }}// 子类 Child 继承父类 Parent,继续使用泛型 Tclass Child<T> extends Parent<T> { public Child(T data) { super(data); }}public class Main { public static void main(String[] args) { Child<String> child = new Child<>("Hello"); System.out.println(child.getData()); // 输出: Hello }}// 子类 Child 指定 Parent 泛型类型为 Integerclass Child extends Parent<Integer> { public Child(Integer data) { super(data); }}public class Main { public static void main(String[] args) { Child child = new Child(42); // 子类的泛型类型已固定为 Integer System.out.println(child.getData()); // 输出: 42 }}
类型擦除
- 在 Java 泛型中,类型擦除是一个重要的概念。泛型类型信息只在编译时存在,运行时所有的泛型类型信息都会被擦除,替换为原始类型(如
Object
)
- 实际上泛型知识在编译的阶段进行类型检查,程序运行的时候是不会保留泛型的具体类型信息
- 在某一些情况下需要通过强制类型转换或生成桥接方法来保证类型的正确性(所以实际上编译器是帮我们写了个桥接方法支持重写的)
- 局限性是,不能运行时判断类型或创建泛型数组
函数式接口
Supplier<T>
供给型函数式接口Supplier
是供给型接口,表示该接口的实现是一个生产者,它会返回一个结果,而不会接受任何参数。Supplier<T>
接口的抽象方法是get()
,它返回一个T
类型的对象public class Student { public void hello() { System.out.println("Hello!"); }}// 使用 Supplier 生成 Student 对象private static final Supplier<Student> STUDENT_SUPPLIER = Student::new;public static void main(String[] args) { Student student = STUDENT_SUPPLIER.get(); // 通过 Supplier 获取 Student 对象 student.hello(); // 输出: 我是学生!}
Supplier<Student>
是一个函数式接口,其get()
方法会返回一个Student
对象。Student::new
是方法引用,表示通过Student
类的构造方法生成对象。
Consumer<T>
消费型函数式接口- 它接受一个参数,但没有返回值。通常用于执行某个操作而不需要返回结果。
Consumer<T>
接口的抽象方法是accept(T t)
private static final Consumer<Student> STUDENT_CONSUMER = student -> System.out.println(student + " 被消费了!");public static void main(String[] args) { Student student = new Student(); STUDENT_CONSUMER.accept(student); // 输出: Student@hashcode 被消费了!}
Consumer<Student>
表示接受一个Student
对象并对其进行消费(处理),但没有返回值。- Lambda 表达式
student -> System.out.println(...)
表示对Student
对象进行输出操作。
andThen
方法:
andThen
方法允许将多个 Consumer
串联在一起连续执行。Function<T, R>
函数型函数式接口Function<T, R>
是一个通用的转换接口,它接受一个参数并返回另一个类型的结果。通常用于数据的转换、处理等操作。Function<T, R>
接口的抽象方法是apply(T t)
,它接受类型T
的参数并返回类型R
的结果。@FunctionalInterfacepublic interface Function<T, R> { R apply(T t); // 接收一个参数并返回结果}private static final Function<Integer, String> INTEGER_TO_STRING = Object::toString;public static void main(String[] args) { String result = INTEGER_TO_STRING.apply(10); // 将 Integer 转为 String System.out.println(result); // 输出: 10}
- 解释:
Function<Integer, String>
表示该函数接受一个Integer
类型的参数,并返回一个String
类型的结果。Object::toString
是方法引用,用于将整数转换为字符串。compose
和andThen
方法:compose(Function before)
:在当前函数之前执行一个函数。andThen(Function after)
:在当前函数之后执行另一个函数。// compose: 将字符串的长度作为 Integer 传入下一个函数String result = INTEGER_TO_STRING.compose(String::length).apply("Hello"); // 输出: "5"// andThen: 判断转换后的字符串是否为空Boolean isEmpty = INTEGER_TO_STRING.andThen(String::isEmpty).apply(10); // 输出: false
Predicate<T>
断言型函数式接口Predicate<T>
是一个用于进行条件判断的函数式接口,它接受一个参数并返回一个boolean
值。通常用于过滤和判断操作。Predicate<T>
接口的抽象方法是test(T t)
,它根据传入的参数返回true
或false
。Function<T, R> 接口定义: @FunctionalInterfacepublic interface Function<T, R> { R apply(T t); // 接收一个参数并返回结果}示例:使用 Function<T, R> 进行类型转换 private static final Function<Integer, String> INTEGER_TO_STRING = Object::toString;public static void main(String[] args) { String result = INTEGER_TO_STRING.apply(10); // 将 Integer 转为 String System.out.println(result); // 输出: 10}
- 解释:
Function<Integer, String>
表示该函数接受一个Integer
类型的参数,并返回一个String
类型的结果。Object::toString
是方法引用,用于将整数转换为字符串。compose(Function before)
:在当前函数之前执行一个函数。andThen(Function after)
:在当前函数之后执行另一个函数。// compose: 将字符串的长度作为 Integer 传入下一个函数String result = INTEGER_TO_STRING.compose(String::length).apply("Hello"); // 输出: "5"// andThen: 判断转换后的字符串是否为空Boolean isEmpty = INTEGER_TO_STRING.andThen(String::isEmpty).apply(10); // 输出: false
compose
和 andThen
方法:
- 总结
Supplier<T>
:供给型接口,用于提供数据。Consumer<T>
:消费型接口,用于处理和消费数据。Function<T, R>
:函数型接口,用于数据转换。Predicate<T>
:断言型接口,用于条件判断。
Java 8 提供了这四个核心的函数式接口,极大简化了基于匿名类的编程,使得代码更加简洁、易读,并且与 Lambda 表达式 结合紧密:
这些接口通过 Lambda 提供了高度简洁的语法,并且通过
andThen
、compose
、or
等方法,使得函数式编程风格在 Java 中更加自然和强大。- 作者:瑾墨
- 链接:https://www.gaoqilan.tech/Code/b485e571-9890-4c96-ad2f-67ab03c92091
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。