"Getting Started with Java" DAY15 Java generics--generic wildcard characters and upper and lower bounds

Source: Internet
Author: User

The previous article describes what generics are, why generics are used, and how generics are used, and I believe you have a basic understanding of generics, and this article will continue to explain the use of generics, giving you a better grasp and a deeper understanding of generics.

After the introduction of generics in the previous article, do you feel that the generic type is very useful? Both eliminate the unsafe type of object conversion, but also can be very convenient to type Object access, but, wait, there is no consideration of such a situation.

We define a fruit class first:

 Public class Fruit {    private  String name;      Public Fruit (String name) {        this. Name = name;    }       Public String GetName () {        return  name;    }      Public void setName (String name) {        this. Name = name;    }} 

Then define an Apple class:

 Public class extends fruit{    public  Apple (String name) {        super(name);}    }

Next, define a generic container:

 public  class  genericholder<t>  { private   T    Obj  public   Genericholder () {}  public   Genericholder (T obj) { this . obj = obj;  public   T getobj () { return   obj;  public  void   Setobj (T obj) { this . obj = obj; }}

Let's start our test:

 Public classTest {/*** Eat fruit *@paramFruitholder*/     Public Static voidEatfruit (genericholder<fruit>Fruitholder) {System.out.println ("I'm eating" +fruitholder.getobj (). GetName ()); }     Public Static voidMain (String args[]) {//It's a bag labeled with fruit.Genericholder<fruit> Fruitholder =NewGenericholder<fruit>(); //This is an apple-labeled Bag .Genericholder<apple> Appholder =NewGenericholder<apple>(); //This is a fruitFruit Fruit =NewFruit ("Fruit"); //This is an appleApple Apple =NewApple ("Apple"); //now let's put the fruit in .fruitholder.setobj (fruit); //call a way to eat fruitEatfruit (Fruitholder); //a fruit-labeled bag with fruit, of course, no problem .//now let's put the fruit sub-apple into this bag and seeFruitholder.setobj (Apple); //It is also possible, in fact, this time will be automatic upward transformation, apple into the fruit type, and then passed into the Fruitholder//but it's no longer possible to assign a value to Redapple.//because the label of the bag is fruit, the object that is taken out can only be assigned to the variables of the fruit class.//failed to compile detection redapple = Fruitholder.getobj ();Eatfruit (Fruitholder); //put the Apple label, naturally only put the AppleAppholder.setobj (Apple); //I can't pass appholder into Eatfruit .//because Genericholder<fruit> and genericholder<apple> are two different kinds.//Eatfruit (appholder);    }}

Operation Result:

I'm eating the fruit I'm eating an apple

Here, when we pass the Eatfruit method into the Fuitholder, it can be compiled normally, but if the appholder is passed in, it cannot be compiled because as a parameter,genericholder<fruit> and Genericholder<apple> is two different types, so it can't be compiled, so the problem comes if I want the Eatfruit method to handle genericholder<fruit> and What about two types of genericholder<apple>? And this is also very reasonable demand, after all, Apple is a fruit subclass, can eat fruit, why not eat apples??? If you want to overload this method once, it would be a bit of a fuss (and in fact, it can't be compiled, after the specific reason will be explained).

In the logic of the Code:

    • Apple is-a fruit
    • An apple plate not-is-a a plate of fruit.

At this point, the generic boundary symbol has its niche. Let's look at the effect first:

 Public classTest {/*** Eat fruit *@paramFruitholder*/     Public Static voidEatfruit (genericholder<?extendsFruit>Fruitholder) {System.out.println ("I'm eating" +fruitholder.getobj (). GetName ()); }     Public Static voidMain (String args[]) {//It's a bag labeled with fruit.Genericholder<fruit> Fruitholder =NewGenericholder<fruit>(); //This is an apple-labeled Bag .Genericholder<apple> Appholder =NewGenericholder<apple>(); //This is a fruitFruit Fruit =NewFruit ("Fruit"); //This is an appleApple Apple =NewApple ("Apple"); //now let's put the fruit in .fruitholder.setobj (fruit); //call a way to eat fruitEatfruit (Fruitholder); //put the Apple label, naturally only put the AppleAppholder.setobj (Apple); //At this time can smoothly put Appholder into EatfruitEatfruit (Appholder); }}

Operation Result:

I'm eating the fruit I'm eating an apple

Here we just use a little bit of magic, change the parameter type to GENERICHOLDER< Extends Fruit>, so you can pass the parameters of the genericholder<apple> type smoothly, how about? Very useful, this is the generic boundary character, with < Extends fruit> in the form of an expression. The meaning of a boundary character is defined by a boundary, which is used here? Indicates that the passed-in generic type is not a fixed type, but rather conforms to all types of the rule scope, with the extends keyword defining an upper boundary, that is, here? can represent any type that inherits from the fruit, you may ask, why is the upper boundary, good question, a picture wins thousand words:

From this graph, we can see the concept of the "upper boundary" very well. There is the upper boundary, the nature has the lower boundary, the generic pattern uses the shape like < Super Fruit> the way to use the next border, at this time,? can only represent fruit and its parent class.

(these two charts are to pull over, do not scold me lazy.) )

These two methods basically solve our previous problems, but at the same time, there are certain limitations.

1. upper bound < extends t> cannot be deposited, only outward

do not be too confused, in fact, very good understanding, because the compiler only know that the container is fruit or fruit subclass, but do not know what the specific type, so when it is not possible to determine whether the type of data to be deposited with the type of container species consistent, so will be rejected   set operation.

2. Nether < Super t> can only be assigned to an object variable without affecting the

Because the compiler only knows that it is fruit or its parent class, which in fact relaxes the type limit, the parent of the fruit can be saved to objects of type object, but when taken, it can only be used as object objects.

So if you need to read out frequently, then use < Extends T> if it is necessary to take out frequently, use < Super t>.

at this point, this chapter is complete, welcome to continue to pay attention!

"Getting Started with Java" DAY15 Java generics--generic wildcard characters and upper and lower bounds

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.