Java泛型
一:故事背景
最近回顾了很早之前学的java基础,其中涉及到了泛型的概念,今天总结到此,以供大家参考以及自己的日后学习。
二:什么是Java泛型
在Java中,泛型是一种参数化类型的机制,它可以让类、接口、方法在定义时使用一个或多个类型参数,这些类型参数可以在实例化时被具体的类型所代替。
三:Java泛型的用法
下面将会分别写出Java泛型的用法,语法都将内含其中。
3.1泛型类
接下来我会通过定义一个泛型类来表示一个集合,可以让这个集合可以存储任何类型的对象,而不需要在定义时指定具体的类型。使用时再去指定集合中元素的类型,避免在运行时发生类型错误。
3.3.1 MyList 泛型类
public class MyList<T> {
private List<T> list = new ArrayList<>();
public void add(T element) {
list.add(element);
}
public T get(int index) {
return list.get(index);
}
public int size() {
return list.size();
}
}
在这个例子中,MyList 是一个泛型类,它的类型参数是 T。我们可以使用 MyList 来存储任何类型的对象,只需要在实例化时指定具体的类型即可
3.3.2 具体使用
MyList<Integer> intList = new MyList<>();
intList.add(1);
intList.add(2);
System.out.println(intList.get(0)); // 输出 1
MyList<String> stringList = new MyList<>();
stringList.add("hello");
stringList.add("world");
System.out.println(stringList.get(0)); // 输出 hello
3.2泛型接口
泛型接口是一个可以定义泛型类型参数的接口。
3.2.1 泛型接口
public interface MyList<T> {
void add(T element);
T get(int index);
int size();
}
这是一个泛型接口,它定义了一个可以存储任何类型的元素的列表。在实现该接口时,需要指定具体的类型参数.
3.2.2 具体使用
public class MyIntegerList implements MyList<Integer> {
private List<Integer> list = new ArrayList<>();
@Override
public void add(Integer element) {
list.add(element);
}
@Override
public Integer get(int index) {
return list.get(index);
}
@Override
public int size() {
return list.size();
}
}
3.3泛型方法
泛型方法是一种定义在类中但具有泛型类型参数的方法,它可以在调用时指定不同的类型参数。
3.3.1 泛型方法
public static <T> T getFirst(List<T> list) {
return list.get(0);
}
这是一个泛型方法,它可以接受任何类型的 List 对象,并返回该列表的第一个元素。在调用时,可以指定不同的类型参数。
3.3.2 具体使用
List<Integer> intList = Arrays.asList(1, 2, 3);
Integer first = getFirst(intList); // 返回 1
List<String> stringList = Arrays.asList("hello", "world");
String firstString = getFirst(stringList); // 返回 "hello"
四:Java泛型的好处
- 提高代码的可读性和可维护性:使用泛型可以使代码更加简洁、易读,减少代码冗余和重复的类型检查,降低了出错的可能性。
- 减少强制类型转换:在使用泛型时,编译器可以自动推断类型参数,无需进行强制类型转换,这减少了编写代码时的工作量,并使代码更加优雅。
- 支持代码重用:泛型代码可以在多个地方重用,而不需要进行修改。例如,在集合框架中,可以使用相同的方法来处理不同类型的集合。
- 支持灵活的数据结构:通过使用泛型,可以创建灵活的数据结构,使其能够处理不同类型的数据。
五:使用Java泛型的注意事项
在使用Java泛型时,有一些注意事项需要注意:
-
泛型类型参数不能是基本数据类型:泛型类型参数只能是类或接口类型,不能直接使用基本数据类型(如int、char、boolean)。如果需要使用基本数据类型,可以使用对应的包装类(如Integer、Character、Boolean)作为泛型参数。
-
泛型类型参数不能使用原生态类型:原生态类型是指未指定泛型类型参数的泛型类型。例如,List是一个原生态类型,而List<String>是具有泛型类型参数的参数化类型。在使用泛型时,应尽量避免使用原生态类型,而是使用具体的参数化类型。
-
泛型类型参数无法在运行时获取:由于Java的泛型使用类型擦除来实现,泛型信息在编译时被擦除,无法在运行时获取。这意味着无法在运行时判断一个对象的具体泛型类型参数。因此,在使用泛型时需要注意,泛型参数的具体类型只能在编译时进行检查。
-
泛型数组的创建受限:Java中不允许直接创建泛型数组,例如
new T[]
是不合法的。这是因为Java泛型数组的创建会涉及到类型擦除的问题,无法进行安全的类型检查。如果需要创建泛型数组,可以通过创建一个Object数组,然后进行强制类型转换来实现。 -
泛型类型参数不能用于静态上下文:由于泛型类型参数是在实例化时确定的,而静态成员和静态方法是在类加载时就存在的,无法访问实例化的泛型类型参数。因此,静态上下文中不能直接使用泛型类型参数,可以使用通配符或将泛型参数定义在静态方法或静态成员所在的类上。
-
通配符的使用限制:通配符(wildcard)用于表示不确定的类型参数,包括无界通配符(
?
)和有界通配符(如? extends T
和? super T
)。在使用通配符时,需要注意,无界通配符只能用于读取,不能用于写入;有界通配符可以用于读取和写入,但受到类型边界的限制。 -
泛型方法和泛型类的类型参数可以独立:在泛型类中,类级别的类型参数和方法级别的类型参数是独立的,即方法中的类型参数可以与类中的类型参数不同。这使得在泛型类的方法中可以使用额外的类型参数,增加了灵活性。
-
泛型类型参数的擦除和桥方法:在泛型类或接口中,由于类型擦除的原因,编译器会生成桥方法来保
持多态性。桥方法是编译器生成的方法,用于在类型擦除后保持泛型方法的多态性。
这些是使用Java泛型时需要注意的一些事项。理解并正确使用泛型可以提高代码的类型安全性和重用性。同时,还可以通过阅读相关的Java泛型文档和学习材料,深入了解泛型的原理和使用技巧。
六:总结提升
总之,Java中的泛型是一种非常强大和有用的机制,它可以提高代码的可读性和可维护性,减少强制类型转换,支持代码重用,同时还可以创建灵活的数据结构,适应不同的需求!