About Question enthuware.ocpjp.i.v11.2.3100 :

Help and support on OCA OCP Java Programmer Certification Questions
1Z0-808, 1Z0-809, 1Z0-815, 1Z0-816, 1Z0-817

Moderator: admin

Post Reply
stxrk___
Posts: 2
Joined: Thu May 14, 2020 2:02 pm
Contact:

About Question enthuware.ocpjp.i.v11.2.3100 :

Post by stxrk___ »

Working through the mock exams, which is really helpful.

I came acress this one:

"Given:

Code: Select all

class Base{
   public  <T extends Number, Z extends Number> Map<T, Z> getMap(T t, Z z)
   {
      return new HashMap<T, Z>();
   }
}

class Derived extends Base{
   //public  <T, Z> TreeMap<T, Z> getMap(T t, Z z) { return new TreeMap<T, Z>(); }; //1

   //public  Map<Number, Number> getMap(Number t, Number z) { return new TreeMap<Number, Number>(); }; //2

   //public  Map<Integer, Integer> getMap(Number t, Number z) { return new HashMap<Integer, Integer>(); };   //3
}
Identify correct statements about the methods defined in Derived assuming they are uncommented one at a time individually."

Correct answer is:
//1 correctly overloads while //2 and //3 correctly override the method in Base.
The rules for multiple type parameters are same as the rules for a single type parameter. You have to apply the same rules for both the type parameters separately. For example, we know that A<S> is a valid subtype of A<? extends T> (where S is a subtype of T). Therefore, Map<Integer, Integer> is a valid subtype of Map<T extends Number, Z extends Number>. The bounds defined by <T extends Number> and <T> are different. Therefore, the parameter list of //1 i.e. getMap(T t, Z z) is different from the parameter list of the Base class's method. Thus, it is a valid overload.

The way I see it. //1 and the baseClass have the same signature ( getMap(T t, Z z)), so one would be an override, no? Am I missing something? :)

admin
Site Admin
Posts: 10384
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by admin »

No, it is an overload because, as explained in the explanation, the bounds of T and Z are different in Base and Derived classes.

You can do a simple test to check this. Just call super.getMap(t, z); in the Derived class's getMap method. It will not compile. This means, the compiler doesn't consider the Derived class's method to be overiding the Base class's method.

stxrk___
Posts: 2
Joined: Thu May 14, 2020 2:02 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by stxrk___ »

hmm, thanks for clearing that up :)

dimitrilc
Posts: 34
Joined: Sat Jun 06, 2020 4:51 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by dimitrilc »

So from this question, is the rule below correct?

1. When the parent method contains range-bounded generic type parameters,
2. If the child method modifies the range-bounded generic type parameters,
3. Then the child method is absolutely NOT Overriding the parent method.

For example, parent method:

Code: Select all

public  <T extends Number, Z extends Number> Map<T, Z> getMap(T t, Z z)
If the child method modifies the range-bounded type parameters, then there is no way that the child method can be an Override:

Code: Select all

public  <T super Number, Z super Number> Map<T, Z> getMap(T t, Z z)

Code: Select all

public  <T, Z> Map<T, Z> getMap(T t, Z z)

admin
Site Admin
Posts: 10384
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by admin »

That's correct. Please go through Section 8.4.8.3 "Requirements in Overriding and Hiding" of JLS 11 for details.

philippe
Posts: 26
Joined: Sun Jul 16, 2017 4:24 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by philippe »

Regarding this override:

Code: Select all

public Map<Integer, Integer> getMap(Number t, Number z) {
  return new HashMap<Integer, Integer>();
}
I don't understand why this compiles.

In the super class, geMap is defined as follows:

Code: Select all

public  <T extends Number, Z extends Number> Map<T, Z> getMap(T t, Z z) {
  return new HashMap<T, Z>();
}
In the sub type, the parameterized types are both Integer. How is it possible that the compiler doesn't complain about the method parameters, which are put as Number and not Integer?

When I put it in my IDE, the following warning is given (I don't understand why):

Code: Select all

Type safety: The return type Map<Integer,Integer> for getMap(Number, Number) from the type Derived needs unchecked conversion to conform to Map<Number,Number> from the type Base

admin
Site Admin
Posts: 10384
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by admin »

The following code explains the issue:

Code: Select all

class A {
   public <T extends Number, Z extends Number> Map<T, Z> getMap(T t, Z z) {
      return new HashMap<T, Z>();
   }
}

public class TestClass extends A {
   public Map<Integer, Integer> getMap(Number t, Number z) {
      return new HashMap<Integer, Integer>();
   }

   public static void main(String[] args) {
      Double d = 1.0;
      A a = new TestClass(); //1
      Map<Double, Double> m = a.getMap(d, d);
   }
}
In the main method at //1, the reference a is of type A. Therefore, anyone calling a.getMap(d, d), will expect a Map of Doubles to be returned. However, the object to which a points is of type TestClass, which overrides the getMap method to return a Map of Integers. The compiler cannot prevent this from happening because Integer satisfies the requirement "T extends Number" imposed by the method in the superclass. Therefore, it generates the warning saying:

Code: Select all

warning: [unchecked] getMap(Number,Number) in TestClass overrides <T,Z>getMap(T,Z) in A
public Map<Integer, Integer> getMap(Number t, Number z) {
                             ^
  return type requires unchecked conversion from Map<Integer,Integer> to Map<T,Z>
  where T,Z are type-variables:
    T extends Number declared in method <T,Z>getMap(T,Z)
    Z extends Number declared in method <T,Z>getMap(T,Z)
The JLS makes a special provision to allow this type of overriding. As per section 8.4.5:
An unchecked conversion is allowed in the definition, despite being unsound, as a special allowance to allow smooth migration from non-generic to generic code. If an unchecked conversion is used to determine that R1 is return-type-substitutable for R2, then R1 is necessarily not a subtype of R2 and the rules for overriding (§8.4.8.3, §9.4.1) will require a compile-time unchecked warning.
Please go through the sections quoted above from the JLS.

philippe
Posts: 26
Joined: Sun Jul 16, 2017 4:24 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by philippe »

Thanks for the clear explanation!

enthunoob
Posts: 57
Joined: Thu Apr 15, 2021 12:21 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by enthunoob »

Hello, in the explanation of this question I think a word 'overriding' should be replaced with 'overridden'.

Third, if it is a potential override, check the return type. Java allows "covariant" returns, which means, the return type of the overriding method must be the same or be a subtype of the return type mentioned in the overridden method. Check the two return types without the generic type specification. If return type of the overriding method is covariant with respect to the return type of the >>>>>overriding<<<<<< method (for example, ArrayList is covariant with List), then perform the same check including the generic type specification (for example, ArrayList<CharSequence> is covariant with List<? extends CharSequence>).

Is my assumption correct?

enthunoob
Posts: 57
Joined: Thu Apr 15, 2021 12:21 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by enthunoob »

And a point of feedback. Please add a step by step analysis per answer/line of code, instead of a half one for only the correct answer. I've come across this (very general) explanation before and find it very hard to get through.

admin
Site Admin
Posts: 10384
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by admin »

You are right, it is a typo and should be fixed.

Regarding explanations to each option, we do try to provide explanations to the wrong options as well whereever the author feels it is warranted. But you are right, the author may sometimes feel that an option is obviously wrong and deserves no further explanation but it may not be so obvious to the reader. We will improve. Did you feel any particular option of this question requires more explanation? Please do tell.


Regarding generic explanations at the end of a question, such explanations may contain a larger theoretical discussion/points on a concept or topic and in that case, it may be repeated in multiple questions. Their purpose is to cover all important aspects of that concept
(even if that question does not test on all aspects) so that the reader can answer other questions on that concept later.

steinov
Posts: 19
Joined: Wed Feb 08, 2023 3:11 am
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by steinov »

I was trying some code to understand the answers better. I tried this override:

Code: Select all

public Map<Integer, Integer> getMap(Integer t, Number z) {
    return new HashMap<Integer, Integer>();
}
If I annotate it with @Override I get a compiler error: `method does not override or implement a method from a supertype`. I don't understand why, my logic would be that T is of type Integer and therefore it should be allowed as parameter type in an override. Can you explain why this is not the case?

admin
Site Admin
Posts: 10384
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by admin »

T and Z are defined in the base class as something that "extends Number". You are trying to override the method with Integer but that make the overriding method more specific than the one which it is overriding. The reason is that "? extends Number" includes many classes such as Integer, Long, Double etc. But Integer is just one specific class. Hence, this method cannot be considered an override.

Think of it this way:

Let us say you got a reference to a Base class object from some method like this:
Base b = getBaseObject(); //you don't know how getBaseObject is implemented. It is implemented by someone else.

You should be able to invoke b.getMap() by passing a Double, Double also because Double extends Number. This is promised by the method definition of Base.getMap.

Now, getBaseObject() method is free to return any subclass of Base also. It is ok because a Derived IS-A Base. But you are overriding getMap(T Z) in Derived with getMap(Integer, Integer). What will happen when you call getMap(Double, Double) on this Derived object? It will fail because Derived's getMap expects Integer.

This shows that getMap(Integer, Number) is not really a valid override for getMap(T, Z). It is a different method altogether.

steinov
Posts: 19
Joined: Wed Feb 08, 2023 3:11 am
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by steinov »

Thanks! I get it now!

_umut_
Posts: 6
Joined: Sun Sep 15, 2024 12:42 am
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by _umut_ »

https://docs.oracle.com/javase/tutorial ... Types.html

This helped me to understand it better.

So If I’m not mistaken, the method:


public <T extends Number, Z extends Number> Map<T, Z> getMap(T t, Z z) {
return new HashMap<T, Z>();
}

becomes after type erasure:

public Map getMap(Number t, Number z) {
return new HashMap();
}

jerry___
Posts: 9
Joined: Tue Nov 26, 2024 2:08 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by jerry___ »

Hi Enthuware!

Working my way through the mock exams, I found one thing that I've been unable to validate in test code.

In the explanation of this question, it says:
Next, you need to check the type specification of generic types. This is a bit complicated. To determine this, you must remember the following hierarchy of subtypes. Assuming that S is a sub type of T and <<< means "is a subtype of", here are the two hierarchies:

Hierarchy 1 : A<S> <<< A<? extends S> <<< A<? extends T>
Example: Since Integer is a subtype of Number, List<Integer> is a subtype of List<? extends Integer> and List<? extends Integer> is a subtype of List<? extends Number>.
Thus, if an overridden method returns List<? extends Integer>, the overriding method can return List<Integer> but not List<Number> or List<? extends Number>.

Hierarchy 2 : A<T> <<< A<? super T> <<< A<? super S>
Example: List<Number> is a subtype of List<? super Number> and List<? super Number> is a subtype of List<? super Integer>
Thus, if an overridden method returns List<? super Number>, the overriding method can return List<Number> but not List<Integer> or List<? super Integer>.

It is important to understand that List<Integer> is not a subtype of List<Number> even though Integer is a subtype of Number.
I tried to test this with the hierarchy Object - String - CharSequence, and I only got a partial success, this is my testing code.

I don't understand why the public List<? extends CharSequence> inthemiddle() { return null; } won't compile since the return type's generic part is lower in hierarchy than the one in the parent, public List<? extends String> inthemiddle() { return null; }

I have a similar issue with the "super" hierarchy but I'm sure once I'd get this "extends" example right in my head, the "super" will follow.

Code: Select all

import java.util.*;

public class Main
{
        class A
        {
                public List<? extends String> inthemiddle() { return null; }
        }

        class B extends A
        {
                // this compiles:
                //@Override
                //public List<String> inthemiddle() { return null; }

                // this doesn't,
                @Override
                public List<? extends CharSequence> inthemiddle() { return null; }
        }
}
compiler error:

Code: Select all

jerry@a-laptop:~/javaprojects$ javac Main.java
Main.java:18: error: inthemiddle() in Main.B cannot override inthemiddle() in Main.A
                public List<? extends CharSequence> inthemiddle() { return null; }
                                                    ^
  return type List<? extends CharSequence> is not compatible with List<? extends String>
Main.java:17: error: method does not override or implement a method from a supertype
                @Override
                ^
2 errors
jerry@a-laptop:~/javaprojects$ 
Thank you very much for your time!

admin
Site Admin
Posts: 10384
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by admin »

? extends CharSequence is not a sub type of ? extends String as per hierarchy rule 1. The reverse is true. Please read the rule carefully.

jerry___
Posts: 9
Joined: Tue Nov 26, 2024 2:08 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by jerry___ »

You're absolutely right, I had a huge blind spot thinking that CharSequence was a subclass of String while it is the other way around, my example was poorly chosen.
Last edited by jerry___ on Wed Nov 27, 2024 12:38 am, edited 1 time in total.

admin
Site Admin
Posts: 10384
Joined: Fri Sep 10, 2010 9:26 pm
Contact:

Re: About Question enthuware.ocpjp.i.v11.2.3100 :

Post by admin »

String is NOT a supertype of CharSequence!!
CharSequence is a supertype of String.

So S is String and T is CharSequence.

Post Reply

Who is online

Users browsing this forum: No registered users and 8 guests