Java programming thought Lesson (iii) 15th-generics

Source: Internet
Author: User

The concept of generics (generics) is one of the major changes in Java SE5. Generics implement the concept of parameterized types (parameterized types) so that code can be applied to multiple types. The term "generics" means: "Applies to many many types".

1 Generic methods

The generic method is not in relation to the class in which it resides, that is, the class in which the generic method resides is a generic class or it can not be a generic class.

    • A generic method enables the method to change independently of the class.

    • A basic guideline: whenever you can do it, you should try to use a generic method. That is, if you use a generic method to replace the entire class with generics, you should only use a generic method, because it makes things clearer.

    • For a static method, the type parameters of a generic class cannot be accessed, so if the static method needs to use generic capabilities, it must be made a generic method.

    • To define a generic method, simply place the generic parameter list before the return value.

1.1 Type parameter Inference

When using a generic method, it is usually not necessary to indicate the parameter type, because the compiler will find the specific type for us. This is called type parameter inference (type argument inference).

    • type inference is only valid for assignment operations .

    • If you pass the result of a generic method call as an argument to another method, the compiler does not perform type inference .

1.1.1 Explicit Type Descriptions

Insert angle brackets between the point operator and the method name, and then place the type inside the angle brackets, which is the explicit type description .

2 The Mystery of erasing

Based on the description of the Class.getTypeParameters() jdk document, " TypeVariable Returns an array of objects representing the type parameters of the generic declaration ...", which seems to imply that you may find information about the parameter types, but, as you can see from the output, you are able to find just the parameter placeholder identifier , which is not useful information.

So the brutal reality is that you can't get any information about generic parameter types inside generic code .

So you can know information such as generic parameter identifiers and generic type boundaries -you don't know the actual type parameters that create a particular instance. ..., it is the most basic problem that must be handled when working with Java generics.

Java generics are implemented using erase , which means that when you use generics, any specific type information is erased, and the only thing you know is that you are using an object . So List<String> and List<Integer> at run time is actually the same type . Both of these forms are erased into their " native" type , i.e. List .

How to 2.1 C + +

2.1.1 The following examples of C + + templates:

How does it know that f() the method exists for the type parameter T? When you instantiate This template, the C + + compiler checks, so at the Manipulator<HasF> moment it is instantiated , it sees HasF a method f() . If this is not the case, you will get a compile-time error so that type safety is guaranteed .

Templates.cpp#include <iostream>using namespace Std;template<class t> class manipulator{    T obj; Public:    Manipulator (T x) {obj = x;}    void manipulate () {obj.f ();}}; Class Hasf{public:    void F () {cout << "hasf::f ()" << Endl;}}; int main () {    hasf hf;    manipulator

2.1.2 translated into Java, will not compile.

Because of the erase, the Java compiler cannot manipulate () must be able to raise the requirement of f () on obj to map to the fact that HASF owns F ().

2.2 Generic boundaries

To invoke F (), we must assist the generic class, given the bounds of the generic class , to tell the compiler to accept only types that follow this boundary . Because of the boundary, the following code can be compiled.

Package net.mrliuli.generics.erase;/** * Created by Li.liu on 2017/12/7. *//** * Due to Erasure, the Java compiler is unable to map manipulate () to the fact that HASF has F () in the need to be able to raise the F () in obj. * @param <T> */class manipulator<t>{    private T obj;    Public manipulator (T x) {obj = x;}    Error:cannot Resolve method ' F () '    //public Void manipulate () {obj.f ();}} /** * In order to invoke F (), we must assist the generic class, given the bounds of the generic class, to tell the compiler to accept only types that follow this boundary. Because of the boundary, the following code can be compiled. * @param <T> */class manipulator2<t extends hasf>{    private T obj;    Public Manipulator2 (T x) {obj = x;}    public void Manipulate () {obj.f ();}} public class Manipulation {public    static void Main (string[] args) {        hasf HF = new hasf ();        manipulator

2.3 Erase

We say that the generic type parameter will erase to its first boundary (it may have multiple boundaries), and we also mention the erasure of the type parameter . The compiler will actually replace the type parameter with its erase, just like the example above. Erased, as if it were replaced in the declaration of the class T . HasF HasF T

2.4 Issues with erasing

The core motivation for erasing is that it allows generalized clients to use non-generalized class libraries, and vice versa, which is often referred to as migration compatibility .

Thus, the main justification for Erasure is the transition from non-generalized code to generalized code, and the inclusion of generics in the Java language without destroying existing class libraries.

The erased code is significant.

If you write code such as the following:

Class foo<t>{T var;}

So it looks as if you were creating Foo an instance:

foo<cat> f = new foo<cat> ();
    • class FooThe code in should know that it is now working Cat , and the generic syntax strongly implies that type T is being replaced everywhere in the class. But this is not the case , and whenever you write this class of code, you must remind yourself: " No, it's just an object." ”

    • Erase and migration compatibility means that using generics is not mandatory.

Class Genericbase<t>{}class derived1<t> extends Genericbase<t>{}class Derived2 extends genericbase{ }//No warning

2.5 Actions at the border

    • Even if the erase removes information about the actual type inside a method or class, the compiler can still ensure internal consistency of the type used in the method or class.

    • Because the erase removes type information from the method body , the problem at run time is the boundary : The place where the object enters and leaves the method . These are the places where the compiler performs type checking at compile time and inserts transformation code .

    • All actions in generics occur at the boundary--additional compile-time checks on the values passed in, and the transformation of values passed in. This helps to clarify the confusion about erasing, and remember, "the boundary is where the action occurs ." ”

3 Erase compensation (compensating for Erasure)

It is sometimes necessary to compensate for erasure by introducing a type tag (compensating). This means that you need to display the class object of your type, so that you can use it in a type expression.

    • Create a Type instance

    • Generic array

4 borders (bound)

    • Boundaries allow you to set restrictions on the type of parameters used for generics. While this allows you to enforce the types that generics can apply, a more significant potential effect is that you can invoke methods according to your own boundary type .

    • Because erase removes type information, methods that can be called with unbounded generic parameters are just those that can be called with object.

    • However, if you can limit this parameter to a subset of a type, you can use these subset of types to invoke the method.

    • wildcard characters are limited to a single boundary .

5 wildcard characters (wildcards)

    • A special behavior of arrays
      You can assign an array of subtypes to an array reference of a base type. The compile -time array element can then place elements of the base type and its subtypes, that is, compile without error , but the runtime array mechanism knows that the actual array type is a subclass, Therefore, at run time, the placed type is checked for the actual type and its re-exported subtype, not java.lang.ArrayStoreException the exception is thrown.

    • Types of containers and types of containers held

Compile error:incompatible types:list<fruit> List = new arraylist<apple> ();

Unlike arrays, generics do not have built-in covariant types. That is, covariance has no effect on generics .

Package Net.mrliuli.generics.wildcards;import java.util.*;/** * Created by Leon on 2017/12/8. */public class Genericsandcovariance {public    static void Main (string[] args) {        //Compile error:incompatible Typ es:        //list<fruit> List = new arraylist<apple> ();        Wildcards allow covariance:        list<? extends fruit> flists = new arraylist<apple> ();        But, the compiler does not know what type of object flists holds. In fact, the above statement makes an upward transition, losing the ability to pass any object to the list, or even passing an object.        //flists.add (New Apple ());        Flists.add (New Fruit ());        Flists.add (New Object ());        Flists.add (null);   Legal but uninteresting        //We know the It returns at least Fruit:        Fruit f = flists.get (0);}    }

5.1 How clever the compiler is

    • For List<? extends Fruit> , the set() method cannot work on Apple and Fruit because the parameters of set () are also ? extends Furit , which means that it can be anything , and the compiler cannot verify the type safety of "anything".

    • However, the equals() method works fine because it accepts an object type instead of a parameter of type T. Therefore, the compiler focuses only on the types of objects passed in and to be returned , and it does not parse the code to see if any actual write and read operations have been performed.

5.2 Inversion (contravariance)

    • Use super-type wildcard characters . Declaring a wildcard is defined by any base class of a particular class, by specifying <? super MyClass> , or even using, a type parameter:. <? super T> This allows you to safely pass a type object into a generic type.

    • The parameter apples is a list of some of Apple's base types, so you know that it's safe to add apple or Apple subtypes to it.

Package Net.mrliuli.generics.wildcards;import java.util.*;p ublic class Supertypewildcards {    /**     * The super-type wildcard makes it possible to write to a generic container. The hyper-type boundary relaxes the restrictions on the parameters that can be passed to the method.     * @param apples    parameter apples is a list of Apple's base types, so you know it's safe to add apple or Apple subtypes to it.     */    static void WriteTo (LIST<? Super Apple> apples) {        apples.add (new Apple ());        Apples.add (New Jonathan ());        Apples.add (New Fruit ());    Error    }}
    • Genericwriting.java in the writeExact(fruitList, new Apple()); JDK1.7 without error, indicating that the generic method is writeExact() T recognized as Fruit , the book said an error, it is possible JDK1.5 will be T identified as Apple .

Package Net.mrliuli.generics.wildcards;import java.util.*;/** * Created by Li.liu on 2017/12/8. */public class Genericwriting {    static <T> void Writeexact (list<t> List, T item) {        List.add (item); c2/>}    static list<apple> applelist = new arraylist<apple> ();    static list<fruit> fruitlist = new arraylist<fruit> ();    static void F1 () {        writeexact (applelist, New Apple ());        Writeexact (fruitlist, New Apple ());    }    static <T> void Writewithwildcard (list<? super t> List, T item) {        List.add (item);    }    static void F2 () {        Writewithwildcard (applelist, New Apple ());        Writewithwildcard (fruitlist, New Apple ());    }    public static void Main (string[] args) {        f1 ();        F2 ();    }}

5.3 Unbounded wildcard character (unbounded wildcards)

Native generics Holder andHolder<?>

The native Holder will hold any combination of types, and Holder<?> will hold a homogeneous set with a specific type , and therefore cannot simply pass object to it.

5.4 Capture transformation

The following example, known as a capture transformation , is not specified because the wildcard type is captured and is converted to the exact type. The parameter type is f2() captured during invocation, so it can be used in a f1() call to a pair.

Package net.mrliuli.generics.wildcards;/** * Created by Leon on 2017/12/9. */public class Captureconversion {    static <T> void F1 (holder<t> Holder) {        T t = holder.get ();        System.out.println (T.getclass (). Getsimplename ());    }    static void F2 (Holder<?> Holder) {        F1 (Holder);     Call with captured type    } public    static void Main (string[] args) {        Holder raw = new Holder<integer> (1) ;        F1 (raw);        F2 (raw);        Holder rawbasic = new Holder ();        Rawbasic.set (New Object ());        F2 (rawbasic);        holder<?> wildcarded = new Holder<double> (1.0);        F2 (wildcarded);    }}

6 questions

    • The base type cannot be a type parameter

    • Because of exploration, a class cannot implement two variants of the same generic interface

    • Because of the erase, overloaded methods through generics will produce the same signature, compile error, cannot implement overloading

    • The base class hijacked the interface

7 Summary

I believe that the common language features called generics, which do not have to be specific implementations in Java, are intended to be expressive , not just to create type-safe containers. A type-safe container is a side effect of the ability to create more generic code.

Generics, as its name implies: it is a way to write more "generalized" code that has fewer restrictions on the types they can work with, so a single piece of code can be applied to more types .

Related articles:

Java Programming thought Learning Lesson (i): 1th to 13th, 16 chapters

Java programming thought Lesson (ii) Chapter 14th-type information

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.