Polymorphism - Method overriding and overloading not clear - java

I am learning polymorphism but not able to understand how it works
When I try to create an object Car car = new Audi();, overriding prints "This is Audi". But with same object I am not able to call first(int x, int y) of Audi class... I am able to call only Car class first().
Overriding prints the Audi method, Overloading prints Car method.. when calling with same object..
Class Car
class Car {
public void carName() {
System.out.println("Parent of car");
}
public int first() {
System.out.println("Base - Parent");
return 2;
}
}
Class BMW
class BMW extends Car {
public void carName() {
System.out.println("This is BMW");
}
public int first(int x) {
System.out.println("BMW override");
return x;
}
}
Class Audi
class Audi extends BMW {
public void carName() {
System.out.println("This is Audi");
}
public int first(int x, int y) {
System.out.println("AUdi Override");
return x;
}
}
Class PloyMor
public class PolyMor extends Audi {
public static void main(String args[]) {
Car car = new Audi();
car.carName();
car.first();
}
}

Important: I am assuming that class BTW extends Car not Audi (which would makes no sense IMO).
But with same object i am not able to call first(int x, int y) of Audi class.
You need to distinguish between variable type and value (object) type. In case of
Car car = new Audi();
variable type is Car while type of object it holds is Audi.
You need to realize that compiler doesn't assume what is the value of variable. It applies same rules as if it was parameter of method like
void someMethod(Car car){
//do something with `car`
}
where inside of that method we don't know if it will be used with someMethod(new Audi()); or someMethod(new BMW());.
So which methods can be safely invoked via car variable inside someMethod body? Only those which are guaranteed to be implemented (to appear) in all objects which can be used as method arguments. If that method would let us write car.first(1, 2); it will work for scenario like someMethod(new Audi()) but will fail for someMethod(new BMW()) because BMW doesn't have first(int x, int y) method.

It would have worked if you had another method defined in the base class like follows:
public int first(int a, int b) {
System.out.println("Base - Parent");
return 2;
}
As the final object you are trying to create is an object of class Car, it only has the methods from the Car class which if are present in Audi class, will override the methods in Car class.

Calling a method depends on the compile-type rather than the runtime type.
Car car = new Audi();
^ ^
compile-type runtime type
Compiled Type vs Runtime Type:
Source
Credit: #duffymo
Let's say we have
A test = new B();
at compile time: the compiler only knows that the variable test is of the type A. He does not know that we are actually giving him an instance of B. Therefore the compile-type of test is A.
at run time: the type of test is known to be B and therefore has the run time type of B
Since compiler does not know what type will be stored at runtime it only allows us to call methods of Class A
Solution:
If you want to call methods from instantiated type do this
then you will be able to access method first(int x, int y)
Audi car = new Audi();
car.carName();
car.first(); // Original Method
car.first(3, 3); // Overloading
Output:
This is Audi
Base - Parent
AUdi Overload
P.S Like OldProgrammer mentioned Audi should extend Car instead of BMW

You are not overriding first from Car in Audi, because the signatures are different.
The signature includes the method name, parameters, and throws clause.
The method first() from Car takes no arguments.
In Audi it takes two ints as arguments. Not the same.
Even your simple hierarchy is not a good design. You are having problems because your implementation is bad.
Try this:
public abstract class Car {
private String name;
private int id;
public Car(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() { return this.name; }
public int getId() { return this.id; }
public static void main(String [] args) {
List<Car> cars = new ArrayList<>();
cars.add(new Audi());
cars.add(new Bmw());
System.out.println(cars);
}
}
class Audi extends Car {
public Audi() {
super("Audi", 1);
}
}
class Bmw extends Car {
public Bmw() {
super("BMW", 2);
}
}

Related

How to invoke different methods in sub-classes with different parameters by calling a single method in super class object without using if condition?

I have a Vehicle abstract class and two subclasses Bike and Car, which has 1 common method and 2 different methods. I want to execute all methods from my main class method by invoking only a single method on the input object.
abstract class Vehicle {
Tire tire;
// a common method
void checkTire (TireValidator tireValidator) {
tireValidator.check(tire);
}
// How to design this abstract method to invoke all validations
abstract void runAllValidations();
}
Now Bike class has to check brakes in addition to tire
class Bike extends vehicle {
Brakes brakes;
void checkBrakes (BrakeValidator brakeValidator) {
brakeValidator.check(brakes);
}
// How to override runAllValidations method here?
}
Car class has to check gas in addition to tire
class Car extends vehicle {
Gas gas;
void checkGas (GasValidator gasValidator) {
gasValidator.check(gas);
}
// How to override runAllValidations method here?
}
How can I design my runAllValidations method and override it in my subclasses so that both the checks - tire & brakes for bike, and tire & gas for car, will run **WITHOUT using any if conditions? **
void main() {
TireValidator TireValidator;
BrakeValidator brakeValidator;
GasValidator gasValidator;
Vehicle car = new car(...);
vehicle bike = new Bike(...);
// how to call runAllValidations method? What to pass as parameters?
car.runAllValidations(...);
bike.runAllValidations(...);
}
First way (but with unnecessary parameters)
One way to do this design my abstract method to accept all three validators as parameters.
Vehicle:
abstract void runAllValidations(TireValidator TireValidator, BrakeValidator brakeValidator, GasValidator gasValidator);
Bike:
void runAllValidations(TireValidator tireValidator, BrakeValidator brakeValidator, GasValidator gasValidator) {
checkTire(tireValidator);
checkBrakes(brakeValidator);
}
Car:
void runAllValidations(TireValidator tireValidator, BrakeValidator brakeValidator, GasValidator gasValidator) {
checkTire(tireValidator);
checkGas(GasValidator);
}
Here, the biggest problem is that I'm passing unnecessary validators to these methods.
Second way (but we are using if conditions)
void main() {}
void checkAllvalidationsForVehicle(Vehicle v) {
if (v instanceof Bike) {
Bike b = (Bike) v;
b.checkTire(tireValidator);
b.checkBrakes(brakeValidator);
} else if (v instanceof Car) {
Car c = (Car) v;
c.checkTire(tireValidator);
c.checkGas(gasValidator);
}
}
Here there are if - else conditions, which I'm trying to avoid in my code.
What is the best possible way to solve these issues?
If you just have a variable of type Vehicle, you cannot know what kind of validation it needs except by checking what type it actually stores. If you do know what validations the vehicle needs for whatever reason, then you don't need the abstract method in Vehicle - create an interface for each kind of validation, like BrakeAndTireValidatable and GasAndTireValidatable, and cast to the appropriate interface.
So how about assigning the validators to the vehicles when you do know the type? The classes would have validator fields, and runAllValidations would be parameterless.
abstract class Vehicle {
private Tire tire;
private TireValidator tireValidator;
public void checkTire() {
tireValidator.check(tire);
}
public void setTireValidator(TireValidator tireValidator) {
this.tireValidator = tireValidator;
}
public abstract void runAllValidations();
}
class Bike extends vehicle {
private Brakes brakes;
private BrakeValidator;
void checkBrakes() {
brakeValidator.check(brakes);
}
public void setBrakeValidator(BrakeValidator brakeValidator) {
this.brakeValidator = brakeValidator;
}
#Override
public void runAllValidations() {
checkTire();
checkBrakes();
}
}
class Car extends vehicle {
private Gas brakes;
private GasValidator;
void checkGas() {
gasValidator.check(gas);
}
public void setGasValidator(GasValidator gasValidator) {
this.gasValidator = gasValidator;
}
#Override
public void runAllValidations() {
checkTire();
checkGas();
}
}
Then in main, you can do:
TireValidator tireValidator = ...;
BrakeValidator brakeValidator = ...;
GasValidator gasValidator = ...;
Car car = new Car(...);
Bike bike = new Bike(...);
car.setTireValidator(tireValidator);
bike.setTireValidator(tireValidator);
car.setGasValidator(gasValidator);
bike.setBrakeValidator(brakeValidator);
// it is still possible to put car and bike into "Vehicle"-typed variables
// and call runAllValidations
// here I'll demonstrate this by putting them in a list and iterate over the list
List.of(car, bike).forEach(Vehicle::runAllValidations);

Confusing java code - related to static binding

something about this code confuses me. The first print line is 1600. I understand it has something to do with the static class being Car and not Sportscar. But we created the object as a Sportscar, so why isn't the volume field 3500? Thanks.
public class Car {
public int volume;
public Car() { this(1600); }
public Car(int volume) { this.volume = volume; }
public String toString() { return "Car:" + volume; }
}
public class SportsCar extends Car {
public int volume;
SportsCar() { this(3000); }
SportsCar(int volume) { this.volume = volume; }
public String toString() {return "SportsCar:"+volume;}
}
public class CarApplication {
public static void main(String [] args) {
Car car = new SportsCar(3500);
System.out.println(car.volume);
System.out.println(car.toString());
System.out.println(car);
}
}
First off, note that when you call the constructor for SportsCar Java will automatically call the default constructor for its parent class, Car. This will set the volume field of the object's parent Car class to 1600.
In Java, there is no polymorphism for fields. So whereas the toString() method inside your SportsCar class always overrides that of its parent (Car) class, the rules for how identically named instance variables are accessed is a little different.
If you are accessing volume from within the SportsCar class then the volume of SportsCar will be used. From outside the class itself (so when you're calling from CarApplication) which instance variable is accessed depends upon the compile-time type of the object in question. Because you declare the type of car to be a Car, the volume value of the parent Car class is used--hence 1600 is printed. If you had instead declared car to be a SportsCar, 3500 would be printed.
Another option would be this:
System.out.println(((SportsCar)car).toString());
This will output 3500, since the type of car has been cast to SportsCar.
So the point here is that when you are using car.volume, car variable is of type Car and object reference is of type SportsCar.
As both the classes have the same element named volume and you are trying to refer it through parent object variable, it is returning 1600.
If you will typecast and then check the volume, it will return 3500 as per below code:
System.out.println(((SportsCar)car).volume);
When you declare something in this way:
ParentClass variable = new ChildClass(Args);
The methods and fields in ParentClass are the only ones available to you. It is restricted because you declared the type as a ParentClass. Because Car's volume is 1600 and the object is restricted to the ParentClass's methods and fields, it prints 1600.
An example would be as follows:
Consider I had an Apple Class and a Fruit class:
public class Fruit {
private String type;
public Fruit(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
And the Apple Class:
public class Apple extends Fruit {
private String variant;
public Apple(String variant) {
System.out.println("I like " + variant + apples too!");
super("Apple");
}
public String getVariant() {
return variant;
}
}
And now I instantiate like this:
Fruit ap = new Apple("Fiji");
I don't have access to getVariant() or any methods in the Apple class because the type is of the parent class, not of Apple. I would be able to do getType() but that's it.
In your case:
public class SportsCar extends Car {
public int volume;
SportsCar() {
this(3000);
}
SportsCar(int volume) {
this.volume = volume;
}
public String toString() {
return "SportsCar:"+volume;
}
}
Although SportsCar has it's own constructor and takes it's own volume, the parent class Car is the actual type, causing the Car constructor to be called, hence setting volume to 1600. To specify a SportsCar object, do this:
SportsCar sc = new SportsCar(3500);
System.out.print(sc.toString());
This will print out:
SportsCar:3500
You can also typecast it like so:
Car c = new SportsCar(1600);
System.out.print(((SportsCar) c).toString());
Aman Chhabra answer is right. You created a SportCar object which is from the Car "family". And what you are printing is the volume of Car, not the volume of SportCar.
One other way is to create a SportsCar object instead of Car.
P.s: you should always set your class attributes as private :)

Returning subclass instead of class

In this situation, do I have access to the overridden/additional methods of CarSubClass?
public Car getCar(){
CarSubClass carSub = new CarSubClass();
return carSub;
}
Update:
Car has subclasses SubClass1, SubClass2, SubClass3.
getCar() can return SubClass1,SubClass2, OR SubClass3.
Can I do this?:
Car car = getCar();
switch(car.getType()){//getType() returns a byte
case SubClass1:
SubClass1 car1 = (SubClass1)car;
break;
case SubClass2:
SubClass car2 = (SubClass2)car;
break;
case SubClass3:
SubClass3 car3 =(SubClass3)car;
break;
default: //don't do anything
}
Only overriden methods :
Car car = getCar();
car.method(); // here you can invoke only the overridden methods in CarSubClass
You cannot call the additional methods of CarSubClass which the reference type Car has no knowledge of. It will fail during compilation itself.
Probably this is possible , but you must be certain what you are doing here :
CarSubClass c = (CarSubClass)getCar();
c.subClassSpecificMethod();
The above casting is safe in your case because the method always returns an instance of CarSubClass . It is better to perform a check though.
Car c = getCar();
if(c instanceof CarSubClass){
((CarSubClass)c).subClassSpecificMethod();
}
switch(c.getType())
That is not a valid switch key.
JLS§14.11:
The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.
Yes, through dynamic typing/calls it will be available. This is the whole purpose of polymorphism.
But since you are returning a Car instance, whichever class that calls 'getCar()'
must cast it to a 'CarSubClass' first.
Car.java
public class Car {
public void a() {
System.out.println("In Car");
}
}
CarSubClass.java
enter code herepublic class CarSubClass extends Car {
#Override
public void a() {
System.out.println("In CarSubClass");
}
public static void main(String[] args) {
Car c = new CarSubClass();
c.a();
}
}
Will output:
'In CarSubClass'
Edit: I have edited my answer. This whole concept is called polymorphism. You are not required to cast, since at runtime, the dynamic type the variable holds, will ensure that the correct method is called.
Not unless you cast it to CarSubClass. See below as an example (a really bad one though):
public class Test {
public static Car getCar() {
return new SmallCar();
}
public static void main(String[] args) throws Exception {
((SmallCar) getCar()).getMake();
}
static class Car {
String model;
public String getModel() {
return this.model;
}
}
static class SmallCar extends Car {
String make;
public String getMake() {
return this.make;
}
}
}
Best of luck...

Java OOP issue - Related to Interface/Abstract Classes

I'm stuck with a Java OOP problem. I have come up with some toy code to explain the problem. Here are my classes -
Class 1 - Car.java
public class Car {
public void reportProblem(String problem){
ReportUtil.reportVehicleInfo("Car", 4, problem); //4 is number of wheels
}
//bunch of other methods
}
Class 2 - Truck.java
public class Truck {
public void reportProblem(String problem){
ReportUtil.reportVehicleInfo("Truck", 6, problem);
}
//bunch of other methods
}
Class 3 - ReportUtil.java
public class ReportUtil {
public static void reportVehicleInfo(String name, int wheels, String problem){
System.out.println(String.format("%s %s %s", name, wheels, problem));
}
}
Class 4 - Test.java
public class Test {
public static void main(String[] args) {
Car c = new Car();
c.reportProblem("puncture");
Truck t = new Truck();
t.reportProblem("engine missing");
}
}
I want to abstract the "reportProblem" method implementation in "Car" and "Truck" to a parent class. This is what I did -
Class 1 - Vehicle.java
public abstract class Vehicle {
public String mName;
public int mNumWheels;
public void reportProblem(String problem){
ReportUtil.reportVehicleInfo(mName, mNumWheels, problem);
}
public void setName(String name){
mName = name;
}
public void setNumWheels(int numWheels){
mNumWheels=numWheels;
}
}
Class 2 - Car.java
public class Car extends Vehicle {
//bunch of other methods
}
Class 3 - Truck.java
public class Truck extends Vehicle {
//bunch of other methods
}
Class 4 - ReportUtil.java (No change made to this class).
public class ReportUtil {
public static void reportVehicleInfo(String name, int wheels, String problem){
System.out.println(String.format("%s %s %s", name, wheels, problem));
}
}
Class 5 - Test.java
public class Test {
public static void main(String[] args) {
Car c = new Car();
c.setName("Car"); //NOTE : Can be missed!
c.setNumWheels(4); //NOTE : Can be missed!
c.reportProblem("puncture");
Truck t = new Truck();
t.setName("Truck"); //NOTE : Can be missed!
t.setNumWheels(6); //NOTE : Can be missed!
t.reportProblem("engine missing");
}
}
This achieves what I want (I have abstracted the implementation of "reportProblem"). But I know this is not the best way to do it. One reason is that the "reportProblem" method should not be called without calling "setName" and "setNumWheels" methods. Otherwise 'null' will be passed. Is there a way of enforcing, using some OOP technique, the two methods calls (setName and setNumWheels) BEFORE reportProblem is called?
I hope I have made myself clear. If I am not, just let me know how you would have done it so that I can learn from it.
Yes, make name and numWheels final and assign then in the constructor. So...
Class 1 - Vehicle.java
public abstract class Vehicle {
public final String mName;
public final int mNumWheels;
protected Vehicle(String name, int numWheels){
this.mName = name;
this.mNumWheels = numWheels;
}
public void reportProblem(String problem){
ReportUtil.reportVehicleInfo(mName, mNumWheels, problem);
}
...
}
Class 2 - Car.java
public class Car extends Vehicle {
public Car(){
super("Car", 4);
}
//bunch of other methods
}
Class 3 - Truck.java
public class Truck extends Vehicle {
public Truck(){
super("Truck", 6);
}
//bunch of other methods
}
Also, public fields are not good OO practice, because they expose details of your class' implementation that could be modified by users of the class. Those fields should be private. If the clients of the class need to know about them (or change them), then you should allow public getter (or setter) methods.
If you want to set the fields "required", you can set them as parameters in Truck/Car constructors and not provide a default constructor for these classes.
If members are essentials for an object's state/functionality, put them as part of a constructor, so it is not possible to create an object (and call the method of concern) without providing proper values for these members.
But you should not also provide a no-args constructor.
If there are too many parameters needed consider looking into the Builder idion
In addition to #Tony's answer (+1) if you have to use bean notation (default constructor and setters) and still do not want to allow using any business methods before the object is initialized you can do the following.
Define abstract method checkInitalized() in your Vehicle class. Implement this methods for your Car and Truck. BTW this method will probably have default implementation in Vehicle. In this case do not forget to call super from its overridden versions.
checkInitalized() should throw exception (e.g. IllegalStateException) if not all required fields are initialized.
Now call this method in the beginning of each business method. This will prevent you from using object that is not initialized yet.
This technique is a little bit verbose. Probably using wrapper pattern or AOP (e.g. AspectJ) may be useful here.

Java overloading vs overriding

Hi I just want to make sure I have these concepts right. Overloading in java means that you can have a constructor or a method with different number of arguments or different data types. i.e
public void setValue(){
this.value = 0;
}
public void setValue(int v){
this.value = v;
}
How about this method? Would it still be considered overloading since it's returning a different data type?
public int setValue(){
return this.value;
}
Second question is: what is overriding
in java? Does it relate to inheritance. Let's I have the following:
public class Vehicle{
double basePrice = 20000;
//constructor defined
public double getPrice(){
return basePrice;
}
}
public class Truck extends Vehicle{
double truckPrice = 14000;
//constructor defined
public double getPrice(){
return truckPrice;
}
}
So now let's say I have the following
Truck truck = new Truck();
if I call
truck.super.getPrice()
this would return the price from the Vehicle class, 20,000
if I call
truck.getPrice()
this would return the price in the truck class, 14,000
Is my knowledge correct for both questions?
You are basically correct. Overloading is having multiple methods in a single class where the method has the same name. However, the return value is not seen as part of the signature of the method. Thus, you cannot overload a method by changing only the return value. You cannot have the following code, from your example:
public void setValue() {
this.value = 0;
}
public int setValue() {
return this.value;
}
This will fail to compile.
As Rob identified, I believe you mean overriding, and you have that correct. Note with overriding, you cannot change the return type. As of Java 5, you can return a derived type of what the base class method returned. Before Java 5, it must be the identical type. That is, you cannot do the below until Java 5 and later:
public class AnimalNoise {}
public class Miaw extends AnimalNoise {}
public class Animal {
public AnimalNoise makeNoise() {
return new AnimalNoise();
}
}
public class Cat extends Animal {
public Miaw makeNoise() {
return new Miaw ();
}
}
However, even in Java 5 and later, you cannot do the following:
public class Animal {
public String makeNoise() {
return "silence";
}
}
public class Cat extends Animal {
public Miaw makeNoise() {
return new Miaw ();
}
}
public class Miaw {}
Finally, a big difference between overloading and overriding that is often overlooked is that overloading is decided at compile time and overriding is decided at runtime. This catches many people by surprise when they expect overloading to be decided at runtime.
Correct; overloading is providing multiple signatures for the same method.
Overriding, which is what I think you mean by "overwriting" is the act of providing a different implementation of a method inherited from a base type, and is basically the point of polymorphism by inheritance, i.e.
public class Bicycle implements Vehicle {
public void drive() { ... }
}
public class Motorcycle extends Bicycle {
public void drive() {
// Do motorcycle-specific driving here, overriding Bicycle.drive()
// (we can still call the base method if it's useful to us here)
}
}
what you have described is correct.
For more clarification take a look at polymorphism concept. The Wikipedia has a good article
http://en.wikipedia.org/wiki/Polymorphism#Computing
http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming

Categories