Table of Contents
2. Cannot be used for runtime type checking
3. Type instances cannot be created
4. Cannot be staticized
1. 无界通配符
2. 上界
3. 下界
4. PECS 原则
5. 自限定类型
Home Java javaTutorial Detailed explanation of Java generics related knowledge (with code)

Detailed explanation of Java generics related knowledge (with code)

Feb 22, 2019 pm 01:35 PM

The content of this article is a detailed explanation of relevant knowledge about Java generics (with code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

I think everyone is very familiar with the use of generics, but they may not be very clear about details such as type erasure and boundary expansion, so this article will focus on explaining them; in addition, understanding of generics can actually It can be seen that the generation logic of a language feature is also very helpful for our daily development;

1. Why do generics appear

First of all, generics It is not a language feature of Java, it is a feature that was not supported until JDK1.5 (the specific differences will be discussed later); so what was done before generics appeared?

List list = new ArrayList();
list.add("123");
String s = (String) list.get(0);
Copy after login

As shown in the above code, we need to remember what we put in the collection, and then force it when we take it out; this also postpones this type conversion error to runtime, that is Trouble is not yet safe, so generics appear;

Usage scenarios: generic classes, generic interfaces, generic methods;

public class Test<T>
public interface Test<T>
public <T> void test(T t)
Copy after login

two , What kind of problems will generics bring

As mentioned above, generics are not a feature that Java has from the beginning, so when you want to add generics later, you must be compatible In previous versions, the compromise solution that Sun came up with was type erasure; this means that generic information only exists during compilation, and all generic information is erased during runtime. I don’t think so;

List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.getClass());
System.out.println(list2.getClass() == list1.getClass());
Copy after login

// Print:
class java.util.ArrayList
true

You can see List<String> and List<String> are actually the same at runtime, they are all class java.util.ArrayList; so when using generics, you need to keep in mind that there are no generics at runtime Type information, and it is impossible to obtain any information about parameter types; so any operation that needs to obtain the runtime type is not supported by generics!

1. Type parameters cannot be instantiated with basic types

new ArrayList<int>();      // error
new ArrayList<Integer>();  // correct
Copy after login

Because type erasure will erase it to its upper bound, which is Object; The direct parent class of Java's 8 basic types is Number, so basic types cannot use basic types to instantiate type parameters, but must use basic type wrapper classes;

2. Cannot be used for runtime type checking

t instanceof T             // error
t instanceof List<T>       // error
t instanceof List<String>  // error
t instanceof List          // correct
Copy after login

But you can use clazz.isInstance(); to compensate;

3. Type instances cannot be created

T t = new T();  // error
Copy after login

You can also use clazz.newInstance(); to compensate;

4. Cannot be staticized

private static T t;                  // error
private T t;                         // correct
private static List<T> list;         // error
private static List<?> list;         // correct
private static List<String> list;    // correct

// e.g.
class Test<T> {
  private T t;
  public void set(T arg) { t = arg; }
  public T get() { return t; }
}
Copy after login

Because static variables are shared in classes, and generic types are undefined, generics cannot be made static; but when they are non-static, the compiler can infer them based on the contextT## What is #, for example:

Test l = new Test();
System.out.println(l.get());
l.set("123");
System.out.println(l.get());

// javap -v 反编译
12: invokevirtual #15         // Method JDK/Test14_genericity$Test.get:()Ljava/lang/Object;
15: invokevirtual #16         // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
18: aload_1
19: ldc       #17             // String 123
21: invokevirtual #18         // Method JDK/Test14_genericity$Test.set:(Ljava/lang/Object;)V
24: getstatic   #6            // Field java/lang/System.out:Ljava/io/PrintStream;

// ---------------------------
Test l = new Test();
System.out.println(l.get());
l.set("123");
System.out.println(l.get());

// javap -v 反编译
12: invokevirtual #15         // Method JDK/Test14_genericity$Test.get:()Ljava/lang/Object;
15: invokevirtual #16         // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
18: aload_1
19: bipush    123
21: invokestatic  #17         // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
Copy after login

According to the above code, you can clearly see the compiler’s derivation of non-static types;

In addition List<?> and List

5. Instances of generic classes cannot be thrown or captured

catch (T t)                        // error
class Test<T> extends Throwable    // error
Copy after login

Because runtime class information is needed when catching exceptions and the inheritance relationship of the exception is determined, instances of generic classes cannot be thrown or captured;


6. Overloading as a parameter is not allowed

void test(List<Integer> list)
void test(List<String> list)
Copy after login

Because the generic information is erased during runtime, the signatures of the two overloaded methods are exactly the same;


7 . Unable to create a generic array

I think this is the most important point. For an introduction to arrays, please refer to Array related;

List<String>[] lists = new ArrayList<String>[10];             // error
List<String>[] lists1 = (List<String>[]) new ArrayList[10];   // correct
Copy after login

The main reason why a generic array cannot be created:

  • Arrays are covariant, while generics are immutable;

  • The

    Class information of the array is running It is created dynamically, and generic class information cannot be obtained at runtime;

According to the above explanation, we can see the general idea of ​​the so-called erasure compensation or correction after erasure. They all use additional methods to inform the runtime of type information, which can be recorded in local variables or the exact type of specified parameters (

Array.newInstance(Class<?> componentType, int length)) ;

3. Boundary expansion

Based on security considerations, Java generics are immutable (to avoid type conversion errors when retrieving data);

List<Object> list = new ArrayList<String>();    // error
Copy after login

So when using collection classes, it is a bit inconvenient to force each collection to specify the exact type. For example, I want to specify a collection to store A and subclasses of A; in this case, extends is introduced ,super,? to expand and manage the boundaries of generics;

1. 无界通配符 <?>

通配符主要用于泛型的使用场景(泛型一般有“声明”和“使用”两种场景);
通常情况下 <?> 和原生类型大致相同,就像 List 和 List<?> 的表现大部分都是一样的;但是要注意他们其实是有本质去别的,<?> 代表了某一特定的类型,但是编译器不知道这种类型是什么;而原生的表示可以是任何 Object,其中并没有类型限制;

List<?> list = new ArrayList<String>();    // correct
list.add("34");                            // error
String s = list.get(0);                    // error
Object o = list.get(0);                    // correct

boolean add(E e);
Copy after login

上面的代码很明确的反应了这一点(<?> 代表了某一特定的类型,但是编译器不知道这种类型是什么),

  • 因为编译器不知道这种类型是什么,所以在添加元素的时候,当然也就不能确认添加的这个类型是否正确;当使用<?>的时候,代码中的 add(E e) 方法,此时的 E 会被替换为 <?>实际上编译器为了安全起见,会直接拒绝参数列表中涉及通配符的方法调用;就算这个方法没有向集合中添加元素,也会被直接拒绝;

  • List<?> 取出元素的时候,同样因为不知道这个特定的类型是什么,所以只能将取出的元素放在Object中;或者在取出后强转;

2. 上界 <extends>

extends,主要用于确定泛型的上界;

<T extends Test>                             // 泛型声明
<T extends Test & interface1 & interface2>   // 声明泛型是可以确定多个上界
<? extends T>                                // 泛型使用时
Copy after login

界定的范围如图所示:

Detailed explanation of Java generics related knowledge (with code)

应当注意的是当extends用于参数类型限定时:

List<? extends List> list = new ArrayList<ArrayList>();  // correct
list.add(new ArrayList());                               // error
List l = list.get(0);                                    // correct
ArrayList l = list.get(0);                               // error
Copy after login

上面的分析同无界通配符类似,只是 List l = list.get(0); 是正确的,是因为 <? extends List> 界定了放入的元素一定是 List 或者 list 的子类,所以取出的元素能放入 List 中,但是不能放入 ArrayList 中;

3. 下界 <super>

super,主要用于确定泛型的下界;如图所示:

Detailed explanation of Java generics related knowledge (with code)

List<? super HashMap> list = new ArrayList<>();   // correct
LinkedHashMap m = new LinkedHashMap();            // correct
HashMap m1 = m;                                   // correct
Map m2 = m;                                       // correct
list.add(m);                                      // correct
list.add(m1);                                     // correct
list.add(m2);                                     // error

Map mm = list.get(0);                             // error
LinkedHashMap mm1 = list.get(0);                  // error
Copy after login

根据图中的范围对照代码,就能很快发现Map在List的范围之外;而编辑器为了安全泛型下界集合取出的元素只能放在 Object里面;

4. PECS 原则

PECS原则是对上界和下界使用的归纳,即producer-extends, consumer-super;结合上面的两幅图,表示:

  • extends只能读,相当于生产者,向外产出;

  • super只能写,相当于消费者,只能接收消费;

  • 同时边界不能同时规定上界和下界,正如图所示,他们的范围其实是一样的,只是开口不一样;

5. 自限定类型

对于上面讲的泛型边界拓展,有一个很特别的用法,

class Test<T extends Test<T>> {}
public <T extends Comparable<T>> T max(List<T> list) {}
Copy after login

自限定类型可以通俗的解释,就是用自己限定自己,即自和自身相同的类进行某操作;如上面的 max 方法,就表示可以和自身进行比较的类型;

那么如果想要表达只要是同一祖先就能相互比较呢?

public <T extends Comparable<? super>> T max(List<? extends T> list) {}
Copy after login

>:表明只要是同一祖先就能相互比较, extends T>表明集合中装的都是同一祖先的元素;(出至《Effective Java》第 28 条)

总结

  • 对于泛型的时候首先要很清楚的知道,在运行时没有任何泛型的信息,全部都被擦除掉了;

  • 需要知道 Java 泛型做不到的事情;

  • 需要知道怎么拓展边界,让泛型更加灵活;

The above is the detailed content of Detailed explanation of Java generics related knowledge (with code). For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Apr 19, 2025 pm 04:51 PM

Troubleshooting and solutions to the company's security software that causes some applications to not function properly. Many companies will deploy security software in order to ensure internal network security. ...

How to simplify field mapping issues in system docking using MapStruct? How to simplify field mapping issues in system docking using MapStruct? Apr 19, 2025 pm 06:21 PM

Field mapping processing in system docking often encounters a difficult problem when performing system docking: how to effectively map the interface fields of system A...

How to elegantly obtain entity class variable names to build database query conditions? How to elegantly obtain entity class variable names to build database query conditions? Apr 19, 2025 pm 11:42 PM

When using MyBatis-Plus or other ORM frameworks for database operations, it is often necessary to construct query conditions based on the attribute name of the entity class. If you manually every time...

How do I convert names to numbers to implement sorting and maintain consistency in groups? How do I convert names to numbers to implement sorting and maintain consistency in groups? Apr 19, 2025 pm 11:30 PM

Solutions to convert names to numbers to implement sorting In many application scenarios, users may need to sort in groups, especially in one...

How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? Apr 19, 2025 pm 11:45 PM

Start Spring using IntelliJIDEAUltimate version...

How to safely convert Java objects to arrays? How to safely convert Java objects to arrays? Apr 19, 2025 pm 11:33 PM

Conversion of Java Objects and Arrays: In-depth discussion of the risks and correct methods of cast type conversion Many Java beginners will encounter the conversion of an object into an array...

E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? Apr 19, 2025 pm 11:27 PM

Detailed explanation of the design of SKU and SPU tables on e-commerce platforms This article will discuss the database design issues of SKU and SPU in e-commerce platforms, especially how to deal with user-defined sales...

How to elegantly get entity class variable name building query conditions when using TKMyBatis for database query? How to elegantly get entity class variable name building query conditions when using TKMyBatis for database query? Apr 19, 2025 pm 09:51 PM

When using TKMyBatis for database queries, how to gracefully get entity class variable names to build query conditions is a common problem. This article will pin...

See all articles