We all know Java stay 1.5 Introduced generic mechanism , The essence of generics is parameterized type , That is to say, the type of variable is a parameter , When using it, specify it as a specific type . Generics can be used for classes 、 Interface 、 Method , You can make the code simpler by using generics 、 Security . In this paper, through reference 《Java Programming idea 》 This paper summarizes the problems that should be paid attention to in the process of using generics, and provides some interview questions related to generics for you to learn and use .

Generics related issues

1、 Generic type reference passing problem

stay Java in , Reference passing like this is not allowed :

ArrayList<String> arrayList1=new ArrayList<Object>();// Compile error
ArrayList<Object> arrayList1=new ArrayList<String>();// Compile error 

Let's look at the first case first , Expand the first case to the following form :

ArrayList<Object> arrayList1=new ArrayList<Object>();
arrayList1.add(new Object());
arrayList1.add(new Object());
ArrayList<String> arrayList2=arrayList1;// Compile error 

actually , In the 4 Line code , There will be compilation errors . that , Let's assume that it compiles correctly . So when we use arrayList2 For reference get() Method values , All of them String Object of type , But it's actually stored by us Object Object of type , such , There will be ClassCastException 了 . So in order to avoid this kind of very easy mistakes ,Java Such reference passing is not allowed .( That's why generics come along , To solve the problem of type conversion , We can't go against its original intention ).

Looking at the second situation , Expand the second case to the following form :

ArrayList<String> arrayList1=new ArrayList<String>();
arrayList1.add(new String());
arrayList1.add(new String());
ArrayList<Object> arrayList2=arrayList1;// Compile error 

you 're right , This situation is much better than the first one , Minimum , We use arrayList2 It doesn't appear when taking values ClassCastException, Because from String Convert to Object. But , What's the point of doing this , The reason for generics , To solve the problem of type conversion . We use generics , In the end , I still have to force myself , Against the original intention of generic design . therefore java It's not allowed . Besides, , If you use it again arrayList2 Inside add() New objects , So when it's time, when it's time , How do I know what I took out String Type of , still Object What about the type? ? therefore , Pay special attention to reference passing in generics .

2、 Generic type variables cannot be basic data types

Like , No, ArrayList<double>, Only ArrayList<Double>. Because when the type is erased ,ArrayList Type variables in the original class of (T) Replace with Object, but Object Type cannot store double value .

3、 Run time type query

ArrayList<String> arrayList=new ArrayList<String>();if( arrayList instanceof ArrayLi

Because after type erasure ,ArrayList<String> Only the original type , Generic information String Does not exist. .

4、 Problems with generics in static methods and static classes

Static methods and static variables in generic classes cannot use generic type parameters declared by generic classes

public class Test2<T> {
public static T one; // Compile error
public static T show(T one){ // Compile error
return null;
} }

Because the instantiation of a generic parameter in a generic class is to define a generic type object ( for example ArrayList<Integer>) It's designated at the time of , Static variables and static methods don't need objects to call . Objects are not created , How to determine what type this generic parameter is , So of course it's wrong .

But pay attention to distinguish between the following situations :

public class Test2<T> {
public static <T >T show(T one){// That's right
return null;
} }

Because this is a generic method , Used in generic methods T It's defined in the method itself T, Not in generic classes T.

Interview questions related to generics

1. Java What are generics in ? What are the benefits of using generics ?

Generics are a mechanism for parameterizing types . It can make the code applicable to all types , To write more general code , For example, the collection framework . Generics are a compile time type validation mechanism . It provides type security at compile time , Make sure that in generic types ( It's usually a collection of generics ) Only objects of the correct type can be used on , Avoid the occurrence of ClassCastException.

2、Java How do generics of work ? What is type erasure ?

The normal work of generics depends on the compiler when compiling the source code , Type check first , Then erase the type and insert the relevant instructions of the cast where the type parameter appears .

The compiler erases all type related information at compile time , So there's no type of information at runtime . for example List<String> Use only one... At runtime List By type . Why erase it ? This is to avoid type inflation .

3. What are qualified wildcards and unqualified wildcards in generics ?

Qualifying wildcards limits the type . There are two kinds of qualified wildcards , One is <? extends T> It ensures that the type must be T To set the upper bound of the type , The other is <? super T> It ensures that the type must be T To set the lower bound of a type . Generic types must be initialized with types within the constraints , Otherwise, it will lead to compilation errors . On the other hand <?> Represents an unqualified wildcard , because <?> You can substitute any type for .

4. List<? extends T> and List <? super T> What's the difference between ?

This is related to the last interview question , Sometimes the interviewer will use this question to evaluate your understanding of generics , Instead of asking you what are qualified wildcards and unqualified wildcards . these two items. List All of the statements are examples of qualified wildcards ,List<? extends T> Any inheritance from T The type of List, and List<? super T> Any T Made up of List. for example List<?extends Number> Acceptable List<Integer> or List<Float>. More information can be found in the links that appear in this paragraph .

5. How to write a generic method , Let it accept generic parameters and return generic types ?

It's not difficult to write generic methods , You need to replace the original type with a generic type , For example, use T, E or K,V And other widely recognized type placeholders . For an example of a generic method, see Java Collection class framework . In the simplest case , A generic method might look like this :

public V put(K key, V value) {
return cache.put(key, value);

6. Java How to use generics to write classes with parameters ?

This is an extension of the last interview question . The interviewer may ask you to write a type safe class with generics , Instead of writing a generic method . The key is still to use generic types instead of primitive types , And use JDK Standard placeholders used in .

7. Write a generic program to implement LRU cache ?

For the love Java It's quite an exercise for programmers . Give you a hint ,LinkedHashMap Can be used to achieve fixed size LRU cache , When LRU When the cache is full , It will move the oldest key value pair out of the cache .LinkedHashMap There is one provided called removeEldestEntry() Methods , The method will be put() and putAll() Call to delete the oldest key value pair .

8. You can take List<String> Pass it on to an acceptor List<Object> Parameter method ?( See above )

For anyone who is not familiar with generics , This Java Generic topics seem confusing , Because at first sight String It's a kind of Object, therefore List<String> Should be able to be used in need of List<Object> The place of , But that's not the case . If you do, it will lead to compilation errors . If you think about it further , You'll find that Java It makes sense to do so , because List<Object> Can store any type of object including String, Integer wait , and List<String> But it can only be used to store Strings.

9. Array Can I use generics in ?

This may be Java The simplest of the general interview questions , Of course, if you know Array In fact, generics are not supported , That's why Joshua Bloch stay Effective Java It is recommended to use List Instead of Array, because List It can provide type security guarantee at compile time , and Array But not .

10. How to stop Java Warning of type unchecked in ?

If you mix generics with primitive types , For example, the following code ,Java 5 Of javac The compiler will generate an unchecked type warning , for example List<String> rawList = new ArrayList() Be careful : Hello.java Use of unchecked or unsafe operations ; This warning can be used @SuppressWarnings("unchecked") Comment to mask .

11、Java in List<Object> And the original type List The difference between ?

Primitive and parameterized types <Object> The main difference between them is , At compile time, the compiler does not perform type safety checks on the original types , However, the type with parameters will be checked , By using Object As a type , You can tell the compiler that the method can accept any type of object , such as String or Integer. The purpose of this question is to understand the primitive types in generics correctly . The second difference between them is , You can pass any generic type with parameters to accept the original type List Methods , But it can't put List<String> Pass it on to the receiver List<Object> Methods , Because there will be compilation errors .

12、Java in List<?> and List<Object> What's the difference ?

This question looks like the next one , In essence, it's totally different .List<?> It's an unknown type of List, and List<Object> It's actually any kind of List. You can take List<String>, List<Integer> Assign a value to List<?>, But I can't List<String> Assign a value to List<Object>.

List<?> listOfAnyType;
List<Object> listOfObject = new ArrayList<Object>();
List<String> listOfString = new ArrayList<String>();
List<Integer> listOfInteger = new ArrayList<Integer>();
listOfAnyType = listOfString; //legal
listOfAnyType = listOfInteger; //legal
listOfObjectType = (List<Object>) listOfString; //compiler error - in-convertible ty

13、List<String> And the original type List The difference between .

The problem is similar to “ What's the difference between a primitive type and a type with parameters ”. Types with parameters are type safe , And its type safety is guaranteed by the compiler , But the original type List But not type safe . You can't put String Any other type of Object Deposit in String Type of List in , And you can put any type of object in the original List in . Using generic parameterized types, you don't need to type cast , But for primitive types , You need to do an explicit type conversion .

List listOfRawTypes = new ArrayList();
listOfRawTypes.add(123); // The compiler allows this  -  There are exceptions at run time
String item = (String) listOfRawTypes.get(0); // Need explicit type conversion
item = (String) listOfRawTypes.get(1); // throw  ClassCastException, because  Integer  Can't be converted to  String
List<String> listOfString = new ArrayList();
listOfString.add(1234); // Compile error , Better than throwing exceptions at runtime
item = listOfString.get(0); // No explicit type conversion is required  -  Compiler auto conversion 


Wildcard upper bound

Regular use

public class Test {
public static void printIntValue(List<? extends Number> list) {
for (Number number : list) {
System.out.print(number.intValue()+" ");
public static void main(String[] args) {
List<Integer> integerList=new ArrayList<Integer>();
List<Float> floatList=new ArrayList<Float>();
floatList.add((float) 3.3);
floatList.add((float) 0.3);
} }

Output :

2 2

3 0

Illegal use

public class Test {
public static void fillNumberList(List<? extends Number> list) {
list.add(new Integer(0));// Compile error
list.add(new Float(1.0));// Compile error
public static void main(String[] args) {
List<? extends Number> list=new ArrayList();
list.add(new Integer(1));// Compile error
list.add(new Float(1.0));// Compile error
} }

List<? extends Number> Can represent List<Integer> or List<Float>, Why can't we just add Integer perhaps Float Well ?

First , We know List<Integer> You can only add Integer. And the following code is feasible :

List<? extends Number> list1=new ArrayList<Integer>();
List<? extends Number> list2=new ArrayList<Float>();

Let's assume that the previous example has no compilation errors , If we put list1 perhaps list2 Incoming method fillNumberList, Obviously there will be type mismatches , Suppose not .

therefore , We come to a conclusion : You can't go to List<? extends T> Add any object to , except null.

So why is that right List<? extends T> It's OK to iterate , Because the subclass must have the same interface as the parent , This is exactly what we expect .

Wildcard lower bound

Regular use

public class Test {
public static void fillNumberList(List<? super Number> list) {
list.add(new Integer(0));
list.add(new Float(1.0));
public static void main(String[] args) {
List<? super Number> list=new ArrayList();
list.add(new Integer(1));
list.add(new Float(1.1));
} }

You can add Number Any subclass of , Why? ?

List<? super Number> Can represent List<T>, among T by Number Parent class ,( although Number No parent ). if ,T by Number Parent class of , We want to List<T> Add Number Subclasses of are certainly ok .

Illegal use

Yes List<? superT> Iteration is not allowed . Why? ? You know which interface to use to iterate List Do you ? Only with Object Class to ensure that all elements in the collection have the interface , Obviously it doesn't make much sense . The application scenarios are as follows .

*** wildcard

We know the upper and lower bounds of wildcards , Actually, it's the same as knowing *** wildcard , Without any modification , One by one “?”. Such as List<?>,“?” Can represent any type of ,“ arbitrarily ” That is, the unknown type .

List<Object> And List<?> It's not the same as ,List<Object> yes List<?> Subclasses of . And you can't go to List<?> list Add any object to the , except null.

Regular use

1、 When the method is original Object When type is used as a parameter , as follows :

public static void printList(List<Object> list) {
for (Object elem : list)
System.out.println(elem + "");

You can choose to implement it as follows :

public static void printList(List<?> list) {
for (Object elem: list)
System.out.print(elem + "");

This allows for more output compatibility , It's not just List<Object>, as follows :

List<Integer> li = Arrays.asList(1, 2, 3);
List<String> ls = Arrays.asList("one", "two", "three");

If you think that asamura's article will help you , Please search and follow on wechat 「 Shallow feathered IT hut 」 WeChat official account , I'll share my computer information knowledge here 、 Theoretical Technology 、 Tool resources 、 The software is introduced 、 The backend development 、 interview 、 A series of articles, such as thoughts on work and some thoughts on life . What you see and what you get , It's all about life . take your time , Work harder , You and I grew up together ...

I set up a technology group , If you want to know more about IT The technology of the industry and the problems in life , Welcome to join the group , Just add my wechat , Note that you can enter the group , We look forward to your participation .

Previous recommendation

How to be in Java Create elegant objects to improve program performance


More pictures , Understand 8 A common data structure


High concurrency , Do you really understand ?


dried food !MySQL Optimization principle analysis and optimization scheme summary


hardcore !15 Zhang diagram Redis Why so soon?


We media people's essential multi platform synchronization 、 More than one article


We media people deserve to have 20 It's a free website for beautiful pictures


Programmer essential technology website Collection


Shallow feather

Message area

Point a praise , Prove that you still love me