I'm trying to understand the concepts of polymorphism and overloading. I have the following code as a sort of experiment. I cannot figure out, however, why this program does not run (it fails because of mobj.foo(str). mobj is defined using polymorphism, and from what I can gather, should be of type MyDerivedClass. If that were true though, wouldn't the line in question work fine?
Why is that line invalid?
class MyBaseClass {
protected int val;
public MyBaseClass() { val = 1; }
public void foo() { val += 2; }
public void foo(int i) { val += 3; }
public int getVal() { return val; }
}
class MyDerivedClass extends MyBaseClass {
public MyDerivedClass () { val = 4; }
public void foo() { val += 5; }
public void foo(String str) { val += 6; }
}
class Test {
public static void main(String[] args)
{
MyBaseClass mobj = new MyDerivedClass();
String str = new String("hello");
mobj.foo();
mobj.foo(str);
mobj.foo(4);
System.out.println("val = " + mobj.getVal());
}
}
its failing because of
MyBaseClass mobj = new MyDerivedClass();
you told the compiler that mobj is a MyBaseClass, so it doesn't know that there is a foo(String) method.
That sort of thing gets resolved at runtime.
Polymorphism only works when you are overriding a method that the parent has already defined, which is not the case with mobj.foo(str). MyBaseClass does not implement a class with signature foo(String). So foo(String) implemented in MyDerivedClass is not overriding anything. Remember java distinguishes methods by name and parameters.
mobj is an instance of MyDerivedClass, but of type MyBaseClass. So you can call only the methods defined for MyBaseClass on mobj. That's why mobj.foo(str) fails.
Related
In Java,
class BlaBlaThirty extends Parent {
void foo(String s, int i) {}
}
class BlaBlaTwentyNine extends Parent {
void foo(int i, Bla a, This t, Other o) {}
}
class BlaBlaFive extends Parent {
void foo(Bla a, Other o) {}
}
...
Many different classes all with a method foo().
ArrayList<Object> arr;
arr.add(blablai);
arr.add(blablaj);
arr.add(blablak);
...
array arr contains many objects which are instances of these classes.
The problem is that all these foo() methods do not have the same parameters. How to call these methods with the right parameters?
arr.get(i).foo(?,?,?);
my solution:
all foo method have one ArrayList params parameter which contains all the needed parameters as Object :
class BlaBlaX {
void foo(ArrayList<Object> params) {}
}
then, I add the variables names of the variables needed in foo() in the class containing foo. before calling foo(), I call getFooParams() :
class BlaBlaTwentyTwo extends Parent {
ArrayList<Object> getFooParams() {
ArrayList<String> p;
p.add("i");
p.add("banana");
p.add("volkswagen");
return p;
}
void foo(ArrayList<Object> params) {
Int i = (int) params.get(0);
Fruit banana = (Fruit) params.get(1);
Car volkswagen = (Car) params.get(2);
}
}
object calling foo() methods contains all the variables required in foo() :
class ObjCallingFoo {
int i;
Fruit banana;
car volkswagen;
//see below for what is here to call foo()
}
import java.lang.reflect.Method;
import java.lang.reflect.Field;
p = arr.get(i).getFooParams();
int size = p.size();
ArrayList<Object> arrParams = new ArrayList<>();
for (int i = 0; i < size; i++) {
String variableName = p.get(i);
Field field = objCallingFoo.getClass.getField(variableName);
arrParams.add(field);
}
I can now call foo with the right parameters :
arr.get(i).foo(arrParams);
I haven't tested yet.
What do you think of that?
Is it possible to store code in an object that can be run from another object?
OR
How to call a method with parameters of another object if we don't know what are the specific member variables to pass as parameters to the method in calling object?
You need an abstraction that includes the specific method to call and how to call it. This is what the Strategy and Command design patterns can do.
In general, you can use instanceof:
Object parent = obj.get(i);
if(parent instanceof BlaBlaThirty)
((BlaBlaThirty)parent).foo(?,?);
else if(parent instanceof BlaBlaTwentyNine)
((BlaBlaTwentyNine)parent).foo(?,?,?);
else if(parent instanceof BlaBlaFive )
((BlaBlaFive )parent).foo(?,?);
P.S. This is not good to hold all these objects in one list. Your code organization should be refactored indeed!
You could have different constructors and a basic method foo() in Parent.
Then you can override it in every class und do something different with the fields.
But i think it is an option but maybe you should refactor your code/abstraction/inheritance in another way.
class Parent {
void foo(){}
}
class BlaBlaThirty extends Parent {
//Contructor with String s, int i
void foo() {
//Do something here with fields String s, int i
}
class BlaBlaTwentyNine extends Parent {
//Contructor with int i, Bla a, This t, Other o
void foo() {
//Do something here with fields int i, Bla a, This t, Other o
}
class BlaBlaFive extends Parent {
//Constructor Bla a, Other o
void foo() {
//Do something here with fields Bla a, Other o
}
...
Many different classes all with a method foo().
ArrayList<Parent> parent;
parent.add(blablai);
parent.add(blablaj);
parent.add(blablak);
...
parent.foo()
parent.foo()
parent.foo()
You may want to use a interface:
public interface Blainterface{
public void foo();
}
public class BlaBlaTwentyNine extends Parent implements Blainterface {
public void foo() {}
}
....
ArrayList<Blainterface> obj;
obj.add(blablai);
obj.add(blablaj);
obj.add(blablak);
//now you can acces it like
obj.get(2).foo();
It gets even better. You may have a class that doesn't implement the interface but with a method that looks the same:
public interface Blainterface{
public void foo();
}
public class Blubclass{
public void bar(){ //note its bar here and not foo()!!!
//do something cool!
}
}
//...
ArrayList<Blainterface> obj;
obj.add(blablai);
obj.add(blablaj);
obj.add(blablak);
Blubclass blub = new Blubclass(); //note that blub has no foo() method.
obj.add(blub::bar);
//And that call will work too:
obj.get(3).foo(); //this will call bar() in the Blubclass.
now one step further with someting that has different parameters:
public interface Blainterface{
public void foo();
}
public class Bazclass{
public void baz(Sting name){ //note its baz here and not foo() and it has a parameter!!!
//do something cool!
}
}
//...
ArrayList<Blainterface> obj;
obj.add(blablai);
obj.add(blablaj);
obj.add(blablak);
Bazclass baz = new Bazclass(); //note that baz has no foo() method and a parameter.
obj.add(()->baz.baz("name"));//mapping of parameters
//And that call will work too:
obj.get(3).foo(); //this will call baz("name") in the Bazclass. Even though we use a different method name and parameters for the call.
Only thing you need is to define the signature you want to use, when you call the methods, in an interface.
And you have to tell java how to map the parameters(it cant't guess).
Finally what I may do,
class FooParamsNeeded {
public boolean blaBlaI;
public boolean blaBlaJ;
public boolean i;
public boolean blaBlaK;
public boolean banana;
public boolean blaBlaL;
public boolean volkswagen;
public boolean blaBlaM;
...
}
//------------ in object where foo() is, there is a specic getFooParams() method with parameters needed set to true----------
FooParamsNeeded getFooParams() {
FooParamsNeeded fpn = new FooParamsNeeded();
fpn.i = true;
fpn.banana = true;
fpn.volkswagen = true;
return fpn;
}
//--------------------
class FooParams {
public BlaBlaI blaBlaI;
public BlaBlaJ blaBlaJ;
public int i;
public BlaBlaK blaBlaK;
public Fruit banana;
public BlaBlaL blaBlaL;
public Car volkswagen;
public BlaBlaM blaBlaM;
...
}
//-------in object where other object's foo() method is called-----
FooParams setFooParams(FooParamsNeeded fpn) {
FooParams fp = new FooParams();
if (fpn.blaBlaI)
fp.blaBlaI = blaBlaI;
if (fpn.blaBlaJ)
fp.blaBlaJ = blaBlaJ;
if (fpn.i)
fp.i = i;
if (fpn.blaBlaK)
fp.blaBlaK = blaBlaK;
if (fpn.banana)
fp.banana = banana;
if (fpn.blaBlaL)
fp.blaBlaL = blaBlaL;
if (fpn.volkswagen)
fp.volkswagen = volkswagen;
if (fpn.blaBlaM)
fp.blaBlaM = blaBlaM;
...
return fp;
}
FooParamsNeeded fpn = arr.get(i).getFooParams();
FooParams fp = setFooParams(fpn);
arr.get(i).foo(fp);
//-------------------------------------
I think I should have 10-15 possible different paramaters and so 10-15 if statements in setFooParams().
Can someone explain why the function prints the variable from super and not from the subclass? Class variables cannot be overridden in Java?
class A {
int i = 1;
int fun() {
return i;
}
}
class B extends A {
int i = 2;
}
class Main {
public static void main(String[] args) {
System.out.println(new B().fun());
}
}
This prints out 1 instead of 2.
Because fields declared in the subclass never override fields of the super class.
Overriding is for methods.
If you want to use the i value of the current class, you could introduce getI() a method to provide the i value :
class A {
int i = 1;
int fun() {
return getI();
}
int getI(){
return i;
}
}
And override it in the subclass :
class B extends A {
int i = 2;
int getI(){
return i;
}
}
You are returning the value of i from fun() function . if you want to return the value of override variable from class B need to override that method, as fun method is a part of the super class it is referring i of super class only.
But always remember overriding of variable in java is always a bad idea it may give you unexpected result.
if you still want you can use this way.
class A {
int i = 1;
int fun() {
return i;
}
}
class B extends A {
int i = 2;
int fun() {
return i;
}
}
class Main {
public static void main(String[] args) {
System.out.println(new B().fun()); // this will refer the override i
}
}
public class MyTest {
public static void main(final String[] args) {
B b = new B();
b.print();
}
}
class A {
private final int x = 5;
protected int getX() {
return x;
}
public void print() {
System.out.println(getX());
}
}
class B extends A {
private final int x = 10;
#Override
protected int getX() {
return x;
}
}
In this example, I need to print subclass value in the parent class.
It is working fine. No issue.
Now it is printing 10.
But I do not want to define that property in the parent class A.
Because in this example this x datatype is very simple. So no issue.
But in real-time I want to use other datatype which may be another Class variable or List<something> which have huge data.
So ultimately I do not wish to store that value in Class A.
Because it is redundant data. It will slow down in my Hibernate thing.
Please let me know, how to achieve this without declaring variable in parent class. But I still need to use subclass variable in parent class.
make abstract your class A and the getX(); method.
public class Test {
public static void main(final String[] args) {
B b = new B();
b.print();
}
}
abstract class A {
protected abstract int getX();
public void print() {
System.out.println(getX());
}
}
class B extends A {
private final int x = 10;
#Override
protected int getX() {
return x;
}
}
and override the toString method in place of your print method
#Override
public String toString() {
return String.valueOf(getX());
}
the final code
public class Test {
public static void main(final String[] args) {
B b = new B();
System.out.println(b);
}
}
abstract class A {
protected abstract int getX();
#Override
public String toString() {
return String.valueOf(getX());
}
}
class B extends A {
private static final int X = 10;
#Override
protected int getX() {
return X;
}
}
you could also define as static your x variable
But as say Andrew Tobilko you can consider also to use an interface if A doesn't represent a stateful entity.
It's certainly the best solution for your case, mix the use of an interface and an abstract class
public class Test {
public static void main(final String[] args) {
B b = new B();
System.out.println(b);
}
}
interface MyInterface {
int getX();
}
abstract class A implements MyInterface{
#Override
public String toString() {
return String.valueOf(getX());
}
}
class B extends A {
private static final int X = 10;
#Override
public int getX() {
return X;
}
}
You need the getX within the parent class, but you don't have information enough to implement this method there.
You can declare this class as abstract and mark the method with abstract as well. Doing that, you are handing the responsibility of method implementation over its subclasses and preventing from parent field declaration.
If the A doesn't describe any state (only actions/methods), you should consider replacing it with an interface. At the current state, it is the case.
You could make the parent class abstract, eliminate the property in the parent class, make getX() abstract, and then leave print() as concrete. Then just use the concrete implementation of getX() in the child class.
Java 8
I was just a little perplexed by that we could not call virtual method from a constructor. The pitfall is that we can overload it and crash. But what if we call it from within a constructor of a final class. Like this:
public final class MyClass implements MyInterface {
private final Object[] arr;
public MyClass(){
Object[] arr;
//init arr
this.arr = arr;
//Now we have to preprocess it
preprocess();
}
#Override
public void preprocess(){
//impl
}
public int count(){
//impl
}
}
public interface MyInterface{
void preprocess();
int count();
}
Are there other pitfalls with calling virtual methods from within a constructor? Of course, I can extract preprocess into a static method and then call it from both, but it looks a little messy. I'd like to keep code as clean as possible.
You should always take care when calling methods from a constructor, because the object construction is not yet complete. This is true even for final and private methods, which cannot be overridden by subclasses.
Example:
public class Test {
public static void main(String[] args) {
new Sub().test();
}
}
class Base {
int b;
Base() {
test();
this.b = 1;
}
void test() {
System.out.println("Hello from Base. b = " + this.b);
}
}
class Sub extends Base {
int s;
Sub() {
test();
this.s = 2;
}
#Override
void test() {
System.out.println("Hello from Sub. b = " + this.b + ", s = " + this.s);
}
}
OUTPUT
Hello from Sub. b = 0, s = 0
Hello from Sub. b = 1, s = 0
Hello from Sub. b = 1, s = 2
test() is called 3 times: From Base constructor, from Sub constructor, and from main().
As you can see, even field b was not yet initialized on the first call.
So, is it illegal to do it? No.
Should you avoid it? Yes.
Just make it clear (e.g. javadoc) that the method may be called on partially initialized objects.
Consider the following code in Python:
class A(object):
CLASS_ATTRIBUTE = 42
def f(self):
return "CLASS_ATTRIBUTE: %d" % self.CLASS_ATTRIBUTE
class B(A):
CLASS_ATTRIBUTE = 44
Now A().f() and B().f() return "CLASS_ATTRIBUTE: 42" and "CLASS_ATTRIBUTE: 44" respectively.
How can I achieve a similar effect in Java? I want a CLASS_ATTRIBUTE field to be initialized statically and redefined in the inherited class but the f method should be only defined in the base class.
Is there a particular reason you want the attribute to be static? In Java the typical way you'd do this is to have A contain a protected variable that you then set in the constructors of the 2 classes:
public class A
{
protected int CLASS_ATTRIBUTE;
public A()
{
CLASS_ATTRIBUTE = 42;
}
public String f()
{
return "CLASS_ATTRIBUTE: " + CLASS_ATTRIBUTE;
}
}
public class B extends A
{
public B()
{
CLASS_ATTRIBUTE = 44;
}
}
Alternatively (and probably more consistent with Java design patterns) you'd declare a function that you can override to return the value instead of using a member variable.
Short answer: you cant solve it like this in Java. You'll have to solve it in another way.
In Java you can't override or "redeclare" fields in subclasses, and you can't override static methods.
It can be solved using an ugly reflection-hack (should be avoided though):
public class Main {
public static void main(String... args) {
A a = new A();
B b = new B();
System.out.println(a.f()); // Prints 42.
System.out.println(a.fReflection()); // Prints 42.
System.out.println(b.f()); // Prints 42.
System.out.println(b.fReflection()); // Prints 44.
}
}
class A {
static int CLASS_ATTRIBUTE = 42;
public int f() {
return CLASS_ATTRIBUTE;
}
public int fReflection() {
try {
return getClass().getDeclaredField("CLASS_ATTRIBUTE").getInt(null);
} catch (Exception wontHappen) {
return -1;
}
}
}
class B extends A {
// Compiles, but will not "override" A.CLASS_ATTRIBUTE.
static int CLASS_ATTRIBUTE = 44;
}
You can't do this directly with only a variable, because in Java variables cannot override (they only shadow the super classes variables).
You need to use a protected "getter" method, which can then be overridden by the subclass:
class A
{
private int attribute=42;
...
protected int getAttribute() {
return attribute;
}
}
class B
extends A
{
private int attribute=44;
...
protected int getAttribute() {
return attribute;
}
}
But note there's a special consideration to calling methods from an object's constructor, in that it allows object code to run before object construction is complete.
I'm not sure if you meant "statically" literally or not, but here's a brief example of how inheritance at it's most basic form looks in Java. Note that using a getter method to access the variable is a better idea for several reasons -- this is just an example.
public class Dog {
protected String whatISay = "Woof!";
public void speak(){
System.out.println(whatISay);
}
}
public class Poodle extends Dog {
public Poodle(){
whatISay = "Yap!";
}
}
public class Main {
public static void main(String[] args){
Poodle fluffy = new Poodle();
fluffy.speak();
Dog dog = new Dog();
dog.speak();
}
}
Yap!
Woof!
This way of doing it introduces as little intrusion as I could think of. setAttribute() could be named something like setDefaultValue() if that's clearer.
public class A
{
protected int attribute;
public A()
{
setAttribute();
}
public String f()
{
return "CLASS_ATTRIBUTE: " + attribute;
}
protected void setAttribute()
{
attribute = 42;
}
}
public class B extends A
{
#Override
protected void setAttribute()
{
attribute = 44;
}
}
public class Main
{
public static void main(String[] args)
{
A a = new A();
B b = new B();
System.out.println("A: " + a.f());
System.out.println("B: " + b.f());
}
}