Consolidate one of the basics of JAVA-extensive explanation (2)

Source: Internet
Author: User
Tags class manager

Consolidate one of the basics of JAVA-extensive explanation (2)

I am used to being boiled in warm water. I never dare to try what I dream of. What if I fail? I can start from scratch at most.
 

 

Related Articles:

1. consolidate one of the basics of JAVA-generic details (1)
2. consolidate one of the basics of JAVA-generic details (2)


The previous article will give you a preliminary explanation of the various application environments of generic variables. This article will give a more in-depth explanation of the Type Binding and wildcard knowledge.

 

I. Type Binding 1. Introduce a new generic type written in the previous article:

 

 

Class Point
 
  
{Private T x; // indicates the X coordinate private T y; // indicates the Y coordinate public void setX (T x) {this. x = x;} public void setY (T y) {this. y = y;} public T getX () {return this. x;} public T getY () {return this. y ;}} // use Point
  
   
P1 = new Point
   
    
(); P1.setX (new Integer (100); System. out. println (p1.getX ());
   
  
 
First, we need to know that any generic variables (such as T here) are derived from objects. Therefore, when we fill in generic variables, we can only use classes derived from objects, for example, String, Integer, Double, and so on, but cannot use the original variable type, such as int, double, float.
Then, the problem arises. Internally, which functions can be called using the generic-defined variable T x?
private T x;  
Of course, only functions of the Object can be called, because the compiler does not know exactly what type T is. The Compiler only knows what type the user gives at runtime. The only thing the compiler can determine is that no matter what type is derived from the Object, T must be a subclass of the Object, so T can call the Object method.
The problem arises again. If I want to write a generic class that finds the minimum value, but I don't know what type the user will upload, I need to write an interface, let the user implement this interface from the size of the type that has been passed by the user.
The interface is as follows:
public interface Comparable
  
   {    public boolean compareTo(T i);}
  
However, if we directly use the T instance to call the compareTo () function, an error is reported. The compiler is as follows:

 

This is because the compiler cannot know that T is a function inherited from the Comparable interface. So how can we let the compiler know that T inherits the type of the Comparable interface?
This is the role of Type binding.

2. Type Binding: extends (1) Definition
Sometimes, you want the generic type to be only a certain part of the type. For example, when operating data, you want to be a Number or its subclass type. The idea is to add a boundary for generic parameters. Its definition form is:

 

 

  
This definition indicates that T is the subtype of BoundingType ). T and BoundingType can be classes or interfaces. In addition, the Child type represented by "extends" here is not the same as inheritance.
It must be noted that the extends here is not the extends in class inheritance! There is no association between the two. Here, the BoundingType after extends can be a class or an interface, meaning that T is created based on BoundingType and has the BoundingType function. Visual testing is a JAVA developer who does not want to introduce another keyword, so it is replaced by existing extends.
(2) instance: Binding Interface
Similarly, we also use the above comparison interface for example.
First, let's look at the min function after the extends limit is added:
Public interface Comparable
  
   
{Public boolean compareTo (T I);} // After the extends Comparable is added, the public static function can be added to the Comparable.
   
    
T min (T... a) {T smallest = a [0]; for (T item: a) {if (smallest. compareTo (item) {smallest = item ;}} return smallest ;}
   
  
This code is used to call the compareTo () function of the item based on the T-type array a passed in, and compare it with each item to find the minimum value.
From this code, we can also see that type binding has two functions: 1. Limit the filled generic type; 2. Use the internal functions of BoundingType when using the generic variable T.
Note that in this sentence, smallest. compareTo (item), smallest, and item are all T-type, that is, compareTo is compared to the same type.
Then we implement a class derived from the Comparable interface:
public class StringCompare implements Comparable
  
    {    private String mStr;    public StringCompare(String string){        this.mStr = string;    }    @Override    public  boolean compareTo(StringCompare str) {        if (mStr.length() > str.mStr.length()){            return true;        }        return false;    }}
  
In this Code, you may wonder why T is also filled into the StringCompare type. Remember what we mentioned above: smallest. compareTo (item), smallest and item are of the same type !! Therefore, the compareTo parameter must be of the same type as the caller, so fill T with StringCompare;
In this Code, compareTo is implemented to compare the length of the current mstr with the length of the mstr passed in instance. If it exceeds the length, true is returned; otherwise, false is returned;
Finally, use the min function:
StringCompare result = min(new  StringCompare(123),new StringCompare(234),new StringCompare(59897));Log.d(TAG,min:+result.mStr);
The result is as follows:

 

Here is the extends interface. As we mentioned at the beginning, extends indicates binding. The BindingType can be an interface or a class. Next we will give an example of binding a class.

The source code is provided at the bottom of the article.

 

(3) instance: Binding class
Let's assume that we have many types of fruits, and we need to write a function to print the name of the filled fruit:
Therefore, we first create a base class to set and extract names:

 

class Fruit {    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}
Then write a generic function to extract the name:
public static 
  
    String getFruitName(T t){    return t.getName();}
  
Here, the usage of generic functions comes out. Because we know that fruits will inherit the Fruit base class, we use You can limit that the filled variable must be derived from the Fruit subclass. First, in T, we can use the Fruit class method and function. Second, if the class you enter is not derived from Fruit, the compiler will report an error.
Then, we create two classes derived from Fruit and fill in their own names:
class Banana extends Fruit{    public Banana(){        setName(bababa);    }}class Apple extends Fruit{    public Apple(){        setName(apple);    }}
Last call:
String name_1 = getFruitName(new Banana());String name_2 = getFruitName(new Apple());Log.d(TAG,name_1);Log.d(TAG,name_2);
The result is as follows:

 

 

The source code is provided at the bottom of the article. (4) bind multiple limits
As we have discussed above, we can bind multiple bindings at the same time to use & connections, for example:

 

 

public static 
   
     String getFruitName(T t){    return t.getName();}
   
Further, the difficulty will be solved. If we have multiple generics and each of them is bound, what should we look like:
public static 
   
     T foo(T a, U b){…………}
   
Let's take a look. Here we have two generic variables T and U, which bind T with Comparable & Serializable and bind U with Runnable.
Okay, this part is over. Next we will talk about the usage of wildcards.
2. wildcard Wildcards are a very troublesome feature. It is difficult to understand and grasp them. I will try my best to understand the differences and usage between them and generic variables.
1. Introduce and review the Point generic definition used in the previous article:
class Point
   
     {    private T x;          private T y;              public Point(){            }    public Point(T x,T y){        this.x = x;        this.y = y;    }    public void setX(T x) {        this.x = x;    }    public void setY(T y) {        this.y = y;    }    public T getX() {        return this.x;    }    public T getY() {        return this.y;    }}
   
This code is very simple. A generic variable T is introduced, and then there are two constructors. Finally, the set and get methods are used to set and obtain the values of x and y respectively. This code is not difficult and I will not elaborate on it.
Let's take a look at the following code:
Point
   
     integerPoint = new Point
    
     (3,3);…………Point
     
       floatPoint = new Point
      
       (4.3f,4.3f);…………Point
       
         doublePoint = new Point
        
         (4.3d,4.90d);…………Point
         
           longPoint = new Point
          
           (12l,23l);…………
          
         
        
       
      
     
    
   
In this Code, we use Point Four instances are generated: integerPoint, floatPoint, doublePoint, and longPoint;
Here, four instances are generated, and four names are required. What if we want to generate ten different types of instances? You cannot think of ten names.
Simply thinking about a name is a thing (in fact, I don't think it's a big thing ...... T _ T. No way. I can't think of a better example ...... )
Is there a way to generate a variable that can assign values to different types of instances?
2. borderless wildcard :? (1) Overview
Let's not talk about what the borderless wildcard is. Let's take the above example and see if we implement it like this:
Point
     point;point = new Point
    
     (3,3);point = new Point
     
      (4.3f,4.3f);point = new Point
      
       (4.3d,4.90d);point = new Point
       
        (12l,23l);
       
      
     
    
Here, we first use the following code to generate a point instance. Note that when filling the generic type, what is used?
Point
     point;
Then, all types of Point instances can be assigned to the point:
point = new Point
    
     (3,3);point = new Point
     
      (4.3f,4.3f);point = new Point
      
       (4.3d,4.90d);point = new Point
       
        (12l,23l);
       
      
     
    
Here? Is the borderless wildcard. A wildcard is an unknown symbol and can represent any class.
Therefore, you may understand that the wildcard variable T is not only a numerical value here. In fact, any Point instance can be passed to the point: for example, the Point (), Point () Is acceptable.

 

(2 ),? Difference from T
You may be wondering, what is the borderless wildcard? What is the difference between it and generic variable T?
The answer is: they have no contact !!!!!
Generic variable T cannot be used to create variables in code. It can only be used after being declared in classes, interfaces, and functions.
For example:

 

public class Box
      
        {   public T get(){   …………   };   public void put(T element){   …………   };}
      
But does not have a boundary wildcard? It can only be used to fill in the generic variable T, indicating that all types are available !!!! Repeat it again :? It can only be used to fill in the generic variable T. It is used to fill T !!!! It's just a filling method !!!
For example:
// Enter the Box without the boundary wildcard
      Box; // other types of filled Box
      
       
StringBox;
      
(3) wildcards can only be used to fill in generic variables T, and cannot be used to define variables
You must remember that the wildcard is only used in the following locations:
Box
       box;box = new Box
      
       ();
      
That is, the position where the wildcard variable T is filled cannot appear in the String behind it !!!!
The third and fourth rows below are all incorrect. Wildcards cannot be used to define variables.

 

Emphasize again ,? Can only appear in the Box Box;, other locations are incorrect.

 

3. What are the wildcards? Extends binding (1) Overview
Can we know the wildcard from above? It can represent any type, but it is the same as the generic type. If it is not limited, the compiler may not report an error in later use. So we should also, right? .
The binding format is also through the extends keyword. The meaning and usage are consistent with those of generic variables.
Similarly For example, if the value of a Point is a numeric value in an instance, it is incorrect to enter the generic variable T as the Object type or String type.
So we need Point: only the value type can be assigned to the point;
We changed the code to the following method:

 

We add a limit to the wildcard: Point Point;
In this case, when T is filled with String and Object in the last two rows, an error will be returned if the value is assigned to point!
Although this refers to any type derived from Number, but you have noticed that the new Point (); Can also be assigned successfully, which indicates that the boundary itself is included.
Repeat it again: the borderless wildcard is only the filling method of the generic T. It is limited to the instance type assigned to it (for example, the point here.
If you want to fundamentally solve the problem of Point population, you need to add :

 

Class Point
       
        
{Private T x; // indicates the X coordinate private T y; // indicates the Y coordinate ............}
       
(2) Note: Use Defined variables. Only values can be obtained and cannot be modified.
See the following code:

 

It is obvious in point. setX (Integer (122); a compilation error is returned. However, point. getX () does not return an error.
Why?
First, the type of the point is Not because point = new Point. (3, 3); change the type.
Even if point = new Point (3, 3); after that, the point type is still , That is, the unknown type derived from the Number class !!! This is easy to understand. (3, 3); after that, point becomes a Point Type, point = new Point (12l, 23l); During the operation, the compilation error is certainly reported because the type does not match. This is because the type of the point is always And can be assigned to instances of various types.
Back to the topic, let's talk about why assignment is not allowed.
Because the type of the point is Point Point, that is, the generic variable T that fills the Point is What type is this? Unknown type !!! How can I set an internal value with an unknown type! This is totally unreasonable.
However, because the generic variable T is filled So the compiler can determine that T must be a subclass of Number, and the compiler will use Number to fill T
That is to say, the compiler only needs to determine the type of the wildcard. If the type of the wildcard cannot be determined, an error is returned.

 

4. What are the wildcards? Super binding (1) Overview
If If the padding is any subclass derived from XXX It indicates filling in the parent class of any XXX!
We will first write three types: Employee, Manager, and CEO, representing workers, managers, and CEOs respectively.
Here, Manager is derived from Employee, and CEO is derived from Manager. The Code is as follows:

 

 

class CEO extends Manager {}class Manager extends Employee {}class Employee {}
Then, if I generate a variable like this:
 List
        list;
It indicates filling the generic T , That is, the parent class of the Manager; that is, the List The generic variable T in is filled with the List variable of the Manager parent class and can be assigned to the list;

 

From the code above, we can see that new ArrayList (), New ArrayList () Is correct, while new ArrayList () But an error is reported, of course, because the CEO class is no longer the parent class of Manager. Therefore, a compilation error is reported.
Note that the new ArrayList is displayed in the code. () Can be successfully assigned to the List List. It can be seen that the super keyword also contains boundaries. That is, instances assembled by the boundary type (Manager) can still be assigned a value.
(2) super wildcard instance content: it cannot be stored
As we mentioned above, the extends wildcard can be retrieved and cannot be stored. What about the super wildcard? Let's try:

First read the saved part:

 

List
        List; list = new ArrayList
        
         
(); // Save list. add (new Employee (); // compilation Error list. add (new Manager (); list. add (new CEO ());
        
First, you must declare In point, the type of a point is The same is that the list type is also determined by the List ; The list item type is always That is, any parent class of the Manager class, that is, it may be Employee or Object.
You may wonder why these two are correct! The list. add (new Employee () is incorrect!
list.add(new Manager());list.add(new CEO());
Because the item type in the list is That is, any parent class of the Manager. If it is Employee, you can understand the following code:
List
        
          list = new ArrayList
         
          ();list.add(new Manager());list.add(new CEO());
         
        
Here, because the Manager and CEO are both the parent classes of the Employee, after being passed into list. add (), they will be forcibly converted to the Employee!
Now let's look back at this:
List
        List; list = new ArrayList
        
         
(); // Save list. add (new Employee (); // compilation Error list. add (new Manager (); list. add (new CEO ());
        
The compiler cannot determine But the only thing that can be determined is that Manager () and CEO () must be So it can be added. But the Employee is not necessarily So it is uncertain and uncertain. It is definitely not allowed, so a compilation error will be reported.
Finally, let's take a look:

 

In this Code, Object object = list. get (0); no error is reported, while Employee employee = list. get (0); an error is returned;
We know that the item type in the list is Which compiler is sure? It must be the parent class of the Manger, but it cannot be determined whether it is an Object or an Employee type. However, whether it is an Object or an Employee, it must be a subclass of the Object!
Therefore, Object object = list. get (0); no error is reported. Because list. get (0); must be a subclass of the Object;
However, the compiler cannot determine whether list. get (0) is of the Employee type. Therefore, the system reports an error for Employee employee = list. get (0.
Although it seems that an Object can be retrieved, it is meaningless to obtain an Object type. Therefore, we think that the super wildcard can be saved but cannot be obtained;

5. What are the wildcards? Summary

 

Summary? Extends and? The features of the super wildcard can be concluded as follows:
◆ If you want to obtain data from a data type, use? Extends wildcard (optional)
◆ If you want to write an object into a data structure, use? Super wildcard (not available for storage)
◆ If you want to store and retrieve data, do not use wildcards.


Well, I am exhausted. This part is really too difficult to talk about. I will not talk about wildcard capturing and compiler type erasure. It is basically not used in actual projects, if you are interested, you can add them on your own.
Next I will introduce reflection to you.

 

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.