some questions about super() method in Java - java

In the book "Effective Java",I can't understand the result when I run the following code.
public class InstrumentHashSet<E> extends HashSet<E>{
private int count;
#Override
public boolean add(E e) {
// TODO Auto-generated method stub
count++;
return super.add(e);
}
#Override
public boolean addAll(Collection<? extends E> c) {
// TODO Auto-generated method stub
int size = c.size();
count+= size;
return super.addAll(c);
}
public int getCount(){
return count;
}
public static void main(String[] args) {
InstrumentHashSet<String> s = new InstrumentHashSet<String>();
s.addAll(Arrays.asList("xinwa1","xinwa2","xinwa3"));
System.out.println("hashSet count:"+s.getCount());
}
}
I can't understand why the result is six. I know that the addAll() method in parent class calls the add() method. But there is no 'count++' in add() method in parent class. I initially thinK that subclass overrides the add() method,so the super().addAll() calls the add() method in subclass. But when run the following code,I'm confused.
class Point {
public int x;
public int y;
public Point(int x,int y) {
this.x= x;
this.y= y;
}
public void method() {
System.out.println("this is parent");
}
}
public class ColorPoint extends Point{
public ColorPoint(int x, int y) {
super(x, y);
}
#Override
public void method() {
System.out.println("this is son");
}
public void print() {
super.method();
}
public static void main(String[] args) {
ColorPoint c = new ColorPoint(1, 2);
c.print();
}
}
Why the result is 'this is parent'? According to the example in 'Effective Java', I think the result should be 'this is son'. Please tell me what's wrong with me.

I initially thinK that subclass overrides the add() method,so the super().addAll() calls the add() method in subclass. But when run the following code,I'm confused.
-- You are Correct
In ColorPoint, In print you are explicitly making a call to parents method and hence it results in "this is parent". When you use super.someMethod() you explicitly telling to call parents method irrespective whether it is ovveriden by child or not
When it will override and print "this is son", below code will print "this is son"
class Point {
public int x;
public int y;
public Point(int x,int y) {
this.x= x;
this.y= y;
}
public void method() {
System.out.println("this is parent");
}
}
public void print() {
method();
}
public class ColorPoint extends Point{
public ColorPoint(int x, int y) {
super(x, y);
}
#Override
public void method() {
System.out.println("this is son");
}
public static void main(String[] args) {
ColorPoint c = new ColorPoint(1, 2);
c.print();
}
}
Changes In Above Code:
Move print method to parent and remove from Colorpoint
inside print change super.method() to method()
Explanation:
You are using object which is instance of ColorPoint, all methods
will be called from ColorPoint class implemenation, if any method is
not present it will call parents method.
When you call print on ColorPoint, it is not present in ColorPoint,
so call print() in method(but you are still using ColorPoint
instance).
Now print calls method, it is present in ColorPoint, so call method
in ColorPoint and not parent.
Whenever you call method like super.method() then it will always try
to call method from super

Below is java implementation of addAll() method. As seen here, it calls add() internally. So, you should increment your count in add() method alone.
public boolean More ...addAll(Collection<? extends E> c) {
boolean modified = false;
Iterator<? extends E> e = c.iterator();
while (e.hasNext()) {
if (add(e.next()))
modified = true;
}
return modified;
}
So, when you call addAll() with a collection of 3 elements, count is increment immediately to 3 and then it increments by 1 each time your add() method is called.

I can't understand why the result is six.
When you invoke super.addAll(c), you invoke the addAll() method of the super class.
And addAll() in HashSet uses the implementation defined in AbstractCollection that iterates on the collection in parameter and invokes add() on each element :
public boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
So this code performs twice the incrementation :
#Override
public boolean addAll(Collection<? extends E> c) {
// TODO Auto-generated method stub
int size = c.size();
count+= size; // + 3
return super.addAll(c); // + 3
}
Here :
count+= size; // + 3
and here :
return super.addAll(c); // + 3

The key point is polymorphism. Often, there are two versions of a method, with the same signature, but in two different classes, and both versions are accessible to code that's running. The JVM has to decide which one to call, it bases its decision on the actual class of the object - not on the type of the variable that references the object, and not on which class it's currently running code from.
In other words if x is a variable that refers to an InstrumentHashSet and you call x.add(something), it's the add method in the InstrumentHashSet class that gets called.
In your example, when you call super.addAll, this calls addAll in the HashSet class, which in turn calls add once for each object that's being added. But because your object is an InstrumentHashSet, it's the InstrumentHashSet version of the add method that gets called.
So your code runs count += size; (which sets count to 3) then makes three calls to your add method, each of which increments count. The end result is that count is 6.

Related

Method is undefined for a class

I am trying to run a code in eclipse that uses a method called getArea(an object). I am currently getting an error saying
The method getArea(ComparableRectangle) is undefined for the type RectangleTest
This is the code for RectangleTest-
package geometry;
import java.awt.Rectangle;
public class RectangleTest extends Rectangle {
/**
*
*/
private static final long serialVersionUID = -3282103336310735942L;
public static void main(String args[]) {
ComparableRectangle rect01 = new ComparableRectangle(5, 4);
ComparableRectangle rect02 = new ComparableRectangle(6, 8);
System.out.println("Area: " + getArea(rect01));
}
}
And this is the code for ComparableRectangle.
package geometry;
import java.awt.Rectangle;
public class ComparableRectangle extends Rectangle implements Comparable {
private int width;
private int height;
public ComparableRectangle(int w, int h) {
width = w;
height = h;
}
public double getArea(ComparableRectangle rect) {
return width*height;
}
public boolean compareTo(ComparableRectangle rect1, ComparableRectangle rect2) {
if(rect1.width == rect2.width && rect1.height == rect2.height) {
return true;
}
else {
return false;
}
}
#Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
How do I clarify that rect01 is a ComparableRectangle?
In object oriented language like Java or C++ to call a class method you need a instance of that class, which we call also an object instantiated from that class. So you have to call your method like below:-
rect02.getArea(rect01);
rect01.getArea(rect02);
Because getArea(ComparableRectangle rect) is a member function or method of class ComparableRectangle hence you need its instance to call it. Here are two instances of that class rect01 and rect02.
Good luck!
You misunderstood how methods and their parameters work.
You need some way to combine the method with some object it should be called on. Currently you do so by using the object as parameter, but this is not correct.
You should combine object and method by writing
obj.method();
Therefore, you should call the method like
rect01.getArea();
and remove the parameter from the method
public double getArea() { ... }
Parameters can be used to give the method additional information on the way. A good example is the compareTo method which is supposed to compare the current instance with the given instance. A call would look like
rect01.compareTo(rect02);
and the methods signature is
public int compareTo(Object o)
Note that it only has one parameter as the current instance is implicitly known to the method (this keyword).
Notes
There is no need for the additional custom compareTo method, which by the way should be named compare and should be static since it's not bound to any instance.
Also note that your custom compareTomethod is not comparing. It just returns same or not same. But for an order you need less than, greater than and equals. Your method thus does not define an order.

Java cast to superclass and call overload method

abstract class A {
int met(A a) {
return 0;
}
int met(B b) {
return 1;
}
int met(C c) {
return 2;
}
}
class B extends A {
int met(A a) {
return 3;
}
int met(B b) {
return 4;
}
int met(C c) {
return 5;
}
}
class C extends B {
int f() {
return ((A)this).met((A)this);
}
}
public class teste {
public static void main(String args[]) {
C x = new C();
System.out.println(x.f());
}
}
The program will return 3 and I was expecting 0. Why does the first cast in the method f do nothing and the second one works? Is it because in the A and B classes the met methods are overloaded and therefore static binding is used?
That's just the way polymorphism works. Just consider this example:
A a = new C();
a.met(a);
This would as expected call the correct method B#met(...). The method-tables for an object don't just change because you change the type of the variable you stored the Object in, since the binding between an Object and it's methods is stronger than the one between the storage-type and the methods related to it. The second type works, because the type of the input is casted to A and thus the method recognizes it as A (the type of the input-storage has stronger binding than the Object type).

Static methods inheritance and polymorphism

How does inheritance and polymorphism work with static methods? Could someone explain what the proper output is supposed to be here and how it was derived?
class A { public static int get() { return 17; } }
class B extends A { public static int get() { return 42; } }
Main
A x = new B();
x.get();
The error message,
The static method get() from the type A should be accessed in a static way
I think I know how to access to it in a static way but this is a question from class and its sort of implied that one or the other values would be returned
In our program, we have the class definitions:
class A { public static int get() { return 17; } }
class B extends A { public static int get() { return 42; } }
and somewhere else we declare A x = new B();
What number will the call x.get() return?
The invocation will return the int value 17.
static methods are not inherited.
static methods are bound and invoked based on the type of the expression they are invoked on.
So
x.get();
where x is of type A invokes A's implementation. Note also that static methods don't need an instance to be invoked.
These would work as well.
((A) null).get();
A.get();
...
public static A someMethod() {}
...
someMethod().get();
The message you got is a warning, not an error.

Create counting class extending Hashset / Inheritance

If we consider the following class to count object added in an HashSet :
public class CountingHashSet<E> extends HashSet<E> {
public int addCount = 0;
#Override
public boolean add(E e) {
addCount +=1;
return super.add(e);
}
#Override
public boolean addAll(Collection<?
extends E> c) {
addCount += c.size();
return super.addAll(c);
}
}
Then, the JUnit test failed :
#Test
public void testCount() {
CountingHashSet<Integer> s = new CountingHashSet<>();
s.addAll(Arrays.asList(1, 2, 3, 4, 5));
for (int i = 6; i <= 10; ++i)
s.add(i);
assertEquals(10, s.addCount);
}
I get the following :
java.lang.AssertionError: expected:<10> but was <15>
Why I get 15 ? To my mind s.addAll(myCollection) call super.addAll(c) and if I look into the source code of hashSet, I saw that addAll(c) call add(e) to add each element. But why super.addAll(c) call the add method that I redefined ? (that's why I get 15 instead of 10)
You're treating inheritance as if it were composition. It's not. The calls don't end up being "add() on the HashSet" - they end up being "add() on the current object".
But why super.addAll(c) call the add method that I redefined ?
Because that's how virtual methods behave. addAll just calls add(), which will use the most overridden implementation in the actual type. That's how polymorphism always works. Let's write a simpler example:
class Superclass {
public void foo() {
bar();
}
public void bar() {
System.out.println("Superclass.bar()");
}
}
class Subclass extends Superclass {
#Override
public void bar() {
System.out.println("Subclass.bar()");
}
}
public class Test {
public static void main(String [] args) {
Superclass x = new Subclass();
x.foo(); // Prints Subclass.bar()
}
}
Is the result of Subclass.bar() what you'd expect from this example? If so, what do you expect the difference would be in your version? Just because you're calling super.addAll() doesn't mean that the object is suddenly in "non-overriding" mode or anything like that.
That's how polymorphism works. Your object is of type CountingHashSet, so a call to add will call CountingHashSet.add, even from the super type.

Object Oriented Class Communication

I have a Java assessment that gets marked by a robot. Whenever I upload my assignment it shows a screen like this.
A good object-oriented design places each method into the most appropriate
class. The most appropriate class for a method should be the same class as
the data fields that that method needs to access. If you don't place a method
into the right class, then this will most likely increase the amount of
communication that is required between your classes.
The score below measures the amount of communication between your classes. A
lower score is better.
19 method invocations between classes
7 arguments passed between classes
15 results returned between classes
Amount of communication = invocations + 2*inputs + 2*outputs = 63
Now what exactly does "method invocations between classes", "arguments passed between classes" and "results returned between classes" mean?
Method invocations between classes
As your class contains their own methods if you want to call the method from another class you have to use an instance of this class.
For example :
class A{
public void methodA(){
  }
}
class B{
public void methodB(){
}
}
If I want to call methodA() from the class B I must use this:
public void methodB(){
A a = new A();
a.methodA(); // method invocation between classes
}
Argument passed between classes
This time methodA() will need an argument, and B as a field which could be used as argument.
class A{
public void methodA(int argument){
  }
}
class B{
private int fieldB = 42;
public void methodB(){
}
}
To call methodA() from B you will pass an argument from a class to another.
public void methodB(){
A a= new A();
a.methodA(fieldB); //Argument passed between classes
}
Results returned between classes
And now methodA() returns a result this is the code.
class A{
public int methodA(){
return 42;
}
}
class B{
private int fieldB;
public void methodB(){
}
}
To use/handle the returned value of the methodA() from the class B you'll have to do this:
public void methodB(){
A a= new A();
fieldB = a.methodA(); //Result returned between classes
}
I'd have to say:
method invocations between classes
Suppose you have classes X and Y. This would be any time class X calls some method on class Y.
e.g.,
class Y
{
public void foo() { }
}
class X
{
public void someMethod()
{
Y y = new Y();
y.foo();
}
}
arguments passed between classes
Could possibly mean one of two things.
Either you are accessing a field of another class directly.
class Y
{
public int number;
}
class X
{
public void someMethod()
{
Y y = new Y();
int yNum = y.number;
}
}
Or a method was called where arguments are supplied. (most likely case)
class Y
{
public void foo(int arg) { }
}
class X
{
public void someMethod()
{
Y y = new Y();
y.foo(56);
}
}
results returned between classes
Received a value from a method of another class that returned a value. e.g., getters or other methods.
class Y
{
public int foo() { return 42; }
private int number;
public int getNumber() { return number; }
}
class X
{
public void someMethod()
{
Y y = new Y();
int yFoo = y.foo();
int yNumber = y.getNumber();
}
}

Categories