• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Paul Clapham
  • Rob Spoor
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Junilu Lacar
  • Tim Cooke
Saloon Keepers:
  • Tim Holloway
  • Piet Souris
  • Stephan van Hulst
  • Tim Moores
  • Carey Brown
Bartenders:
  • Frits Walraven
  • Himai Minh

Purpose of Upper-Bounded Wildcards Immutability

 
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Referencing this code:

2: static class Sparrow extends Bird { }
3: static class Bird { }
4:
5: public static void main(String[] args) {
6: List<? extends Bird> birds = new ArrayList<Bird>();
7: birds.add(new Sparrow()); // DOES NOT COMPILE
8: birds.add(new Bird()); // DOES NOT COMPILE
9: }

My question is what is the purpose of the collection being immutable when assigned to a bounded reference(Upper-Bound),
when this code can do what it prevents:

List<Bird> birds1 = new ArrayList<>();
birds1.add(new Sparrow());
birds1.add(new Bird());
List<? extends Bird> birds2 = birds1;
//birds2.add(new Sparrow());
//birds2.add(new Bird());

(Removing the comment will cause a compiler error)
 
Kertes Gray
Greenhorn
Posts: 3
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think the code below should cause a compiler error as well.
 
Bartender
Posts: 1059
33
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Shortest answer:
List<? extends Bird> myListRefVar

declares a reference variable that can have a List of literally any sub-type of Bird assigned to it at any time.

Had you said:
List<Bird> myOtherListRefVar

solely and only Lists with the exact precise parameterized type of Bird itself could be assigned to it.  No List<Sparrow> no ArrayList<Chickadee>, no LinkedList<Dodo>

Much longer answer?

I beat this to death while I was studying it, asking many questions and getting many patient answers.
They are fairly recent, but not this week's, threads on Java in General.

There are both differences in what List objects can be assigned to the reference variable as well as what you can then do with them once they are referenced.

 
Jesse Silverman
Bartender
Posts: 1059
33
Eclipse IDE Postgres Database C++ Java
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


I think I see an answer to the "Meaning of Life" (Purpose Of) question here, that I didn't a moment ago.

The whole and entire point of Java Generics is to increase Compile-Time Type Safety.

Why can you add those to birds1 but not using birds2?

In birds1.add() calls, the compiler is aware that it is a List that can for sure hold any Bird sub-type, including Bird just fine.  So everything is cool and that compiles.

In birds2.add( ) calls, even if you think you can look at the code and say "Hey, well, looking at that I know that I really have a List<Bird>, so these .add() calls are fine" the compiler is not permitted to do so.
It only knows that it is a List< something which is either Bird or some subtype of Bird > it can not, from just knowing the declared type of birds2, which is all it is allowed to look at to decide, know if birds2 is actually in reality a List<Turkey> an ArrayList<Hawk> or a LinkedList<BlueJay>.  It therefore would violate compile-time safety to allow those lines to compile.
And the Whole Point of Java Generics is to provide as much compile-time type safety as they could shoehorn in at the point they were added without breaking the first 9 or 10 years of programs out there (which was already countless millions).

So the answer is Compile-Time Type Safety combined with "the compiler doesn't analyze the entire possible flow of your program code, and must make the decision of whether things compile or not based solely upon your compile-time declared types of things, not make any inferences based on the possible code flow".
EDIT--stupid typo correction not affecting meaning.
 
Sheriff
Posts: 9687
42
Android Google Web Toolkit Hibernate IntelliJ IDE Spring Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
To add to Jesse's excellent explanation, the purpose of such a list is to get objects from it and perform operations on them which all birds can do. So for example


So as you can see, you can loop over the List<? extends Bird> and feed all the birds.

It is not that the List<? extends Bird> is immutable, but no parameter you pass to the add method will be allowed by compiler. The main difference lies in the declaration of the add and get methods.

For a List<? extends Bird> the get method returns <? extends Bird> you don't know exactly what it returns but it will be either Bird or Nightingale or some other sub-class of Bird so you can always be sure it is assignable to Bird. <br /> But for the add method, any parameter you pass won't be allowed as <? extends Bird> doesn't tell the compiler exactly what the type <T> is. So whether you try to pass a Bird object or a Nightingale to the add method, nothing is <? extends Bird> so the compiler cannot allow you to pass any of them to the add method. <br /> Thus although it might look like a List<? extends Bird> is immutable, but actually the problem is the there is no valid parameter to the add method. You can for example call List.clear method to clear a List<? extends Bird> so it is not immutable.
 
Jesse Silverman
Bartender
Posts: 1059
33
Eclipse IDE Postgres Database C++ Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What Ankit said!

According to the Sybex 819 book by Jeanne and Scott, it is okay to think of a List<? extends SomeClass> as immutable for the exam.

So Ankit's true statement that you can for instance, call .clear() on it, and my super-trivia that you can even call Collections.sort( ) on it, while interesting because they go back to illuminating that the whole point of Generics is Type-Safety, which means basically "Be Careful With .add()/.set()" apparently are not in scope for the exam.

Being able to call methods on them as he shows, very much is in scope, of course.
 
There's a hole in the bucket, dear Liza, dear Liza, a hole in the bucket, dear liza, a tiny ad:
the value of filler advertising in 2021
https://coderanch.com/t/730886/filler-advertising
reply
    Bookmark Topic Watch Topic
  • New Topic