Calling virtual method from a constructor - java

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.

Related

Java how to make a method argument accept subclass type and superclass

I have a superclass and one subclass with some variables like below:
public class A{
private int first;
private int second;
public A(int _first, int _second){
first = _first;
second = _second;
}
public int getFirst(){
return first;
}
}
public class B extends A{
private int third;
public B(int _first, int _second, int _third){
super(_first, _second);
third = _third;
}
public int getThird(){
return third;
}
}
I want to build a method in the main class that accepts a generic argument that can be of type A or type B like below:
public class Main{
public int val = 2;
public static void main(String []args){
A a = new A(1, 2);
B b = new B(1, 2, 3);
printObject(a);
printObject(b);
}
public void printObject(A a){
int f = a.getFirst() * val;
int s = a.getSecond() * val;
if(a instanceOf B){
int t = a.getThird() * val; // compiler does not find the getThird() method this way
}
}
}
How can this be achieved?. is generics an option? I have thought about making printObject() method inside A then override it inside B however I have some other variable like val above that I am creating in main.
update
I tried to use instanceOf like the above method. But this way the compiler does not find the subclass's specific method.
Firstly, by definition, if you declare A as a parameter to any method and B is it's sub-class, then any A or B can be passed to that method.
You could then achieve what you want using the instanceof operator (to check if the parameter passed in is of type B). However, inheritance / method override should typically be used rather than instanceof.
You could pass 'val' into the printObject() methods on A/B. If several variables like 'val' are involved you could pass in another object or perhaps you need to split your code across multiple methods on class A (overridden in B), passing in different values as appropriate? (You wouldn't normally do calculations in a method whose purpose is to print an object but perhaps that was just an example?)
Everything is much simplier) You could get rid of this method in the main class, cause it's producing some redundant coupling. And all this instanceof really smells in 2019. You could make it more independent.
Class A:
public class A{
private int first;
private int second;
public A(int _first, int _second){
first = _first;
second = _second;
}
public int getFirst(){
return this.first;
}
public int getSecond(){
return this.second;
}
public void print(int multiplier) {
System.out.println(this.first * multiplier);
System.out.println(this.second * multiplier);
}
}
Class B:
public class B{
private int third;
public B(int _first, int _second, int _third){
super(_first, _second);
third = _third;
}
public int getThird(){
return this.third;
}
#Override
public void print(int multiplier) {
super.print(multiplier);
System.out.println(this.third * multiplier);
}
}
Class Main:
public class Main{
public int val = 2;
public static void main(String []args){
A a = new A(1, 2);
B b = new B(1, 2, 3);
a.print(val);
b.print(val);
}
}
Writing object oriented code is more than extending a class , your API's and other functionality should be designed as part of the solution.
In your case, the most appropriate way to do this is to add the print method to the object itself, you can either override the entire function or to call the super class inside the overriding class.
public class A{
/// ... your code
public void print(){
System.out.println("first :"+first+", second : "+second);
}
}
public class B extends A{
/// ... your code
public void print(){
//Option A - use parent class getters/setters to implement print for object B
System.out.println("first :"+super.getFirst()+", second : "+super.getsecond() +" third" + third);
}
//Option B (More usable to methods returning a value or performing an update) - Perform operation on parent variables, then perform on class specific variables
super.print()
System.out.println("third : "+third);
}
}
and then
A a = new A();
A b = new B();
a.print();
b.print();
Will each call the correct runtime function based on their actual implementation

What does makes those methods calls returns those values?

I need to write what is the output of those methods calls.
My answer was:
I i = new A();
i.m(b);
My answer: m_IB because I doesn't have any method with a B type so I went down to class A which implements I. A doesn't also have any methods with parameter B but it extends I.IImpl which has a method with m(B b) that prints m_IB.
I j = new B();
j.m(b);
My answer: m_BB becuase again I doesn't have any method with a B type so I went down to class B because I j = new B() and it has a m(B b) which print m_BB.
interface I {
public void m(A a);
class IImpl {
public static void m(B b) { System.out.println("m_IB"); }
}
}
class A extends I.IImpl implements I {
public void m(A a) { System.out.println("m_AA"); }
}
class B extends A {
public void m(A a) {
super.m(a);
System.out.println("m_BA");
}
public static void m(B b) { System.out.println("m_BB"); }
}
public class Interfac {
public static void main(String[] args) {
A a = new A();
B b = new B();
a.m(b); System.out.println(); // m_IB
I i = new A();
i.m(b); System.out.println(); // m_AA
I j = new B();j.m(b); // m_AA m_BA
}
}
Both of my answers are wrong and the correct output is m_AA for i and m_AA m_BA for j.
I can't understand why I get this output even if I'm calling a method with a type B.
Both of the correct answer are calling a m(A a) methods.
Your interface provides this method:
public void m(A a);
And your j is declared like this:
I j = new B();
So, yes, it's an instance of B, but it is declared as an I, meaning, when you call that method, it calls the method provided by the interface, not the overloaded one.
So, in class B it takes the method that is provided by the interface:
public void m(A a) { // this one
super.m(a);
System.out.println("m_BA");
}
// not this overloaded one
public static void m(B b) { System.out.println("m_BB"); }
The first line of that method is:
super.m(a);
Which calls the m(a) method in the A class, which then prints: "m_AA".
Then, it prints "m_BA"

Calling an overridden superclass method from a subclass

public class F {
protected int a=0, b=0;
public F() {
a = 2;
b = 2;
}
public void increase() {
upA();
}
public void upA() {
a = a + 1;
}
public String toString() {
return a+" "+b;
}
}
public class G extends F {
public void increase() {
super.increase();
upB();
}
public void upA() {
a = a + a;
}
public void upB() {
b = b + 1;
}
}
What is printed in the Output window by the following Java fragment?
G g = new G();
g.increase();
System.out.println(g);
Can someone explain to me why the answer is 4,3
(ie. the subclass method is called even though I have called super.increase() which calls the upA method in the superclass?)
All your methods are being called virtually, with overrides applying. So this code in F:
public void increase() {
upA();
}
... is invoking G.upA(), because the object it's calling upA() on is an instance of G.
So the execution flow for increase() is:
G.increase() calls super.increase()
F.increase() calls upA()
G.upA() executes (so a = 4)
G.increase() calls upB()
G.upB() executes (so b = 3)
Think of increase() as being implemented like this
public void increase() {
this.upA();
}
and then ask yourself what object "this" is.
You are seeing "polymorphic" behaviour, and it's a really powerful feature of Object languages.
Note that you can write
F gInDisguiseAsAnF = new G();
gInDisguiseAsAnF.increase();
and still get the same result. Which version of the upA() method is selected on the basis of the type that was newed.
public void increase() {
upA();
}
is same as this.upA(), so the method in G was called, since this is instance of G.
calling super won't restrict your current instance only in super type.
This is being called from increase() of F
public void upA() {
a = a + a; // a=2+2
}
Not,
public void upA() {
a = a + 1; //not a=2+1
}

Question about polymorphism and overloading

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.

Inheritance in Java

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());
}
}

Categories

Resources