随着 Java 编程语言的不断发展和更新,Java 1.5 版本引入了一项全新的特性——Java 泛型(Java Generic),这一特性为 Java 程序员提供了一种更加灵活、安全和通用的编程技术。本文将全面介绍 Java 泛型的概念、语法和应用,并提供一些示例代码来帮助您更好地理解和使用 Java 泛型。
Java 泛型(Java Generic)是一种编程技术,它允许程序员在编写 Java 类、接口和方法时定义泛型类型参数,这些类型参数可以在代码中表示不同的类型,使得代码变得更加通用、可重用和类型安全。Java 泛型还提供了运行时类型检查机制,可以在运行时捕获类型错误,从而避免出现类型转换异常等常见问题。
需求:存放学生的成绩
//在集合中使用泛型之前的情况:
@Test!
public void test(){
ArrayList list = new ArrayList();
list.add(99);
list.add(98);
list.add(97);
}
存在问题:
问题一:类型不安全
list.add("Tom");
问题二:强转时,可能出现ClassCastException
for(Object score : list){
int stuScore = (Integer) score;
System.out.println(stuScore);
}
在集合中使用泛型的情况:以ArrayList为例
@Test
public void test1(){
ArrayList list = new ArrayList();
list.add(78);
list.add(87);
list.add(99);
list.add(65);
// list.add("Tom");
//编译时,就会进行类型检查,保证数据的安全
for(Integer score : list){ //避免了强转操作
int stuScore = score;
System.out.println(stuScore);
}
}
Java 泛型的核心语法包括类型参数、类型变量、类型通配符和上下界限制。
Java 泛型定义了一组类型参数,这些类型参数可以在类、接口或方法的声明中使用,以表示可以适用于多种不同类型的代码。类型参数使用尖括号(<>)包裹,并且通常使用单个大写字母表示。例如:
class MyGenericClass {}
上述代码中,类 MyGenericClass 定义了一个泛型类型参数 T,它可以用来表示任何数据类型。
类型变量是指在使用泛型类型参数时所定义的具体类型,通常使用小写字母表示。例如:
MyGenericClass myGenericInt = new MyGenericClass();
上述代码中,我们使用泛型类型参数 T 来定义一个整数类型变量 myGenericInt,并且在实例化类对象时将类型参数 T 替换为具体类型 Integer。
List> myList;
上述代码中,我们定义了一个泛型列表 List,并使用类型通配符 ? 表示可以接受任何类型的数据。
上下界限制用来限制类型参数的范围,包括上界限制和下界限制。
class MyGenericClass {}
上述代码中,我们定义了一个泛型类型参数 T,并使用上界限制 extends Number 表示类型参数必须是 Number 类型或其子类类型。
void myMethod(List super Integer> myList) {}
上述代码中,我们定义了一个方法 myMethod,并使用下界限制 super Integer 表示方法参数必须是 Integer 类型或其父类类型的列表。
Java 泛型可以应用于类、接口、方法等各种代码块中,下面我们将逐一介绍这些用法。
java
public class MyGenericClass {
private T element;
public MyGenericClass(T element) {
this.element = element;
}
public T getElement() {
return element;
}
public void setElement(T element) {
this.element = element;
}
}
上述代码中,我们定义了一个泛型类 MyGenericClass,它的类型参数为 T,我们在其中定义了一个变量 element,它的类型为 T,这样就可以用来存储任意类型的数据。
方法泛型就是在方法的声明中使用泛型类型参数。例如:
public class MyGenericMethod {
public void printArray(T[] array) {
for (T element : array) {
System.out.println(element.toString());
}
}
}
上述代码中,我们定义了一个泛型方法 printArray,它接受一个泛型数组类型作为参数,使用 for-each 循环遍历数组并打印出每个元素的字符串表示。
接口泛型就是在接口声明中使用泛型类型参数。例如:
public interface MyGenericInterface {
public T doSomething();
}
上述代码中,我们定义了一个泛型接口 MyGenericInterface,它声明了一个泛型方法 doSomething,返回值类型为 T。
下面我们来看一些 Java 泛型的示例代码,以帮助读者更好地理解和使用 Java 泛型。
- 类泛型的示例
public class MyContainer {
private T element;
public MyContainer(T element) {
this.element = element;
}
public T getElement() {
return element;
}
public void setElement(T element) {
this.element = element;
}
public static void main(String[] args) {
MyContainer myInt = new MyContainer<>(10);
MyContainer myString = new MyContainer<>("Hello, World!");
System.out.println(myInt.getElement());
System.out.println(myString.getElement());
}
}
这是一个基于泛型的容器类 MyContainer,它可以存储不同类型的数据,并提供了访问元素和设置元素的方法。通过在类声明中加入一对尖括号 <>,其中的变量 T 表示泛型类型参数,可以使该类变得更加通用和灵活。
在 MyContainer 类的主函数中,我们使用泛型类型参数来创建两个不同类型的实例对象分别存储 Integer 和 String 类型的值,并分别获取元素并输出到控制台。这样,就可以在避免类型转换异常的同时,实现了类型安全和代码复用的效果。
- 方法泛型的示例
public class MyGenericMethod {
public static T pickOne(T a, T b) {
return Math.random() < 0.5 ? a : b;
}
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "World";
Integer int1 = 10;
Integer int2 = 20;
System.out.println(pickOne(str1, str2));
System.out.println(pickOne(int1, int2));
}
}
这是一个使用泛型的方法 pickOne,它接受两个相同类型的参数,并以等概率随机返回其中一个参数。在方法声明的 中,T 表示泛型类型参数,使得该方法可以接受任意类型的参数并且不需要进行类型转换。
在类的主函数中,我们分别创建了两个字符串和两个整数对象,并将它们作为参数传递给了 pickOne 方法,然后输出所返回的结果。在输出语句中,也没有指定具体的数据类型,而是由编译器自动推导出了正确的类型。这样,就可以实现代码复用和类型安全的效果。
- 接口泛型的示例
public interface MyGenericInterface {
public T doSomething();
}
public class MyGenericClass implements MyGenericInterface {
@Override
public String doSomething() {
return "Hello, World!";
}
public static void main(String[] args) {
MyGenericClass myGeneric = new MyGenericClass();
System.out.println(myGeneric.doSomething());
}
}
这是一个使用泛型接口的示例代码,其中 MyGenericInterface 是一个泛型接口,定义了一个类型参数 T 和一个无参数的方法 doSomething,它返回一个泛型类型 T 的结果对象。
在 MyGenericClass 类中,我们实现了泛型接口 MyGenericInterface,并将泛型类型参数 T 替换为具体类型 String。在 doSomething 方法中,我们返回了一个字符串类型的结果对象 “Hello, World!”。
在类的主函数中,我们创建了一个 MyGenericClass 类的对象,并调用了 doSomething 方法获取它的返回值,并将其输出到控制台。通过使用泛型接口,我们可以灵活地定义和实现不同类型的接口,并保证类型安全和代码复用的效果。
总结✌️
泛型的使用 jdk 5.0新增的特性
在集合中使用泛型: 总结:
① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
② 在实例化集合类时,可以指明具体的泛型类型
③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。 比如:add(E e) —>实例化以后:add(Integer e)
注意点:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
好书分享
618,清华社 IT BOOK 多得图书活动开始啦!活动时间为 2023 年 6 月 7 日至 6 月 18 日,清华
社为您精选多款高分好书,涵盖了 C++、Java、Python、前端、后端、数据库、算法与机器学习等多
个 IT 开发领域,适合不同层次的读者。全场 5 折,扫码领券更有优惠哦!快来查看详情 !
图书链接:Node.js从基础到项目实践(视频教学版)