Calling child attributes before super()? - java

I work primarily with dynamic languages - I've just started playing with Java, and I'm struggling with a static pattern.
From what I understand, the first call in the constructor of a child class has to be to its parent. That's fine, but I need to set instance variables in the child that are referenced in the constructor of the parent...which, of course, creates a catch-22. (Need to set variables in child before calling parent, but need to call parent before setting variables in child).
I'm sure I'm breaking some sort of static language pattern or law...I'm just not sure which one, or how to redesign it. Any help appreciated. Stripped down example below:
Class Race {
public Race(Venue event_venue) {
greeting();
}
public void greeting() {
String event_greeting = String.format("The next event is: %s", getName());
System.out.println(event_greeting);
}
public String getName() {
return getClass().getSimpleName();
}
}
Class Sprint extends Race {
private int event_distance;
public Sprint(Venue event_venue, int distance) {
// super has to be the first call
super(event_venue);
// but I need to set event_distance to reference getName() in parent constructor
setDistance(distance);
}
public String getName() {
String sprint_name = String.format("%s meter sprint", Integer.toString(getDistance());
return sprint_name;
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
event_distance = distance;
}
}

You have side-effects in your constructor, which is frowned upon. For best results, put the side-effects in an other method. You have this already, so just specify in the javadoc that greeting() should be called after construction (or, it could be called by the subclass constructors, but then sub-subclasses will have the same problem).

I assume each race will have a distance, so why not make this field part of the supertype. This field can then be set via an argument provided to the constructor.
Class Race {
private int event_distance;
public Race(Venue event_venue, int distance) {
this.distance = distance;
greeting();
}
public void greeting() {
String event_greeting = String.format("The next event is: %s", getName());
System.out.println(event_greeting);
}
public String getName() {
return getClass().getSimpleName();
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
event_distance = distance;
}
}
Providing distance as argument to super constructor:
Class Sprint extends Race {
private int event_distance;
public Child(Venue event_venue, int distance) {
super(event_venue, distance);
}
/* omitted rest of class */
}

Yes, that does not work.
You need to refactor your code in ways that make it possible to execute the constructors in their proper order. Usually this is not a problem if the constructors do not have side-effects and do not call methods that can be overridden in subclasses (both of which are discouraged patterns).
public Race(Venue event_venue) {
greeting(); // constructor should not call non-final method
}
// method called by a constructor should not print anything
public void greeting() {
String event_greeting = String.format("The next event is: %s", getName());
System.out.println(event_greeting);
}

Related

How to overload a GUI constructor? [duplicate]

Is it possible to call a constructor from another (within the same class, not from a subclass)? If yes how? And what could be the best way to call another constructor (if there are several ways to do it)?
Yes, it is possible:
public class Foo {
private int x;
public Foo() {
this(1);
}
public Foo(int x) {
this.x = x;
}
}
To chain to a particular superclass constructor instead of one in the same class, use super instead of this. Note that you can only chain to one constructor, and it has to be the first statement in your constructor body.
See also this related question, which is about C# but where the same principles apply.
Using this(args). The preferred pattern is to work from the smallest constructor to the largest.
public class Cons {
public Cons() {
// A no arguments constructor that sends default values to the largest
this(madeUpArg1Value,madeUpArg2Value,madeUpArg3Value);
}
public Cons(int arg1, int arg2) {
// An example of a partial constructor that uses the passed in arguments
// and sends a hidden default value to the largest
this(arg1,arg2, madeUpArg3Value);
}
// Largest constructor that does the work
public Cons(int arg1, int arg2, int arg3) {
this.arg1 = arg1;
this.arg2 = arg2;
this.arg3 = arg3;
}
}
You can also use a more recently advocated approach of valueOf or just "of":
public class Cons {
public static Cons newCons(int arg1,...) {
// This function is commonly called valueOf, like Integer.valueOf(..)
// More recently called "of", like EnumSet.of(..)
Cons c = new Cons(...);
c.setArg1(....);
return c;
}
}
To call a super class, use super(someValue). The call to super must be the first call in the constructor or you will get a compiler error.
[Note: I just want to add one aspect, which I did not see in the other answers: how to overcome limitations of the requirement that this() has to be on the first line).]
In Java another constructor of the same class can be called from a constructor via this(). Note however that this has to be on the first line.
public class MyClass {
public MyClass(double argument1, double argument2) {
this(argument1, argument2, 0.0);
}
public MyClass(double argument1, double argument2, double argument3) {
this.argument1 = argument1;
this.argument2 = argument2;
this.argument3 = argument3;
}
}
That this has to appear on the first line looks like a big limitation, but you can construct the arguments of other constructors via static methods. For example:
public class MyClass {
public MyClass(double argument1, double argument2) {
this(argument1, argument2, getDefaultArg3(argument1, argument2));
}
public MyClass(double argument1, double argument2, double argument3) {
this.argument1 = argument1;
this.argument2 = argument2;
this.argument3 = argument3;
}
private static double getDefaultArg3(double argument1, double argument2) {
double argument3 = 0;
// Calculate argument3 here if you like.
return argument3;
}
}
When I need to call another constructor from inside the code (not on the first line), I usually use a helper method like this:
class MyClass {
int field;
MyClass() {
init(0);
}
MyClass(int value) {
if (value<0) {
init(0);
}
else {
init(value);
}
}
void init(int x) {
field = x;
}
}
But most often I try to do it the other way around by calling the more complex constructors from the simpler ones on the first line, to the extent possible. For the above example
class MyClass {
int field;
MyClass(int value) {
if (value<0)
field = 0;
else
field = value;
}
MyClass() {
this(0);
}
}
Within a constructor, you can use the this keyword to invoke another constructor in the same class. Doing so is called an explicit constructor invocation.
Here's another Rectangle class, with a different implementation from the one in the Objects section.
public class Rectangle {
private int x, y;
private int width, height;
public Rectangle() {
this(1, 1);
}
public Rectangle(int width, int height) {
this( 0,0,width, height);
}
public Rectangle(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
}
This class contains a set of constructors. Each constructor initializes some or all of the rectangle's member variables.
As everybody already have said, you use this(…), which is called an explicit constructor invocation.
However, keep in mind that within such an explicit constructor invocation statement you may not refer to
any instance variables or
any instance methods or
any inner classes declared in this class or any superclass, or
this or
super.
As stated in JLS (§8.8.7.1).
Yes, any number of constructors can be present in a class and they can be called by another constructor using this() [Please do not confuse this() constructor call with this keyword]. this() or this(args) should be the first line in the constructor.
Example:
Class Test {
Test() {
this(10); // calls the constructor with integer args, Test(int a)
}
Test(int a) {
this(10.5); // call the constructor with double arg, Test(double a)
}
Test(double a) {
System.out.println("I am a double arg constructor");
}
}
This is known as constructor overloading.
Please note that for constructor, only overloading concept is applicable and not inheritance or overriding.
Using this keyword we can call one constructor in another constructor within same class.
Example :-
public class Example {
private String name;
public Example() {
this("Mahesh");
}
public Example(String name) {
this.name = name;
}
}
Yes it is possible to call one constructor from another. But there is a rule to it. If a call is made from one constructor to another, then
that new constructor call must be the first statement in the current constructor
public class Product {
private int productId;
private String productName;
private double productPrice;
private String category;
public Product(int id, String name) {
this(id,name,1.0);
}
public Product(int id, String name, double price) {
this(id,name,price,"DEFAULT");
}
public Product(int id,String name,double price, String category){
this.productId=id;
this.productName=name;
this.productPrice=price;
this.category=category;
}
}
So, something like below will not work.
public Product(int id, String name, double price) {
System.out.println("Calling constructor with price");
this(id,name,price,"DEFAULT");
}
Also, in the case of inheritance, when sub-class's object is created, the super class constructor is first called.
public class SuperClass {
public SuperClass() {
System.out.println("Inside super class constructor");
}
}
public class SubClass extends SuperClass {
public SubClass () {
//Even if we do not add, Java adds the call to super class's constructor like
// super();
System.out.println("Inside sub class constructor");
}
}
Thus, in this case also another constructor call is first declared before any other statements.
I will tell you an easy way
There are two types of constructors:
Default constructor
Parameterized constructor
I will explain in one Example
class ConstructorDemo
{
ConstructorDemo()//Default Constructor
{
System.out.println("D.constructor ");
}
ConstructorDemo(int k)//Parameterized constructor
{
this();//-------------(1)
System.out.println("P.Constructor ="+k);
}
public static void main(String[] args)
{
//this(); error because "must be first statement in constructor
new ConstructorDemo();//-------(2)
ConstructorDemo g=new ConstructorDemo(3);---(3)
}
}
In the above example I showed 3 types of calling
this() call to this must be first statement in constructor
This is Name less Object. this automatically calls the default constructor.
3.This calls the Parameterized constructor.
Note:
this must be the first statement in the constructor.
You can a constructor from another constructor of same class by using "this" keyword.
Example -
class This1
{
This1()
{
this("Hello");
System.out.println("Default constructor..");
}
This1(int a)
{
this();
System.out.println("int as arg constructor..");
}
This1(String s)
{
System.out.println("string as arg constructor..");
}
public static void main(String args[])
{
new This1(100);
}
}
Output -
string as arg constructor..
Default constructor..
int as arg constructor..
Calling constructor from another constructor
class MyConstructorDemo extends ConstructorDemo
{
MyConstructorDemo()
{
this("calling another constructor");
}
MyConstructorDemo(String arg)
{
System.out.print("This is passed String by another constructor :"+arg);
}
}
Also you can call parent constructor by using super() call
There are design patterns that cover the need for complex construction - if it can't be done succinctly, create a factory method or a factory class.
With the latest java and the addition of lambdas, it is easy to create a constructor which can accept any initialization code you desire.
class LambdaInitedClass {
public LamdaInitedClass(Consumer<LambdaInitedClass> init) {
init.accept(this);
}
}
Call it with...
new LambdaInitedClass(l -> { // init l any way you want });
Pretty simple
public class SomeClass{
private int number;
private String someString;
public SomeClass(){
number = 0;
someString = new String();
}
public SomeClass(int number){
this(); //set the class to 0
this.setNumber(number);
}
public SomeClass(int number, String someString){
this(number); //call public SomeClass( int number )
this.setString(someString);
}
public void setNumber(int number){
this.number = number;
}
public void setString(String someString){
this.someString = someString;
}
//.... add some accessors
}
now here is some small extra credit:
public SomeOtherClass extends SomeClass {
public SomeOtherClass(int number, String someString){
super(number, someString); //calls public SomeClass(int number, String someString)
}
//.... Some other code.
}
Hope this helps.
Yes it is possible to call one constructor from another with use of this()
class Example{
private int a = 1;
Example(){
this(5); //here another constructor called based on constructor argument
System.out.println("number a is "+a);
}
Example(int b){
System.out.println("number b is "+b);
}
You can call another constructor via the this(...) keyword (when you need to call a constructor from the same class) or the super(...) keyword
(when you need to call a constructor from a superclass).
However, such a call must be the first statement of your constructor. To overcome this limitation, use this answer.
The keyword this can be used to call a constructor from a constructor, when writing several constructor for a class, there are times when you'd like to call one constructor from another to avoid duplicate code.
Bellow is a link that I explain other topic about constructor and getters() and setters() and I used a class with two constructors. I hope the explanations and examples help you.
Setter methods or constructors
I know there are so many examples of this question but what I found I am putting here to share my Idea. there are two ways to chain constructor. In Same class you can use this keyword. in Inheritance, you need to use super keyword.
import java.util.*;
import java.lang.*;
class Test
{
public static void main(String args[])
{
Dog d = new Dog(); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.
Dog cs = new Dog("Bite"); // Both Calling Same Constructor of Parent Class i.e. 0 args Constructor.
// You need to Explicitly tell the java compiler to use Argument constructor so you need to use "super" key word
System.out.println("------------------------------");
Cat c = new Cat();
Cat caty = new Cat("10");
System.out.println("------------------------------");
// Self s = new Self();
Self ss = new Self("self");
}
}
class Animal
{
String i;
public Animal()
{
i = "10";
System.out.println("Animal Constructor :" +i);
}
public Animal(String h)
{
i = "20";
System.out.println("Animal Constructor Habit :"+ i);
}
}
class Dog extends Animal
{
public Dog()
{
System.out.println("Dog Constructor");
}
public Dog(String h)
{
System.out.println("Dog Constructor with habit");
}
}
class Cat extends Animal
{
public Cat()
{
System.out.println("Cat Constructor");
}
public Cat(String i)
{
super(i); // Calling Super Class Paremetrize Constructor.
System.out.println("Cat Constructor with habit");
}
}
class Self
{
public Self()
{
System.out.println("Self Constructor");
}
public Self(String h)
{
this(); // Explicitly calling 0 args constructor.
System.out.println("Slef Constructor with value");
}
}
It is called Telescoping Constructor anti-pattern or constructor chaining. Yes, you can definitely do. I see many examples above and I want to add by saying that if you know that you need only two or three constructor, it might be ok. But if you need more, please try to use different design pattern like Builder pattern. As for example:
public Omar(){};
public Omar(a){};
public Omar(a,b){};
public Omar(a,b,c){};
public Omar(a,b,c,d){};
...
You may need more. Builder pattern would be a great solution in this case. Here is an article, it might be helpful
https://medium.com/#modestofiguereo/design-patterns-2-the-builder-pattern-and-the-telescoping-constructor-anti-pattern-60a33de7522e
Yes, you can call constructors from another constructor. For example:
public class Animal {
private int animalType;
public Animal() {
this(1); //here this(1) internally make call to Animal(1);
}
public Animal(int animalType) {
this.animalType = animalType;
}
}
you can also read in details from
Constructor Chaining in Java
Originally from an anser by Mirko Klemm, slightly modified to address the question:
Just for completeness: There is also the Instance initialization block that gets executed always and before any other constructor is called. It consists simply of a block of statements "{ ... }" somewhere in the body of your class definition. You can even have more than one. You can't call them, but they're like "shared constructor" code if you want to reuse some code across constructors, similar to calling methods.
So in your case
{
System.out.println("this is shared constructor code executed before the constructor");
field1 = 3;
}
There is also a "static" version of this to initialize static members: "static { ... }"
I prefer this way:
class User {
private long id;
private String username;
private int imageRes;
public User() {
init(defaultID,defaultUsername,defaultRes);
}
public User(String username) {
init(defaultID,username, defaultRes());
}
public User(String username, int imageRes) {
init(defaultID,username, imageRes);
}
public User(long id, String username, int imageRes) {
init(id,username, imageRes);
}
private void init(long id, String username, int imageRes) {
this.id=id;
this.username = username;
this.imageRes = imageRes;
}
}

Abstract Class and toString() method

I am a little confused on how to set up the TestHomework method so that it prints properly when using the toString() method. Right now when I run the main method it prints "null - 0" but what I would like it to say is "Math - 6". This program is supposed to extend an abstract class. It is supposed to say how many pages there are for homework and for what subject.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
{
// initialise instance variables
pagesToRead = 0;
typeHomework = "none";
}
public Homework(int pages, String hw) {
this.pagesToRead = pages;
this.typeHomework = hw;
}
public abstract void createAssignment(int p);
public int getPages() {
return pagesToRead;
}
public void setPagesToRead(int p) {
pagesToRead = p;
}
public String getTypeHomework() {
return typeHomework;
}
public void setTypeHomework(String hw) {
typeHomework = hw;
}
}
public class MyMath extends Homework {
private int pagesRead;
private String typeHomework;
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
public String toString() {
return typeHomework + " - " + pagesRead;
}
}
public class TestHomework {
public static void main(String[] args) {
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
System.out.println(one);
}
}
That's because you are defining the 2 properties (that one of them happen to have the same name as one of the abstract class's) but you are not initializing them, you are initializing those of the abstract class. (So their values is always set to their type's default)
You need to drop those from the MyMath class, & define the toString method in your abstract class: it's the one to be used by default by its inheriting classes.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
// Same code
// Define the toString here
#Override
public String toString() {
return typeHomework + " - " + pagesToRead;
}
}
public class MyMath extends Homework {
// You don't need to define any extra attributes
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
}
public static void main(String[] args) {
// Calls the constructor of the MyMath class, which in turn
// invokes the constructor of its superclass, the 'Homework' class
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
// Invokes the toString of the MyMath class. Since it does not have one,
// The toString method of its superclass (Homework) is called.
System.out.println(one);
}
Your derived class has its own typeHomework and pagesRead fields, which are never set (even though the base class happens to have fields with the same names). Therefore, they stay null and 0.
You should delete those fields and use the data from the base class, via the public getter methods.
Why it doesn't work:
Be careful you redeclared the attribute typeHomework of you parent class. Attributes are automatically added to your extending class so you don't have to write them again.
By redeclaring it you confused the compiler, viewing your code in debug shows, that your one object contains your typeHomework twice:
typeHomework = null // The one from the super class
typeHomework = "Math" // The one from your child class
Your method now uses the typeHomework from your super-class therefor the output is null!
pagesRead is 0 because you are setting the pagesToRead of your super-class to 6(not pagesRead!) when calling setPagesToRead(p);.
Some style tips
Use the #Override annotation when overriding methods like this:
#Override
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
It's not really needed but it's good practice (readers of your code know that it overrides something).
When referring to attributes of your class it's also good practice to use the this statement so it's clear, that you're referring to an attribute and not a local variable:
#Override
public String toString() {
return this.typeHomework + " - " + this.pagesRead;
}

A java method with both variable return type and variable input arguments

I have an abstract java class "BaseOperation". This class only has a single abstract method:
public abstract T execute()
{
...
return T;
}
Subclasses of BaseOperation must implement this method:
public class GetUsersOperation extends BaseOperation<GetUsersResponse>
{
...
#Override
public GetUsersResponse execute()
{
...
return GetUsersResponse;
}
}
This is a great way to put all common "operation" logic in the BaseOperation class, but still have every concrete subclass's execute() method have a different return type.
Now I need to change this structure to allow the execute() methods to have a variable amount of arguments. For example, one concrete subclass would require:
execute(String, int)
and another would need:
execute(Date, Date, String)
This is tricky, because the execute method is declared in the base class. Simply overloading the execute methods in the base is not ideal. Firstly, the amount of overloads would be huge. Secondly, every subclass will only ever use one of the execute methods, what's the point of all the others?
The (in my opinion) easiest solution would be to declare the execute method with varargs:
execute(Object... arguments)
And then downcast all arguments in the subclasses:
execute(Object... arguments)
{
String s = (String) arguments[0];
...
}
Obviously this has 2 major downsides:
Reduced performance because of all the downcasting operations
Calling the execute() methods is no longer strictly typed because any amount of objects can be passed witout compiler warnings.
Are there patterns or other solutions that could don't have these disadvantages?
You could use a bean holding the parameters:
public interface BaseOperation<T, U> {
T execute(U input);
}
public class GetUsersOperation implements BaseOperation<GetUsersResponse, UserInput> {
#Override
public GetUsersResponse execute(UserInput input) {
Date date = input.getDate();
return new GetUsersResponse(date);
}
}
Your abstract class only has one single abstract method: better use an interface. You can implement several interfaces while you can extend only one class.
As already said, the common approach for solving your issue is using a bean holding parameters. But here is another solution, based on a builder approach:
public interface BaseOperation<T> {
public T execute();
}
public class AddOperation implements BaseOperation<Integer> {
private int a, b;
public void setA(int arg){
a = arg ;
return this;
}
public void setB(int arg){
b = arg;
return this;
}
#Override
public Integer execute() {
return a+b ;
}
}
And then use it like this :
new AddOperation().setA(1).setB(2).execute();
You can mix required and optional parameters in this way:
public class MultipleAddOperation implements BaseOperation<Integer> {
private int sum ;
public MultipleAddOperation(int requiredInt){
sum = requiredInt;
}
public void add(int optionalInt){
sum += optionalInt ;
return this;
}
#Override
public Integer execute(){
return sum;
}
}
And so:
new MultipleAddOperation(5).add(1).add(2).execute();

How the super function works in java? [duplicate]

This question already has answers here:
super() in Java
(18 answers)
Closed 8 years ago.
Here is a code snippet from the head first design patterns book:
public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) {
super(in);
}
public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toLowerCase((char)c));
}
public int read(byte[] b, int offset, int len) throws IOException {
int result = super.read(b, offset, len);
for (int i = offset; i < offset+result; i++) {
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}
There is another toy example in the same chapter:
public class Mocha extends CondimentDecorator {
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
public double cost() {
return .20 + beverage.cost();
}
}
These two are quite similar except that the Macha class has a concrete object inside that it initialize and use, while the LowerCaseInputStream class initializes an InputStream object by super(in) and later seems to make use of this object by using the super.read() function.
I am a bit confused about how the super function works here. In the Mocha example, it's very clear that it wraps a beverage object inside and calls its methods and modifies the results, while in the LowerCaseInputStream class it's not straight-forward how the behavior modification happened.
In the first case super refers to the constructor in the base class FilterInputStream. If the constructor of a parent class has argument, any class that extends it must explicitly call the appropriate constructor using super. If the base class simply has a no-argument constructor the super is supplied implicitly by Java.
In the second case, FilterInputStream read method has been overloaded by LowerCaseInputStream. This means that any call to LowerCaseInputStream.read() would go to its implementation. So for LowerCaseInputStream to call the read implementation in FilterInputStream (to get the standard behavior) it must reference super otherwise it would be an infinite loop.
The keyword super exists to give child classes access to their parent classes and their exposed public members. That being said:
super(in): Calls the superclass's constructor, passing in the stream as an argument
super.read(): Calls the superclass's read method
super keyword means parent, in this case FilterInputStream
//this invoke parent's constructor like `FilterInputStream(in)`
super(in);
//this invoke parent's read() method
super.read();
Learn basic Java Programming first well and enjoy it.
super() in this case is just a keyword that allows you to call the constructor of the superclass (hence the name). You can call other functions using super.function() too.
Example,
public class A
{
protected String myName;
public A(String name)
{
this.myName = name;
}
public void print(String input)
{
System.out.println("" + input);
}
}
public class B extends A
{
public B(String name)
{
super(name); //calls A(String name) constructor above
}
#Override
public void print(String input)
{
if(input == null || "".equals(input))
{
System.out.println(this.myName);
}
else
{
super.print(input); //calls A.print(String input)
}
}
}
public class Main
{
public static void main(String[] args)
{
B b = new B("qed");
b.print(null); //prints 'qed'
}
}

Enforcing dynamic polymorphic calls with general parent type input arguments

I am trying to use polymorphism to enable different processing of an object based on its class, as follows:
public class GeneralStuff {
private int ID;
}
public class IntStuff extends GeneralStuff {
private int value;
public void setValue(int v)
{
value = v;
}
public int getValue()
{
return value;
}
}
public class DoubleStuff extends GeneralStuff {
private double value;
public void setValue(double v)
{
value = v;
}
public double getValue()
{
return value;
}
}
public class ProcessStuff {
public String process(GeneralStuff gS)
{
return doProcess(gS);
}
private String doProcess(IntStuff i)
{
return String.format("%d", i.getValue());
}
private String doProcess(DoubleStuff d)
{
return String.format("%f", d.getValue());
}
}
public class Test {
public static void main(String[] args)
{
IntStuff iS = new IntStuff();
DoubleStuff dS = new DoubleStuff();
ProcessStuff pS = new ProcessStuff();
iS.setValue(5);
dS.setValue(23.2);
System.out.println(pS.process(iS));
System.out.println(pS.process(dS));
}
}
This, however, doesn't work, because calling doProcess(gS) expects a method with a signature doProcess(GeneralStuff gS).
I know I could just have two exposed polymorphic process methods in the ProcessStuff class, but the actual situation won't allow it because I'm working within the constraints of an existing library mechanism; this is just a contrived example for testing.
I could, of course, define process(GeneralStuff gS) as
public String process(GeneralStuff gS)
{
if (gS instanceof IntStuff)
{
return doProcess((IntStuff) gS);
}
else if (gS instanceof DoubleStuff)
{
return doProcess((DoubleStuff) gS);
}
return "";
}
which works, but it seems that I shouldn't have to do that (plus, the Programming Police would skewer me for using instanceof in this way).
Is there a way that I can enforce the polymorphic calls in a better way?
Thanks in advance for any help.
The type of dynamic dispatch you are looking for is not possible in Java without using reflection. Java does its linking at compile time based on the declared type (so even though a method is overloaded, the actual method invoked is based on the declared type of the variable not the runtime type).
So you are left with either using instanceof as you propose, using reflection, or putting the process methods in the objects themselves (which is the "oop" way to do it, but is often not suitable or advisable).
One potential alternative is to create a map of processing objects by class, eg:
Map<Class<? extends GeneralStuff>,Processor> processors;
public String process(GeneralStuff stuff)
{
Processor processor = processors.get(stuff.getClass());
if (processor != null)
{
return processor.process(stuff);
}
}
public interface Processor
{
public String process(GeneralStuff stuff);
}
public class IntegerProcessor implements Processor
{
public String process(GeneralStuff stuff)
{
return String.format("%i",((IntegerStuff) stuff).getValue());
}
}
However, for your specific example, String.format takes objects as the parameters, so you could avoid this whole issue by having getValue and getFormatString methods in GeneralStuff which are overriden in the specific subclasses.
You are actually on the right track, you indeed need to use reflection in this case. What you are looking for is sort of double dispatch, because you want the dispatch to be done on the dynamic type of the stuff parameter.
This type of switching-on-dynamic-type is not as rare as you think. See for example this javaworld tipe, which reflects on the visitor pattern
The compiler complains for good reason. There is no guarantee that your GeneralStuff object is an IntStuff or a DoubleStuff. It can be a plain GeneralStuff or any other extension of GeneralStuff, which is a case you also did not cover in your process method with the instanceof (unless returning the empty String was the desired behavior).
Is it not possible to move that process method into the GeneralStuff class and override it in the extensions ?
Another possible solution is to have a sort of composite ProcessStuff class in which you plug a IntStuffProcess, DoubleStuffProcess, ... instance . Each of those instances will still have the instanceof check to decide whether they can handle the GeneralStuff object passed to them, but this is at least more scalable/maintainable then one big instanceof construct
Perhaps, it's better to have overloaded process method in ProcessStuff:
public class ProcessStuff {
private String process(IntStuff i) {
return String.format("%d", i.getValue());
}
private String process(DoubleStuff d) {
return String.format("%f", d.getValue());
}
}
Define an GeneralStuff as an abstract class, with a doProcess method (abstract) which is filled in in the inheriting classes. This way you avoid all problems with instanceof values and such. Or you can do what is suggested by βнɛƨн Ǥʋяʋиɢ, but then you still would have to define an overload for each specific class, whereas in mine you just call it directly.
So my suggestion would be:
public abstract class GeneralStuff {
private int ID;
public abstract String process();
}
public class IntStuff extends GeneralStuff {
private int value;
public void setValue(int v)
{
value = v;
}
public int getValue()
{
return value;
}
#override
public String process(){
return String.format("%d", getValue());
}
}
public class DoubleStuff extends GeneralStuff {
private double value;
public void setValue(double v)
{
value = v;
}
public double getValue()
{
return value;
}
#override
public String process(){
return String.format("%f", getValue());
}
}
public class Test {
public static void main(String[] args)
{
IntStuff iS = new IntStuff();
DoubleStuff dS = new DoubleStuff();
ProcessStuff pS = new ProcessStuff();
iS.setValue(5);
dS.setValue(23.2);
System.out.println(iS.process());
System.out.println(dS.process());
}
}

Categories