In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-03-30 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article shows you how to understand the generics and implementation of Java. The content is concise and easy to understand, which will definitely brighten your eyes. I hope you can get something through the detailed introduction of this article.
Generic basis
Generics are an extension of the Java language type system, somewhat similar to C++ 's templates, in that type parameters can be thought of as placeholders for types specified when using parameterized types. The introduction of generics is a big enhancement to the Java language and brings a lot of benefits:
Type safe. Type errors are now caught during compilation rather than shown as java.lang.ClassCastException at run time. Moving type checking from runtime to compile time will help developers find errors more easily and improve the reliability of the program.
Eliminates a lot of forced type conversions in the code and enhances the readability of the code
Makes it possible for a larger optimization.
What a generic type is does not affect what type an object instance is, so it is not possible to try to define different overloaded methods by changing the way generics are used. The rest of the content I will not talk too much about the use of generics, generic wildcards and other knowledge, please consult yourself.
Before moving on to the following discussion, I would like to ask a few questions:
How many classes are generated by defining a generic class, such as how many classes does ArrayList have?
Defining a generic method will eventually have several methods in the class file
Why can't generic parameters be basic types?
Is ArrayList a class?
What is the relationship between ArrayList and List and ArrayList and List? can these types of references be assigned to each other?
Type erase
The first prerequisite for correctly understanding the concept of generics is to understand type erasure (type erasure). Generics in Java are basically implemented at the compiler level. The type information in generics is not included in the generated Java bytecode. The type parameters added when using generics are removed by the compiler at compile time. This process is called type erasure. Types such as List and List defined in the code become List after compilation. All JVM sees is List, while type information attached by generics is not visible to JVM. The Java compiler will find possible errors as much as possible at compile time, but still cannot avoid type conversion exceptions at run time. Type erasure is also an important difference between the generic implementation of Java and the template mechanism of C++.
Many of the strange features of generics are related to the existence of this type of erasure, including:
Generic classes do not have their own unique Class class objects. For example, there is no List.class or List.class, but only List.class.
Static variables are shared by all instances of a generic class. For classes declared as MyClass, the method to access the static variables in it is still MyClass.myStaticVar. Objects created through new MyClass or new MyClass share a static variable.
Generic type parameters cannot be used in catch statements for Java exception handling. Because exception handling is done by JVM at run time. Because the type information is erased, JVM cannot distinguish between the two exception types MyException and MyException. For JVM, they are all of type MyException. The catch statement corresponding to the exception cannot be executed.
The basic process of type erasure is also relatively simple, starting with finding the concrete class to replace the type parameters. This concrete class is generally Object. This upper bound is used if the upper bound of the type parameter is specified. Replace the type parameters in the code with specific classes. At the same time, remove the type declaration that appears, that is, the removed content. For example, the T get () method declaration becomes Object get (); List becomes List.
The implementation principle of generics
For various reasons, Java can not achieve true generics, can only use type erasure to achieve pseudo-generics, which does not have the problem of type bloating (the puzzle of C++ templates), but also gives rise to a lot of new problems. Therefore, Sun has imposed a lot of restrictions on these problems to prevent us from making all kinds of mistakes.
Ensure type safety
First of all, * The java compiler compiles by checking the types of generics in the code and then erasing the types. Who is that type of inspection aimed at? let's look at an example first.
ArrayList arrayList1=new ArrayList (); / / correct, can only be put into String ArrayList arrayList2=new ArrayList (); / / can be put into any Object
There are no errors, but there will be a compile-time warning. However, in the case of * *, you can achieve the same effect as using generic parameters completely, while the second one has no effect at all. Because, the original type checking is done at compile time. New ArrayList () simply opens up a storage space in memory that can store any type of object. What really involves type checking is its reference, because we use it to reference arrayList1 to call its methods, such as calling the add () method. So arrayList1 references can complete the check of generic types. The reference arrayList2 does not use generics, so it is not possible.
Type checking is for references. If a reference is used to call a generic method, a type check will be performed on the method called by the reference, regardless of the object it actually references.
Implement automatic type conversion
Because of the problem of type erasure, all generic type variables are replaced with the original type. This raises the question, since they are all replaced with primitive types, why do we not need to cast when we get them?
Public class Test {public static void main (String [] args) {ArrayList list=new ArrayList (); list.add (new Date ()); Date myDate=list.get (0);}}
The class file generated by the compiler will add type conversion before returning to the call point after you call the generic method. For example, the get function above adds a cast before the jump returns to the instruction position of the original assignment operation after the completion of the get method, and the converted type is deduced by the compiler.
Inheritance relationships in generics
Let's first look at an example:
Class DateInter extends A {@ Override public void setValue (Date value) {super.setValue (value);} @ Override public Date getValue () {return super.getValue ();}}
First of all, let's analyze the setValue method. The type of the parent class is Object, while the type of the subclass is Date, and the parameter type is different. If it is really a common inheritance relationship, it will not be overridden at all, but overloaded.
Public void setValue (java.util.Date); / / our rewritten setValue method Code: 0: aload_0 1: aload_1 2: invokespecial # 16 / / invoke A setValue: (Ljava/lang/Object;) V 5: return public java.util.Date getValue () / / our rewritten getValue method Code: 0: aload_0 1: invokespecial # 23 / / A.getValue: () Ljava/lang/Object; 4: checkcast # 26 7: areturn public java.lang.Object getValue () / / the compiler-generated method Code: 0: aload_0 1: invokevirtual # 28 / / Method getValue: () to call our rewritten getValue method; 4: areturn public void setValue (java.lang.Object) / / the compiler-generated method Code: 0: aload_0 1: aload_1 2: checkcast # 26 5: invokevirtual # 30 / / Method setValue; to call our rewritten setValue method) V 8: return
Also, it may be doubtful that the methods Object getValue () and Date getValue () in the subclass exist at the same time, but if they are two regular methods, their method signatures are the same, that is, the virtual machine cannot distinguish the two methods at all. If we write our own Java code, such code cannot be checked by the compiler, but the virtual machine is allowed to do so, because the virtual machine determines a method by parameter type and return type, so the compiler allows itself to do what seems to be "illegal" in order to achieve generic polymorphism, and then give it to the virtual machine to distinguish.
Let's look at another example that often occurs.
Class A {Object get () {return new Object ();}} class B extends A {@ Override Integer get () {return new Integer (1);}} public static void main (String [] args) {An a = new B (); BB = (B) a; A c = new A (); a.get (); b.get (); c.get ();}
The result after decompilation
17: invokespecial # 5 / / Method com/suemi/network/test/A. "": () V 20: astore_3 21: aload_1 22: invokevirtual # 6 / / Method com/suemi/network/test/A.get: () Ljava/lang/Object 25: pop 26: aload_2 27: invokevirtual # 7 / / Method com/suemi/network/test/B.get: () Ljava/lang/Integer; 30: pop 31: aload_3 32: invokevirtual # 6 / / Method com/suemi/network/test/A.get: () Ljava/lang/Object
In fact, when we use the parent class reference to call the get of the subclass, we first call the override method generated by JVM, and then call the method implementation written by ourselves in the bridge method.
Inheritance relationship of generic parameters
In Java, people are familiar with the type architecture generated through the inheritance mechanism. For example, String inherits from Object. According to the Liskov substitution principle, a subclass can replace a parent class. There is no problem passing in a String object when a reference to the Object class is needed. But on the other hand, when you replace a subclass reference with a reference to the parent class, you need to cast. The compiler does not guarantee that this conversion is legal at run time. This automatic subclass replaces the type conversion mechanism of the parent class, which is also applicable to arrays. String [] can replace Object []. However, the introduction of generics has had a certain impact on this type system. As mentioned earlier, List cannot replace List.
The type system after the introduction of generics adds two dimensions: one is the inheritance architecture of the type parameter itself, and the other is the inheritance architecture of the generic class or interface itself. * refers to cases such as List and List, where the type parameter String is inherited from Object. The second means that the List interface inherits from the Collection interface. For this type system, there are some rules:
The relationship between generic classes with the same type parameters depends on the inheritance architecture of the generic class itself. That is, List can be assigned to a reference of type Collection, and List can replace Collection. This also applies to type declarations with upper and lower bounds. When wildcards are used in the type declaration of a generic class, the determination of this substitution can be expanded in two dimensions. For example, Collection can be used. List can replace subtypes of List, so no error occurs when passing parameters.
Personally, I think it is inappropriate to use subtypes to describe this relationship for the above situation, because List and so on are not types in nature, but there is no such thing as a subtype because of the compiler check constraints on List types. It can only be explained by whether type conversion can be performed at the time of assignment.
Attention points in the use of generics run-time type query / / error, after erasing the type, only the original type is left in ArrayList, the generic information String no longer exists, and it is impossible to judge the problem of using generics in if (arrayList instanceof ArrayList) if (arrayList instanceof ArrayList) / / correct exceptions.
Objects of generic classes cannot be thrown or captured. In fact, it is illegal for generic classes to extend Throwable. Why can't Throwable be extended, because exceptions are caught and thrown at run time, and all generic information is erased at compile time. After the type information is erased, so many catch using different generic parameters become the original type Object, that is to say, the catch becomes exactly the same in multiple places, which is naturally not allowed.
Generic variables can no longer be used in catch clauses.
Public static void doWork (Class t) {try {...} catch (T e) {/ / compilation error T-> Throwable, the following will never be captured So it is not allowed...} catch (IndexOutOfBounds e) {}} to create an array of generic classes Pair [] table = new Pair [10] / / compilation error Pair [] table = new Pair [10]; / / No compilation error
Because the array must carry the type information of its own elements, after the type is erased, the Pair array becomes the Pair array, and the array can only carry the information that its element is Pair, but it cannot carry the information of its generic parameter type, so the type safety of table [I] assignment cannot be guaranteed. The compiler can only disable this operation.
Static methods and static variables in generic classes
Static methods and static variables in a generic class cannot use generic type parameters declared by a generic class.
Public class Test2 {public static T one; / / compilation error public static T show (T one) {/ / compilation error return null;}}
Because the instantiation of generic parameters in a generic class is specified when the object is defined, static variables and static methods do not need to be called with an object. Objects have not been created, how to determine the type of this generic parameter, so of course it is wrong.
Conflict class Pair {public boolean equals (T value) {return null;}} after type erasure
Method is redefined and there are two equals (Object o) at the same time.
The above content is how to understand the generics and implementation of Java. Have you learned the knowledge or skills? If you want to learn more skills or enrich your knowledge reserve, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 280
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.