Avoiding instanceof - unmodifiable classes - java

Suppose I've got two classes A and B such that B extends A, respectively implementing method getA and getB that has the same input parameter types and same return type (but different names). In a method public static <T extends A> void print(T t) getting as input an object of type A or B, I want to call getA if the object is of type A or getB if the object is of type B.
If I could edit the code of A and B I would make them implement an interface I providing getValue() (in the implementation for A and B, getValue() would call getA() and getB() resp.), and then call this method from print(). Problem is: classes A and B are not modifiable!. No methods can be added or changed, their class hierarchy is fixed, I didn't write their code, and I don't have access to the source.
Note that this also applies to the cases when - for any reason - I don't want to change the code of A and B.
Is there any way of doing so without the use of instanceof?
Here follows a solution that uses instanceof (bad!).
public class Test {
public static <T extends A> void print(T t){
if (t instanceof B)
System.out.println(((B)t).getB());
else if (t instanceof A)
System.out.println(t.getA());
}
public static class A {
public String getA(){
return "A";
}
}
public static class B extends A {
public String getB(){
return "B";
}
}
}

When you don't have access to the original code for whatever reason, you end up having to fall back on things like instanceof. In these cases, it's not bad per se - your hands are tied.
What I would do is to create a wrapper class that is genericized on your T, give it a getValue that tests with instanceof as you proposed, and make it clear that the only reason this class exists is to provide a consistent interface for using either an A or a B. It's still gross, but you've contained the grossness in one place.

To extend Matt's answer, I would consider adopting the Facade Pattern for these classes. This means you create a separate class (or two) to wrap all the functionality you require from these two classes. This includes adding a method, as Matt suggests.
The benefit is you decouple your application from an API you have no control over. You also have an opportunity to simplify the API, if you don't require all the methods from the original libraries.

Thank you and #Matt. Guess this one is definitely the cleanest way. Will provide the full code that does not make use of instanceof:
public static void main(String[] args){
A a = new A();
B b = new B();
AWrapper aw = new AWrapper(a);
BWrapper bw = new BWrapper(b);
print(aw);
print(bw);
}
public static void print(Wrapper t){
System.out.println(t.getValue());
}
public static class A {
public String getA(){
return "A";
}
}
public static class B extends A {
public String getB(){
return "B";
}
}
public static interface Wrapper{
public String getValue();
}
public static class AWrapper implements Wrapper{
A a;
public AWrapper (A a){
this.a = a;
}
public String getValue(){
return a.getA();
}
}
public static class BWrapper implements Wrapper{
B b;
public BWrapper (B b){
this.b = b;
}
public String getValue(){
return b.getB();
}
}

Related

Is it possible to "adopt" a class as a child?

I'm currently writing a class, that should serve as an add-on to already existing classes. For example, let my add-on class be the following:
public class NewClass {}
Also, assume there already exist classes like:
public final class ExistingClassA {}
public final class ExistingClassB {}
...
These I am not allowed to change.
For some algorithms, I'd like to define the existing classes to be children of my NewClass, though. So instead of inherit from some class with extends, I kind of want to achieve the opposite: I want to "adopt" a class, as if the existing classes were originally defined this way:
public final class ExistingClassA extends NewClass {}
public final class ExistingClassB extends NewClass {}
...
Is this even possible in Java? And if so, is it also possible to add a class as a parent of a class, which already extends another class?
Edit:
To make my situation a bit clearer, I'll try describing what I want to achieve in more detail. E.g. assume a variable myVar, which should only be instance of specific classes. If those classes belonged to a common parent class, this wouldn't be a problem:
public final class ExistingClassA extends CommonParentClass {}
public final class ExisitingClassB extends CommonParentClass {}
public final class ExistingClassC extends CommonParentClass {}
...
/* We're inside some class now... */
CommonParentClass myVar; // May be of ExistingClassA, ExistingClassB, or ExistingClassC.
Now say, I want myVar to be only of the class ExistingClassA or ExistingClassB. Assuming I could "adopt" those two classes with my NewClass, I could also just write:
NewClass myVar; // May be of ExistingClassA, or ExistingClassB, but not ExistingClassC.
Since this seems not to be possible (from reading the comments), what approach would be the smartest to achieve the goal of just allowing myVar so be of a subset of CommonParentClass?
There's no compile-time mechanism to check whether a class extends either class A or B. If the authors of A and B did not define that they are related, they are not.
You have several options:
You could use instanceof and then cast to the specified type.
Object myObj = ...;
if (myObj instanceof Alpha) {
((Alpha) myObj).doSomething();
}
else if (myObj instanceof Bravo) {
((Bravo) myObj).doSomethingElse();
}
else {
throw new IllegalArgumentException("myObj" must be of either Alpha or Bravo");
}
Or you could make a wrapper object accepting either in the constructor:
class Either<A, B> {
A a;
B b;
boolean isA;
Either(A a) {
this.a = a;
this.isA = true;
}
Either(B b) {
this.b = b;
}
boolean isA() {
return isA;
}
A getA() {
return a;
}
B getB() {
return b;
}
}
and then call it:
Either<Alpha, Bravo> either = new Either(...);
if (either.isA()) {
either.getA().doSomething();
}
else {
either.getB().doSomethingElse();
}
But I fail to see how you want to use those two classes. Do they have a method with the same name? And why don't you just simply use two variables?

Java inheritance not behaving as expected

The following context is needed: The purpose of this way of coding is to avoid if-else statements and instanceof; which is always a bad idea.
I have 3 classes with the following signatures:
abstract class A {}
class B extends A {}
class C extends A {}
Then I have another class with the following structure:
class MyClass {
private final A model;
public MyClass(A m) {
this.model = m;
}
public void doSomething() {
System.out.println(this.model instanceof C); //TRUE!!
execute(this.model);
}
private void execute(A m) {
System.out.println("noo");
}
private void execute(C m) {
System.out.println("yay");
}
}
And finally the contents of my main:
public static void main(String... args) {
C mod = new C();
MyClass myClass = new MyClass(mod);
myClass.doSomething();
}
Now the problem; the execute(C) method never gets executed, it's always the execute(A) method. How can I solve this? I cannot change the signature of the execute(A) method to execute(B) since that would give an error saying java "cannot resolve method execute(A)" at MyClass#doSomething.
Method overloads are resolved at compile time. At compile time, the type of m is A, so execute(A m) gets executed.
In addition, private methods are not overridable.
The solution is to use the Visitor pattern as suggested by #OliverCharlesworth.
Your code illustrates the difference between a static and a dynamic type of an object. Static type is what's known to the compiler; dynamic type is what's actually there at runtime.
The static type of your model field is A:
private final A model;
That is, the compiler knows that A itself or some of its implementations is going to be assigned to model. The compiler does not know anything else, so when it comes to choosing between execute(A m) and execute(C m) its only choice is execute(A m). The method is resolved on the static type of the object.
instanceof, on the other hand, understands the dynamic type. It can tell that the model is set to C, hence reporting the true in your printout.
You can solve it by adding a method to A and overriding it in B and C to route to the proper execute:
abstract class A {
public abstract void callExecute(MyClass back);
}
class B extends A {
public void callExecute(MyClass back) {
back.execute(this);
}
}
class C extends A {
public void callExecute(MyClass back) {
back.execute(this);
}
}
class MyClass {
private final A model;
public MyClass(A m) {
this.model = m;
}
public void doSomething() {
System.out.println(this.model instanceof C); //TRUE!!
model.callExecute(this.model);
}
public void execute(B m) {
System.out.println("noo");
}
public void execute(C m) {
System.out.println("yay");
}
}
Note that both implementations call
back.execute(this);
However, the implementation inside B has this of type B, and the implementation inside C has this of type C, so the calls are routed to different overloads of the execute method of MyClass.
I cannot change the signature of the execute(A) method to execute(B)
Also note that now you can (and should) do that, too, because callbacks are performed to the correct overload based on type of this.
Method overloading is a compile time polymorphism. Thus, for calling method execute(C) you need to define your model as class C.
It's better to define method execute() in class A and override it in subclasses.
abstract class A {
abstract void execute();
}
class B extends A {
public void execute(){};
}
class C extends A {
public void execute(){};
}
And then:
class MyClass {
private final A model;
public void doSomething() {
model.execute();
}
This much better way to use polymorphism to avoid if-else statements and instanceof checking
You are sending object of type C as an object of type A in constructor( you've done upcasting) and assigning it to a reference to type A(which will result in calling only execute(A) method).You could check if the object is a instance of C and depending on the outcome, call the desired method. You could do it like this
public void doSomething(){
System.out.println(model instanceof C);
if (model instanceof C) execute((C)model);
else
execute(model);
}

Can a super class method implementation depend on child class field

I am in a situation as follows.
I have an interface A which is inherited by class B,C,D (B,C,D implements A).
public interface A{
public String someMethod();
}
class B implements A{
ObjectType1 model;
#Override
public String someMethod(){
if(model instanceof X){
System.out.print(true);
}
}
}
class C implements A{
ObjectType2 model;
#Override
public String someMethod(){
if(model instanceof X){
System.out.print(true);
}
}
class D implements A{
ObjectType3 model;
#Override
public String someMethod(){
if(model instanceof X){
System.out.print(true);
}
}
As you can see all method implementations are the same. So I am duplicating code. My plan was to move the method to A and make A an abstract class. But the problem is my method depends on the model field. So what would be my options to make this code better?
bdw class A,B,C extends and implements other classes too.
EDIT
modification in code. check field
I don't see any problem related to the model field transforming the interface A into an abstract class.
There is no need to reimplement the method in the subclasses if it is the same, unless you want to change its behavior (override it).
public abstract class A {
// Make it protected so it can accessible by subclasses
protected Object model;
// Common behavior that will be inherited by subclasses
public String someMethod() {
if (model instanceof X) {
return "x";
} else {
return "not x";
}
}
}
public class B extends A {
// Subclasses may access superclasses fields if protected or public.
public void someOtherMethod() {
System.out.println(super.model.toString());
}
}
public class C extends A {
// You may wish to override a parent's method behavior
#Override
public String someMethod() {
return "subclass implements it different";
}
}
For your new code example, if you really want to do that in a procedural way you can create an abstract superclass ObjectType and then it will be accessible for the parent as well.
However I wouldn't do that. It seems to me that in doing so is the very opposite of what object orientation tries to solve.
By using a subclass to define the behavior, you wouldn't need to do it in a procedural logic. That's precisely then point of using objects, inheritance and overriding/implementing behavior as needed.
Create a parent class A with said field, and said function. Have the other classes extend A. No need to override them if they function the same.
To deduplicate, you can either make A an abstract class and move the implementation of the method and the field there, or create an abstract class, say E, that implements the interface with that method and field and then have B, C and D extend that class E.
For the more general question of depending on a subclass's field, you can create an abstract method getModel which the subclasses decide how to implement -- by returning a model field or doing something else.
If you are using java 8 you could use default method in interface A, with a getter method for model.
public interface A{
default public String someMethod() {
if(getModel() instanceof X){
System.out.print(true);
}
}
public Object model getModel();
}
Then implement getModel method in all child interfaces.
If you're going to do this you must have model to be of the same (basic) type in all derived objects. If it were of the same type there's a case for putting the model to a base class. Anyway if they are of different derived types you would need to have an accessor to get it.
interface B {
BaseModel getModel();
default public strict doSomething() {
BaseModel m = getModel();
// do something with m
}
}
class D implements B {
DerivedModel model;
public getModel() {
return model;
}
}
If I was given a chance to refactor it, I will follow below approach, leveraging Java 8 Default Methods:
interface A {
default String someMethod(X objectType) {
if (objectType instanceof X) {
System.out.println(true);
}
// return something, for now returning class
return objectType.getClass().toString();
}
}
class B implements A {
#Override
public String someMethod(X objectType) {
if (objectType instanceof X) {
System.out.println(true);
}
// return "Hello"
return "Hello";
}
}
class C implements A {}
class D implements A {}
Usage:
public class Main implements A {
public static void main(String[] args) {
B b = new B();
C c = new C();
D d = new D();
Main main = new Main();
main.call(b);
main.call(c);
main.call(d);
}
public void call(A clazz) {
ObjectType1 objectType1 = new ObjectType1();
String type = clazz.someMethod(objectType1);
System.out.println(type);
}
}
interface X {
}
class ObjectType1 implements X {
}

Method argument of different types

I want to write method that would accept parameter of types a.A or b.B.
Currently it's implemented:
import a.A;
import b.B;
...
public void doSth(A arg) {
SpecificClass.specificMethod(arg);
}
public void doSth(B arg) {
SpecificClass.specificMethod(arg);
}
I want to have one generic method "doSth" that use wildcards and accepts only a.A or b.B.
Important information a.A and b.B aren't subtypes of each other. The only common type is java.lang.Object.
Any help?
Assuming you could do that, if A and B have no common superclass, you won't be able to call any methods on the arguments but Object's methods.
So I think the only 2 reasonable solutions are:
have two methods, one for A and one for B (your current setup)
have one method that takes an Object as a parameter, check that the argument is an instanceof A or B, and if not throw an IllegalArgumentException
You may wrap both A and B extending a common interface, just like:
interface CommonWrapper {
public void doSth();
}
public class AWrapper implements CommonWrapper {
private A wrapped;
public AWrapper(A a) {
this.wrapped = a;
}
public void doSth() {
// implement the actual logic using a
}
}
public class BWrapper implements CommonWrapper {
private B wrapped;
public BWrapper(B b) {
this.wrapped = b;
}
public void doSth() {
// implement the actual logic using b
}
}
Then modify your method doSth to accept a CommonWrapper object as parameter:
public void doSth(CommonWrapper c) {
c.doSth();
}
public <T> void doSth(T arg) {
SpecificClass.specificMethod(arg);
}
will be called :
yourClass.doSth(yourarg);
But it doesn't restrict to anything that can extend object, whats the point everything does.I would suggest having both your classes implement a common interface and then program to that interface.

Enforcing interface implementation in order to use another class

SITUATION: Say there is a class A and an interface B.
REQUIREMENT: If any class, say C, wants to create objects of A and use them, then that class will also have to implement interface B.Is there any way to enforce this condition?
WHY: Now a question may arise as to why I want to do such a thing. The reason is that when a class C creates objects of A and uses them, then those objects call certain methods of C. I want to declare those methods in interface B, so that C will invariably implement those methods.
Try this snippet:
public interface B {
// methods
}
public class A {
private final B b;
public A(B b) {
this.b = b;
}
...
}
public class C implements B{
// implement B's methods
public static void main(String[] arg) {
C c = new C();
A a = new A(c);
}
}
Since you say that objects of class A will call methods on C, they will have to keep reference to C somehow. Make this reference of type B and you are done.
That is
public class A {
public A(B arg) {
....
}
}
Then in C:
A a = new A(this);
That will force class C to implement interface B.

Categories