Test with a knife and fly with a stupid bird

Source: Internet
Author: User

Test with a knife and fly with a stupid bird
Preface


General classes and methods can only use specific types: either basic data type or custom class.

If you want to write code that can be applied to multiple types of code, such rigid restrictions will be very restrictive to the code.

-- Think in Java


What are the benefits of generic programming?


It is hard to imagine that the requirement "can be applied to multiple types of code" exists at the beginning, because code reuse has always been a key aspect of coding.

However, it is worth noting that generic technology is available only after Java 1.5. So before that, how does Java meet the above requirements?


In fact, the answer is not hard to imagine. Of course, it is achieved through the inherited polymorphism feature: the object reference of the super class type declaration can point to any of its subclass objects.

At the same time, it is well known that any class defined in Java has a default generic class: Object class.

Naturally, if you want a piece of code to receive data of any type, the data type should naturally be defined as "Object.


The container classes in the Java Collection framework are implemented based on the generic technology, so they ensure that the container objects you define can accept any specified type of data for storage.

You already know that the collection framework was born after JDK 1.2. In Java 1.2-1.5, how does one ensure that the feature "any object type can be stored?

The answer is not surprising. Of course, it is also based on inheritance. As in the ArrayList container class at that time, only a variable array referenced by the Object type is maintained internally.


It is hard to imagine that, as in Java, the original array can store multiple data of the same data type. In subsequent upgrades, the same principle is derived from the Collection framework.

With the inherited polymorphism, the same piece of code can be applied to multiple types. Java has developed generic technology in the upgrade process, because the original design method has defects.

We can consider this as follows: if you want to write a method, the method can accept parameters that operate on any object type. Before Java 1.5, the code is like this:

public class Demo {void anyObject(Object o){//some code..}}
It is not difficult to see that using this method may cause problems.

First, because of the "dynamic binding mechanism" in Java ". Therefore, you can only call methods of the Object class in the method by passing parameters in this way.

Therefore, if you want to call the extra methods of the specific object type you pass in the method, you must involve forced type conversion-to complete "downward transformation ".

This leads to the butterfly effect: Once forced conversions of types are involved, type conversion exceptions may occur: "ClassCastException ".


The emergence of generic programming technology is precisely to make up for the defects of the above implementation methods. So the biggest benefit of generics is:

  • Reduces the complexity of the Code: avoids the trouble of using forced type conversion in the code.
  • Enhanced code security: the exception "ClassCastException" during runtime is transferred to the exception detection during compilation.


Practical Use of generics


Generic usage specifications are not complex and can be summarized:

  • Use the symbol "<>" in Java to declare the use of generics. Enclose one or more generic parameters with commas.
  • We recommend that you use a concise name to name generic parameters. It is best to avoid lowercase letters, which can be used to distinguish them from other common parameters.
  • If a generic class also contains a generic method, it is best to avoid using the same identifier for the generic type parameters of the method and the generic parameters of the class to avoid confusion.


Definition of generic classes


A generic class is a class with one or more type variables. The definition format is generally: class ClassName <T>. For example:

Package com. tsr. j2seoverstudy. generic; public class GenericClassDemo <T> {private T; GenericClassDemo (t T) {this. t = t;} public T getT () {return t;} public void setT (T t) {this. t = t;}/** output result: * generic_class * new value */public static void main (String [] args) {String genericVar = new String ("generic_class"); GenericClassDemo <String> g = new GenericClassDemo <String> (genericVar); System. out. println (g. getT (); g. setT ("new value"); System. out. println (g. getT ());}}
The usage of generic classes can be seen as follows:

In a generic class, you can use the type parameter in the class declaration as the Data Type of the member variables of the class.

As defined in the above Code: "private T ;".


This type of parameter can be specified as any object data type during the construction of this class.

In the above example, the specific type we set for it is the String type "String ". This process is "Generic instantiation ".


At the same time, methods defined in generic classes can accept and operate the type parameters declared on generic classes.

At the same time, it is worth noting that the instantiation of generics is completed when the generic classes are constructed and the objects are generated.

This also explains why a static method in a class must be defined on a generic method without being allowed to be defined on the class.

It is precisely because the generics declared on a class depend on the objects of the class to define clearly, but static methods do not depend on objects.

Next, let's take a look at the definition and use of generic methods.


Generic method definition


Generic method Definition Format: public <T> return type method name (T t T)

For the definition of generic methods, note that the generic type of methods should be placed between the method modifier and the return type of the method.

Package com. tsr. j2seoverstudy. generic; public class GenericMethodDemo {/** the output result is: * The number in the middle of the array is: 5 */public static void main (String [] args) {Integer [] nums = {1, 3, 5, 7, 9}; System. out. println ("the number in the middle of the array is:" + getMiddle (nums);} static <T> T getMiddle (T [] t) {return t [t. length/2] ;}}


The wildcard carriers in Java include: generic methods, generic classes, and generic interfaces. That is to say, in addition to classes and methods, generics can also be applied to interfaces.

However, after learning about the usage of generic interfaces in classes and methods, you should also be familiar with them.


Limits on the range of generic Variables


Sometimes, type variables are constrained as needed. In this case, the use of the generic variable range is involved.

We all know that the compareTo method under compareable can be used to compare and sort two objects.

Let's assume that we have defined the following generic method and want to give the maximum object result of comparing the compareTo method in an array:

Package com. tsr. j2seoverstudy. generic; public class GenericMethodDemo {/** output result: * The largest String element is zsda */public static void main (String [] args) {String [] strs = {"asdas", "xzvzh", "zsda", "qwe"}; System. out. println ("the largest string element is:" + getMaxElement (strs);} static <T extends Comparable <T> T getMaxElement (T [] t) {if (t = null | t. length = 0) return null; T max = t [0]; for (int I = 1; I <t. length; I ++) {if (t [I]. compareTo (max)> 0) {max = t [I] ;}} return max ;}}
We know that the most basic generic parameters can be used to accept any object data type.

However, in the above example, we want to use the compareTo Method for object comparison.

The compareTo method is the class object that implements the Comparable interface.

Therefore, we must make a constraint on declared generics: the specified data type must implement the Comparable interface.

This is the so-called: generic parameter range Limitation.


In the above Code, "<T extends Comparable <T>" is a method used to limit the generic range.

You may notice that here we use extends, a keyword originally used to indicate the inheritance relationship of the class in Java, to specify that the generic must implement the Comparable interface.

No. In generics, the declared type parameter inherits from a class or implements an interface, which is represented by extends.

This limitation is often referred to as the upper limit of generics. The format is: <extends upper limit of the generic type parameter>.


Note: If the declared generic type implements multiple interfaces, multiple interfaces in the upper limit are separated by the symbol.

If the declared type parameter inherits from a class and multiple interfaces are implemented at the same time, the inherited class must be declared as the first in the upper limit.


Since there is a limit on generics, it is not hard to imagine that there must be a corresponding lower limit: generics. The limitation is as follows: <super lower limit of the generic type parameter>.

The limitation of the lower limit indicates that this generic parameter can be instantiated by all the super classes of the lower limit type in addition to at least the declared lower limit type.

For example, there are three custom categories: Animal, tiger, and northeast tiger. The inheritance relationship between them is: the Northeast Tiger inherits from the tiger. The tiger inherits automatic things.

If "<T super tiger>" is used, it indicates that the generic parameter T can be instantiated as a tiger or an animal, but cannot be instantiated as a northeast tiger.


Generic Erasure


Generic erasure means that when the program passes through the compiler and enters the runtime, the generic type will be removed from the JVM. This process is called generic erasure.

The reason for generic erasure is that generics are only supported by Java compilers. Virtual machines do not know generics.

Therefore, when a Java program uses generic technology, it first checks the compiler during the compilation period to determine whether there is a type conversion problem.

When the compilation is passed, the program is switched to the runtime. In the virtual machine responsible for Java program running, the generic type is erased.


Generic erasure refers to restoring the defined generic type to its original type (raw type ). The restoration process is determined based on the limited type of the generic type:

  • If the type parameter of the specified type is not declared, it will be restored to: Object.

When we talk about the definition of generic classes, the restoration method of the examples used is as follows:

// Before generic erasure, public class GenericClassDemo <T> {private T t; GenericClassDemo (T t) {this. t = t ;}// public class GenericClassDemo {private Object o; GenericClassDemo (Object o) {this. o = o ;}}

  • If there is a limit on the generic type, the original type is replaced by the first type variable.

For example:

// Public class GerericDemo <T extends Comparable <T> & Serializable> {private T; GerericDemo (t T) {this. t = t ;}// public class GerericDemo implements Serializable {private Comparable t; GerericDemo (Comparable t) {this. t = t ;}}

So we can see that the so-called generic technology will eventually involve forced conversions of types. However, the difference is that the forced conversion after the generic type is used is safe!

This is because we have ensured data type consistency during compilation. If you use a data type other than the specified generic type, the program cannot be compiled.


Now, let's take a look at the above-mentioned example: "What does the generic type refer to when the runtime exception" ClassCastException "is transferred to the compilation stage?

Take the container ArrayList as an example. If you do not use the generic technology, assume that the following method is used:

package com.tsr.j2seoverstudy.generic;import java.util.ArrayList;public class GerericDemo{    public static void main(String[] args) {ArrayList list = new ArrayList();list.add(new String());list.add(new Integer(5));for (int i = 0; i < list.size(); i++) {String value = (String)list.get(0);}}}

The above code compilation will not cause any problems, but once it is run, it will report the runtime exception: java. lang. Integer cannot be cast to java. lang. String

This is because there is no limit to generics. ArrayList itself accepts any data of the Object type inherited from the Object class.

Because of the inheritance feature, it is no problem to store the two defined objects of the String and Integer types into the list container, because they will all complete an "upward transformation ".

But it is precisely because after the "upward transformation" is completed, they are actually stored in the list container, and their types are already the Object type.

So when we want to extract a specific type, we must perform "downward transformation", that is, force type conversion.

However, the Integer type itself cannot be forcibly converted to the Strring type, which leads to a type conversion exception.


When the container class is added with the generic technology, the code changes:

Public class GerericDemo {public static void main (String [] args) {ArrayList <String> list = new ArrayList <String> (); list. add (new String (); list. add (new Integer (5); // compilation error due to the appearance of generics! For (int I = 0; I <list. size (); I ++) {// you do not need to forcibly convert String value = list. get (I );}}}
When constructing a generic class, you must specify a specific type for the type parameter, that is, instantiate the generic parameter.

Therefore, when we specify the type as <String>, the compilation error will occur if we want to add an Integer type object to the container.

At the same time, because the compiler already knows the Data Type stored in the container memory as String, it does not need to perform strong conversion when extracting data.


Wildcard


The wildcard character in Java is "?". As the name suggests, that is, any object data type can be matched.

The main usage is as follows:

Package com. tsr. j2seoverstudy. generic; public class Animal <T> {private T; Animal (t T) {this. t = t ;}public T getT () {return t ;}} class Tiger {@ Overridepublic String toString () {return "";}} class Bird {@ Overridepublic String toString () {return" ";}}

Suppose we want to define a tool class for outputting animal information. If there is no wildcard character, it is actually quite uncomfortable to use it:

package com.tsr.j2seoverstudy.generic;public class GerericDemo {   public static void main(String[] args) {Animal<Tiger> tiger =  new Animal<Tiger>(new Tiger());Animal<Bird> bird =  new Animal<Bird>(new Bird());printTiger(tiger);printBird(bird);}static void printTiger(Animal<Tiger> animal){System.out.println(animal.getT());}static void printBird(Animal<Bird> animal){    System.out.println(animal.getT());}}
As we have already said, when constructing a generic class, you must specify the specific type of the type parameter. Therefore, you can only achieve your needs in this bulky way.

However, using wildcards makes coding much easier:

public class GerericDemo {   public static void main(String[] args) {Animal<Tiger> tiger =  new Animal<Tiger>(new Tiger());Animal<Bird> bird =  new Animal<Bird>(new Bird());printAnimal(tiger);printAnimal(bird);}static void printAnimal(Animal<?> animal){System.out.println(animal.getT());}}
In addition, wildcard wildcards can also be used to limit the upper limit and lower limit of a wildcard type.


Finally, take a note. Note the following error:

static void printAnimal(Animal<Tiger> animal){System.out.println(animal.getT());}static void printAnimal(Animal<Bird> animal){System.out.println(animal.getT());}
You must know that this writing method will cause compilation failure, rather than taking it as an overload through different parameter types.

Generic erasure !!! Do not forget this job. After the code above is erased by generics, it actually becomes two identical method declarations, which naturally cannot be compiled.


Summary


At this point, the application of generic programming in Java is basically a comprehensive and detailed summary.

If you want to continue, you may need to use some books and materials to study the principle of generics and knowledge about Java virtual machines.

I personally feel that the underlying principle of generic erasure is still very complicated. It takes some effort to master it in depth.

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.