首页 >Java >java教程 >Java 中的泛型是什么?

Java 中的泛型是什么?

WBOY
WBOY原创
2024-08-30 16:18:36974浏览

Java 中的泛型是一项高级功能,可实现代码可重用性和类型安全。代码可重用性功能是通过定义通用类、接口、构造函数和方法来实现的。泛型使用数据类型声明来确保类型安全,从而消除运行时错误的机会。尖括号“”符号用于实现泛型,类型参数在括号内定义。这些类型参数包括“T”(类型)、“E”(元素)、“N”(数字)、“K”(键)和“V”(值)。具有类型 T 参数的泛型类的示例是“public class DemoGenericClass”。 {…}’

 

开始您的免费软件开发课程

网络开发、编程语言、软件测试及其他

Java 中泛型是如何实现的?

泛型是使用尖括号“”实现的括号内包含类型参数“T”。例如,在中,类型参数“T”是一个占位符,表示将在运行时分配数据类型。

泛型类可以定义为:

代码:

public class MyGenericClass<T> {…}

以下是标准类型参数:

  • T: 类型
  • E: 元素
  • N: 数字
  • K:钥匙
  • V:价值

多参数的情况下,用S、U、V等分别定义第二个、第三个、第四个参数。

理解 Java 中的泛型

什么是类型安全以及它如何工作?泛型类、接口、构造函数和方法与我们的常规类和方法有何不同,从而使它们可重用?

Java 是一种静态类型语言,在使用变量之前需要声明其数据类型。

示例:

代码:

String myString ="eduCBA";

在上面的代码中,“String”是数据类型,“myString”是保存 String 类型值的变量。

现在,如果尝试传递一个布尔值来代替字符串,如下所示:

代码:

String myBooleanStr = true;

它将立即导致编译时错误,指出“类型不匹配:无法从布尔值转换为字符串”

输出:

Java 中的泛型是什么?

如何通过泛型实现代码的可重用性?

现在,让我们定义一个常规方法:

代码:

public static void welcome(String name){
System.out.println("welcome to " + name);
}

该方法只能通过传递字符串参数来调用。

代码:

welcome("eduCBA");

其输出将是“欢迎来到 eduCBA”

但是,只有 String 可以调用此方法。尝试传递任何其他数据类型(例如整数或布尔值)将导致编译时错误,指出“Runner 类型中的方法welcome(String) 不适用于参数(布尔值)”

输出:

Java 中的泛型是什么?

如果想要为不同的数据类型调用类似的方法,可以创建一个接受所需数据类型作为参数的新方法。这种用不同数据类型的参数重写方法的技术称为“方法重载”。然而,这种方法的一个缺点是它可能会导致更大的代码大小。

还可以使用泛型重写上述方法,并将其用于我们需要的任何数据类型。

定义通用方法:

代码:

public static <T> void welcome(T t){
System.out.println("it is " + t);
}

注意: 这里,“t”是类型 T 的对象。用于调用方法的实际数据类型将分配给类型参数“T”。

这使得该方法可以根据需要与不同的数据类型重用,包括字符串、布尔值、整数等。

代码:

welcome("educba");
Integer myint = 1;
welcome(myint);
welcome(true);

上述语句将提供以下输出:

输出:

it is educba
it is 1
it is true

因此,在这里使用泛型,我们可以针对不同的数据类型重用我们的方法。

Java 中的泛型是什么?

如何使用泛型实现类型安全?

数组和集合之间的主要区别之一是数组只能存储同质数据,而集合可以存储异构数据。换句话说,集合可以存储任何类型的对象,包括用户定义的数据类型。

注意:集合只能保存对象,包括用户定义的数据类型,而不是原始数据类型。为了使用原始数据类型,集合使用包装类。

Now, let’s consider an ArrayList.

Code:

ArrayList myList = new ArrayList();

One can add elements of various data types, such as strings, integers, and doubles, to an ArrayList object.

Code:

myList.add("eduCBA");
myList.add(1);
myList.add(5.2);

On printing the ArrayList object, one can see that it contains the following values: [eduCBA, 1, 5.2].

Output:

Java 中的泛型是什么?

To retrieve these values into variables, one needs to typecast them.

Code:

String someStr = (String)myList.get(0);
Integer someInt = (Integer)myList.get(1);
Double someFlt = (Double)myList.get(2);

If one does not typecast, it will prompt a compile-time error stating, “Type mismatch: cannot convert from Object to String”

Output:

Java 中的泛型是什么?

Thus, one must typecast them to their respective types while retrieving the objects from the ArrayList. However, in real-time scenarios, an ArrayList can contain thousands of records, and manually typecasting every object may not be feasible. There is the risk of mistakenly typecasting an object to an incorrect data type. In such cases, a runtime error will occur, stating “Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at com.serviceClasess.Runner.main(Runner.java:43)”.

Java 中的泛型是什么?

As there is no guarantee with regard to the type of data present inside a collection (in this case, ArrayList), they are considered unsafe to use with respect to type. Here, Generics play a role in providing type safety.

Using ArrayList with Generics:

Code:

ArrayList<String> myList = new ArrayList<String>();

The String type is specified inside the angular brackets “>” which means that this particular implementation of ArrayList can only hold String type data. If one tries to add another data type, it will simply throw a compile-time error. Here, the ArrayList has been made type-safe by eliminating its chances of adding a data type other than “String.”

Output:

Java 中的泛型是什么?

Now, since one has specified the data type that is allowed to be added to the collection with the help of Generics, there is no need to typecast it while retrieving the data. One can simply retrieve the data by writing.

Code:

String someStr = myList.get(0);

Output:

Java 中的泛型是什么?

How do Generics in Java make Work Easier?

  • It helps make the collections type safe and ensures the code does not fail at a later point due to any run time exception.
  • It saves the coder from having to typecast each object in the collection, which simplifies and speeds up the code development process.
  • Generics allow writing code in a way that can work with multiple data types.

What else to do with Generics in Java?

So far, we have seen how we can achieve type safety and code reusability with Generics.

In addition to type safety and code reusability, here are some other features that Generics can provide:

  • Bounded & Multiple Bounded Types
  • Type Wildcards

1. Bounded Type

In the case of a bounded type, the data type of a parameter is bounded to a particular range. The keyword “extends” helps achieve this.

For example, let’s consider a Generic class with a bounded type parameter that extends the ‘Runnable interface’:

Code:

class myGenericClass<T extends Runnable>{}

Now, while creating its object in another class:

Code:

myGenericClass<Thread> myGen = new myGenericClass<Thread>();

The above statement will execute perfectly without any errors. In the case of the bounded type, one can pass the same class type or its child class type. Also, one can bind the parameter type to an interface and pass its implementations when invoking it, as in the example above.

What happens if one uses any other type of parameter?

Code:

myGenericClass<Integer> myGen = new myGenericClass<Integer >();

In the above case, it will result in a compile-time error, stating “Bound mismatch: The type Integer is not a valid substitute for the typecast of the type myGenericClass

Output:

Java 中的泛型是什么?

  • Multiple bounded types: In the case of multiple bounded types, one can bind the parameter data type to more than one type.

Example:

Code:

class myGeneric<T extends Number & Runnable>{}

In this case, one can pass any type that extends the Number class and implements the Runnable interface. However, when using multiple bounded types, a few things should be noted:

  • One cannot extend more than one class at a time.
  • One can extend any number of interfaces simultaneously, i.e., there is no limit for interfaces.
  • The class name should always come first, followed by the interface name. If not, it will result in a compile-time error.

2. Type Wildcards

The “?” (question mark) symbol represents Type Wildcards. It makes use of two main keywords:

  1. extends (to define upper bound)
  2. super (to define lower bounds).

Example:

Code:

ArrayList<? extends T> al

The ArrayList object “al” will hold any data of type T and all its subclasses.

Code:

ArrayList<? super T> al

The ArrayList object “al” will hold any data of type T and all its superclasses.

Advantages of Generics in Java

  • Flexibility: Generics allow the code to accommodate different data types with the help of Generic classes and methods.
  • Code Maintenance and Reusability: Due to Generic classes and methods, one need not rewrite the code in case of a change in requirements later, making the code easier to maintain and reuse.
  • Type Safety: Provides type safety to the collection framework by defining the data type the collection can hold beforehand; and eliminating any chances of failure at run time due to ClassCastException.
  • Eliminating the Need to Typecast: Since the data types being held by the collections are already determined, one need not typecast it at the time of retrieval. This reduces the code’s length and a coder’s effort.

Generics in Java Skills

  • To work with Generics, one should be proficient in the basics of Java.
  • One should understand how type checking and typecasting work. Thorough knowledge of other concepts such as method overloading, the relationship between parent and child classes, interfaces, and their implementations is necessary.
  • Also, it is crucial to understand the difference between primitive data types (system-defined data type) and objects (user-defined data type) when working with the collection framework.

Why use Generics in Java?

  • Using Generics makes the code more maintainable as it reduces the need to rewrite data type-specific code every time there is a change in requirements.
  • By using Generics bounded type, one can restrict the data type and, at the same time, provide flexibility to the code by defining its range.
  • Generics provide type safety, making the code less error-prone and less likely to fail at a later point.

Scope for Generics in Java

Generics scope is limited to compile time, i.e., the Generics concept is applicable only at compile time but not at run time.

Example:

Code:

ArrayList myList = new ArrayList<Integer>();
ArrayList myList = new ArrayList<Float>();
ArrayList myList = new ArrayList<Double>();
ArrayList myList = new ArrayList<Boolean>();

Here all the above four statements are the same. They will allow adding any type of data to the list object.

Conclusion

Generics renders coding easy for a coder. It diminishes the chances of encountering ClassCastException at run time by providing strong type-checking. Also, it eliminates the need for typecasting, which means less code needs to be written. It allows the development of Generic algorithms independent of the data type they are working with.

以上是Java 中的泛型是什么?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn