java--generics

Source: Internet
Author: User
Tags comparable

Java generics ( generics ) is a new feature introduced in JDK 5 that allows for the use of type parameters (types parameter) when defining classes and interfaces. The declared type parameter is replaced with a specific type when used. The most important application of generics is in the new collection class framework in JDK 5. For the introduction of generic concepts, the development Community's view is mixed. On the good side, the introduction of generics can solve the runtime type errors that the previous collection class framework would normally have in use, because the compiler can find many obvious errors at compile time. In the never-so-good place, there are some less elegant implementations of Java generics to ensure compatibility with older versions. This is, of course, the historical burden of any historical programming language. Subsequent versions of the update will be tired of earlier design flaws.

When using generics, developers can easily make mistakes based on their intuition. For example, if a method is received List<Object> as a formal parameter, then if you try to List<String> pass an object as an actual argument, you find that it cannot be compiled. Although it is intuitively that object is the parent of string, this type conversion should be reasonable. In practice, however, this creates an implicit type conversion problem, so the compiler directly prohibits such behavior. This article attempts to make a general description of Java generics.

Type Erase

The first prerequisite for a proper understanding of the generic concept is to understand type erasure ( type erasure ).

Generics in Java are basically implemented at the compiler level. In the generated Java byte code, the type information in generics is not included. When you use generics, the type parameters are removed by the compiler at compile time. This process is called type erasure. As defined in the code List<Object> and the List<String> type, after compilation will become a list. The JVM sees only the list, and the type information appended by generics is not visible to the JVM. The Java compiler will try to identify possible errors at compile time, but there is still no way to avoid a type conversion exception at run time. Type erasure is also an important difference between the generic implementation of Java and the way the C + + template mechanism is implemented. Many of the strange features of generics are related to the existence of this type of erasure, including:

A generic class does not have its own unique class object. Like it doesn't exist List<String>.class or List<Integer>.class , it's just List.class . A static variable is shared by all instances of the generic class. For MyClass<T> a class declared, the method to access the static variable is still myclass.mystaticvar. new MyClass<String>; new MyClass<Integer> A static variable is shared, either through or through the created object. A generic type parameter cannot be used in a catch statement for Java exception handling. Because exception handling is performed by the JVM at run time. Because the type information is erased, the JVM cannot distinguish between two exception types MyException<String>; and MyException<Integer> the other. For the JVM, they are all myexception types. You cannot execute a catch statement that corresponds to an exception.

The basic process of type erasure is also simple: first, find the specific class to replace the type parameter. This specific class is generally object. If the upper bound of the type parameter is specified, the upper bound is used. Replace the type parameters in the code with the specific classes. At the same time, remove the occurrence of the type declaration, that is, <> the removed content. For example: The T get() method declaration becomes Object get() ; List<String> it becomes List . Next, you may need to generate some bridging methods (bridge method). This is because the class after the erasure type may be missing some of the necessary methods. Consider the following code, for example:

Class MyString implements comparable<string> {public    int compareTo (String str) {                return 0;}        }

When the type information is erased, the declaration of the above class becomes the class MyString implements comparable. However, the class mystring will have a compile error because there is no int compareTo (Object) method that implements the comparable declaration of the interface. This method is dynamically generated by the compiler at this time.

Example analysis

Once you understand the type erase mechanism, you will understand that the compiler takes all of the type checking work. The compiler prohibits the use of some generics precisely to ensure type security. Take the above mentioned List<Object> and List<String> for example to analyze concretely:

public void Inspect (list<object> List) {for        (Object obj:list) {                System.out.println (obj);        }        List.add (1); This operation is valid in the context of the current method. }public void Test () {        list<string> STRs = new arraylist<string> ();        Inspect (STRs); Compilation Error}

In this code, the inspect method accepts List<Object> as a parameter, and a compilation error occurs when an attempt is made to test pass in List<String> the method. Assuming this is allowed, the inspect method can be used list.add(1) to add a number to the collection. Thus, in the test method's view, List<String> a Integer type of object is added to the collection it is declared as. This is obviously a violation of the principle of type safety, and will certainly be thrown at some point ClassCastException . Therefore, the compiler prohibits such behavior. The compiler will check for possible types of security issues as much as possible. A compilation error is given where it is determined to violate the relevant principles. A warning message is given when the compiler cannot determine whether the type is being used correctly.

wildcard characters and upper and lower bounds

When using a generic class, you can specify a specific type, such as List<String> declaring a specific type, String or you can use a wildcard ? to represent an unknown type, such as declaring that the List<?> element type contained in the list is unknown. Wildcard characters are actually a set of types, but the specific type is unknown. List<?>What is declared is that all types are possible. But it's List<?> not the same List<Object> . In List<Object> fact, it is determined that the List inclusion Object and its subclasses can be referenced by the time they are used Object . The List<?> type of element it contains is indeterminate. Which may or may not be included String Integer . If it contains String , it is wrong to add an Integer element of the type to it. Because the type is unknown, you cannot new ArrayList<?>() create a new object by using a ArrayList method. Because the compiler cannot know what the specific type is. However List<?> , for elements in, it is always possible Object to refer to them, because although the type is unknown, it is definitely Object its subclass. Consider the following code:

public void wildcard (list<> List) {    list.add (1);//Compilation Error}

As shown above, there is always a compile error when trying to manipulate a generic class with wildcard characters. The reason for this is that the type represented by the wildcard is unknown.

Because the List<?> elements in the can only be Object referenced, in some cases is not very convenient. In these cases, you can use the upper bound to limit the range of unknown types. List<? extends Number>the type of element that may be contained in the list is described as Number its subclass. The List<? super Number> description List contains Number its parent class. When an upper bound is introduced, the method defined in the upper bound class can be used when the type is used. For example List<? extends Number> , when visiting, you can use Number the class intValue method.

Type System

In Java, you are more familiar with the type architecture that is generated by the inheritance mechanism. Like String inheriting from Object . Depending on the Liskov substitution principle, subclasses can replace the parent class. When a reference to the object class is required, String there is no problem with passing in one of the objects. However, when you replace a subclass reference with a reference to a parent class, you need to cast the coercion type. The compiler does not guarantee that this conversion must be legal at runtime. This automatic subclass replaces the parent class's type conversion mechanism, which is also applicable for arrays. String[]can be replaced Object[] . However, the introduction of generics has a certain impact on this type of system. As mentioned above, the list cannot be replaced List<Object> .

The type system introduced after 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. The first one refers to the List<String> case where the List<Object> type parameter String is inherited from Object . The second means that the List interface inherits from the Collection interface. For this type of system, there are some rules:

The relationship of a generic class of the same type parameter depends on the inheritance architecture of the generic class itself. That List<String> is Collection<String> , the subtype, which List<String> can be replaced Collection<String> . This also applies to type declarations with upper and lower bounds. When a wildcard character is used in the type declaration of a generic class, its subtypes can be expanded separately on two dimensions. For example Collection<? extends Number> , the subtypes can be expanded on the dimension of collection, i.e., and so on, and List<? extends Number> Set<? extends Number> can be expanded on the number level, i.e., Collection<Double> and so on Collection<Integer> . So the cycle goes ArrayList<Long> on, and HashSet<Double> so is also considered as Collection<? extends Number> sub-type. If a generic class contains more than one type parameter, the above rule is applied separately for each type parameter.

After understanding the above rules, it is easy to correct the code given in the example analysis. You just have to List<Object> change it List<?> . List<String>is a List<?> subtype, so no error occurs when passing parameters.

Develop your own generic classes

A generic class is basically the same as a general Java class, except that it has more than a declared type parameter on the class and interface definitions <> . A class can have more than one type parameter, such as MyClass<X, Y, Z> . Each type parameter can specify an upper bound at the time of declaration. The declared type parameter can be the same as the normal type in the Java class as the parameter and return value of the method, or as the type of the domain and local variables. However, because of the type erasure mechanism, type parameters cannot be used to create objects or as types of static variables. Consider the correct and incorrect usage in the following generic class.

Class Classtest<x extends number, Y, z> {        private x x;        private static y y; Compile error, cannot be used in static variable public        x GetFirst () {        //correct usage                return X;        }        public void Wrong () {                Z z = new Z ();//Compile error, cannot create object        }}
Summarize

There are some basic principles that you can follow when using generics to avoid some common problems.

Avoid mixing generic classes and primitive types in your code (effective Java does not recommend using the original type in your code). For example, list and list should not be used together. This produces some compiler warnings and potential run-time exceptions. When you need to take advantage of legacy code developed prior to JDK 5 and have to do so, isolate the relevant code as much as possible. When using a generic class with wildcard characters, you need to clarify the concept of a set of types represented by wildcards. Because the specific type is unknown, many operations are not allowed. Generic classes are best not to be used with arrays. You can only create an array such as new list<?>[10], and you cannot create new list[10] like this. This limits the ability of arrays to be used, and it can cause a lot of puzzling problems. Therefore, when a function like an array is required, the collection class can be used. Do not ignore the warning messages given by the compiler.

java--generics

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.