Conditionally invoke method with same name from two different classes - java

I want an implementation where I need to invoke a method from one of two classes based on a condition. To illustrate, lets say I have two simplistic classes:
public class A implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTA");
}
}
public class B implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTB");
}
}
and an interface
public interface IObject {
void doIt();
}
My method to dynamically call a class function is implemented as:
void call(String s, A a, B b, Consumer<IObject> o) {
if(s.equalsIgnoreCase("CONDITION")) {
o.accept(a);
} else {
o.accept(b);
}
}
I can call the method as
A objectA = new A();
B objectB = new B();
call("CONDITION", objectA, objectB, IObject::doIt);
call("OTHER", objectA, objectB, IObject::doIt);
This will essentially invoke doIt on class A or B depending upon the condition parameter
Is there a cleaner way to achieve this by perhaps reducing the number of parameters an hence the function call signature?
Thanks

For my understanding of your problem:
You have a condition
You have a context to use (object a and b)
You would not ask such a question if there was not an intent to generalize your code for more than one condition or object (a, b). Otherwise, a ternary operator or a if would be far more easier to maintain (eg: ((condition) a:b).doIt() vs the code below).
Why not using a pattern like this:
A a = new A();
B b = new B();
String hint = ...;
List<Executor> list = new ArrayList<>();
list.add(new Executor("CONDITION"::equalsIgnoreCase, a::doIt));
list.add(new Executor(s -> true, b::doIt));
for (Executor executor : list) {
if (executor.process(hint)) {
break;
}
}
With Executor class:
class Executor {
private final Predicate<String> predicate;
private final Runnable runnable;
...
public boolean process(String s) {
if (!predicate.test(s)) {
return false;
}
runnable.run();
return true;
}
}
The loop will evaluate the condition, then run the code if true, otherwise continue onto the next element.
The Executor class is technically not bound to a or b; only the initial setup is.

Here is a complete different approach, utilizing java.lang.reflect.Proxy:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* #author ben
*/
public class Test {
public interface IObject {
void doIt();
}
public static class A implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTA");
}
}
public static class B implements IObject {
#Override
public void doIt() {
System.out.println("OBJECTB");
}
}
public static void main(String[] args) {
final boolean condition = true;
IObject proxyObj = (IObject)Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{IObject.class}, new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (condition)
new A().doIt();
else
new B().doIt();
return null;
}
});
proxyObj.doIt();
}
}
Here, you are creating a Proxy-Object for your Interface.
When you call .doIt() on this object, the invocation-handler will call the appropriate implementation, based on a condition.
You could then pass the proxy around and work with the invocation handler.
(It should be clear that this code should only give an idea and is only an example of how proxied interfaces/objects could be used to solve this problem.)

The above requirement can be implemented easily by using the 'Factory design pattern'
The factory design pattern involves these 3 steps:
Define the common interface for both the object types
Define the different classes that implement the common interface
Create a Factory class with a static method that returns one of the object types based on the input condition
Here is a working demo:
// File name: Demo.java
interface IObject {
public void doIT();
}
class A implements IObject {
public void doIT() {
System.out.println("DoIT - Class A");
}
}
class B implements IObject {
public void doIT() {
System.out.println("DoIT - Class B");
}
}
class IObjectFactory {
static IObject getObject(String CONDITION) {
if(CONDITION.equalsIgnoreCase("CONDITION")) {
return (new A());
}
return (new B());
}
}
public class Demo {
public static void main(String[] args) {
IObject io1 = IObjectFactory.getObject("condition");
IObject io2 = IObjectFactory.getObject("no condition");
io1.doIT();
io2.doIT();
}
}
Output:
> javac Demo.java
> java Demo
DoIT - Class A
DoIT - Class B

It really depends on your use cases. If the use cases are as simple as what you've described, you could remove the Consumer and just call doIt directly in the call function. However, I would recommend generalizing the function even further:
static <T> void ifElse(boolean decider, T optionA, T optionB, Consumer<T> callback) {
if (decider) {
callback.accept(optionA);
} else {
callback.accept(optionB);
}
}
Then call it with:
A a = new A();
B b = new B();
ifElse(condition.equals("CONDITION"), a, b, IObject::doIt);
Doing it this way is cleaner and more expandable. It also takes the same amount of code. (Untested, may have errors, but you get the idea). This approach is what you might see in purely ("purely") functional programming languages, where an if statement is just a function that takes a conditional and two functions (one for true, one for false).

Related

Implement Two EventHandlers [duplicate]

I have a generic interface
public interface Consumer<E> {
public void consume(E e);
}
I have a class that consumes two types of objects, so I would like to do something like:
public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
public void consume(Tomato t) { ..... }
public void consume(Apple a) { ...... }
}
Apparently I can't do that.
I can of course implement the dispatch myself, e.g.
public class TwoTypesConsumer implements Consumer<Object> {
public void consume(Object o) {
if (o instanceof Tomato) { ..... }
else if (o instanceof Apple) { ..... }
else { throw new IllegalArgumentException(...) }
}
}
But I am looking for the compile-time type-checking and dispatching solution that generics provide.
The best solution I can think of is to define separate interfaces, e.g.
public interface AppleConsumer {
public void consume(Apple a);
}
Functionally, this solution is OK, I think. It's just verbose and ugly.
Any ideas?
Consider encapsulation:
public class TwoTypesConsumer {
private TomatoConsumer tomatoConsumer = new TomatoConsumer();
private AppleConsumer appleConsumer = new AppleConsumer();
public void consume(Tomato t) {
tomatoConsumer.consume(t);
}
public void consume(Apple a) {
appleConsumer.consume(a);
}
public static class TomatoConsumer implements Consumer<Tomato> {
public void consume(Tomato t) { ..... }
}
public static class AppleConsumer implements Consumer<Apple> {
public void consume(Apple a) { ..... }
}
}
If creating these static inner classes bothers you, you can use anonymous classes:
public class TwoTypesConsumer {
private Consumer<Tomato> tomatoConsumer = new Consumer<Tomato>() {
public void consume(Tomato t) {
}
};
private Consumer<Apple> appleConsumer = new Consumer<Apple>() {
public void consume(Apple a) {
}
};
public void consume(Tomato t) {
tomatoConsumer.consume(t);
}
public void consume(Apple a) {
appleConsumer.consume(a);
}
}
Because of type erasure you can't implement the same interface twice (with different type parameters).
Here's a possible solution based on Steve McLeod's one:
public class TwoTypesConsumer {
public void consumeTomato(Tomato t) {...}
public void consumeApple(Apple a) {...}
public Consumer<Tomato> getTomatoConsumer() {
return new Consumer<Tomato>() {
public void consume(Tomato t) {
consumeTomato(t);
}
}
}
public Consumer<Apple> getAppleConsumer() {
return new Consumer<Apple>() {
public void consume(Apple a) {
consumeApple(t);
}
}
}
}
The implicit requirement of the question was Consumer<Tomato> and Consumer<Apple> objects that share state. The need for Consumer<Tomato>, Consumer<Apple> objects comes from other methods that expect these as parameters. I need one class the implement them both in order to share state.
Steve's idea was to use two inner classes, each implementing a different generic type.
This version adds getters for the objects that implement the Consumer interface, which can then be passed to other methods expecting them.
At least, you can make a small improvement to your implementation of dispatch by doing something like the following:
public class TwoTypesConsumer implements Consumer<Fruit> {
Fruit being an ancestor of Tomato and Apple.
just Stumbled upon this. It just happened, that I had the same Problem, but I solved it in a different way:
I just created a new Interface like this
public interface TwoTypesConsumer<A,B> extends Consumer<A>{
public void consume(B b);
}
unfortunately, this is considered as Consumer<A> and NOT as Consumer<B> against all Logic. So you have to create a small Adapter for the second consumer like this inside your class
public class ConsumeHandler implements TwoTypeConsumer<A,B>{
private final Consumer<B> consumerAdapter = new Consumer<B>(){
public void consume(B b){
ConsumeHandler.this.consume(B b);
}
};
public void consume(A a){ //...
}
public void conusme(B b){ //...
}
}
if a Consumer<A> is needed, you can simply pass this, and if Consumer<B> is needed just pass consumerAdapter
In Functional style it is quite easy do this without implementing the interface and also it does the compile time type checking.
Our functional interface to consume entity
#FunctionalInterface
public interface Consumer<E> {
void consume(E e);
}
our manager to process and consume entity appropriately
public class Manager {
public <E> void process(Consumer<E> consumer, E entity) {
consumer.consume(entity);
}
public void consume(Tomato t) {
// Consume Tomato
}
public void consume(Apple a) {
// Consume Apple
}
public void test() {
process(this::consume, new Tomato());
process(this::consume, new Apple());
}
}
You cannot do this directly in one class as the class definition below cannot be compiled due to erasure of generic types and duplicate interface declaration.
class TwoTypesConsumer implements Consumer<Apple>, Consumer<Tomato> {
// cannot compile
...
}
Any other solution for packing the same consume operations in one class requires to define your class as:
class TwoTypesConsumer { ... }
which is pointless as you need to repeat/duplicate the definition of both operations and they won't be referenced from interface. IMHO doing this is a bad small and code duplication which I'm trying to avoid.
This might be an indicator also that there is too much responsibility in one class to consume 2 different objects (if they aren't coupled).
However what I'm doing and what you can do is to add explicit factory object to create connected consumers in the following way:
interface ConsumerFactory {
Consumer<Apple> createAppleConsumer();
Consumer<Tomato> createTomatoConsumer();
}
If in reality those types are really coupled (related) then I would recommend to create an implementation in such way:
class TwoTypesConsumerFactory {
// shared objects goes here
private class TomatoConsumer implements Consumer<Tomato> {
public void consume(Tomato tomato) {
// you can access shared objects here
}
}
private class AppleConsumer implements Consumer<Apple> {
public void consume(Apple apple) {
// you can access shared objects here
}
}
// It is really important to return generic Consumer<Apple> here
// instead of AppleConsumer. The classes should be rather private.
public Consumer<Apple> createAppleConsumer() {
return new AppleConsumer();
}
// ...and the same here
public Consumer<Tomato> createTomatoConsumer() {
return new TomatoConsumer();
}
}
The advantage is that the factory class knows both implementations, there is a shared state (if needed) and you can return more coupled consumers if needed. There is no repeating consume method declaration which aren't derived from interface.
Please note that each consumer might be independent (still private) class if they aren't completely related.
The downside of that solution is a higher class complexity (even if this can be a one java file) and to access consume method you need one more call so instead of:
twoTypesConsumer.consume(apple)
twoTypesConsumer.consume(tomato)
you have:
twoTypesConsumerFactory.createAppleConsumer().consume(apple);
twoTypesConsumerFactory.createTomatoConsumer().consume(tomato);
To summarize you can define 2 generic consumers in one top-level class using 2 inner classes but in case of calling you need to get first a reference to appropriate implementing consumer as this cannot be simply one consumer object.
Another alternative to avoid the use of more classes. (example using java8+)
// Mappable.java
public interface Mappable<M> {
M mapTo(M mappableEntity);
}
// TwoMappables.java
public interface TwoMappables {
default Mappable<A> mapableA() {
return new MappableA();
}
default Mappable<B> mapableB() {
return new MappableB();
}
class MappableA implements Mappable<A> {}
class MappableB implements Mappable<B> {}
}
// Something.java
public class Something implements TwoMappables {
// ... business logic ...
mapableA().mapTo(A);
mapableB().mapTo(B);
}
Sorry for answer old questions, but I really love it! Try this option:
public class MegaConsumer implements Consumer<Object> {
Map<Class, Consumer> consumersMap = new HashMap<>();
Consumer<Object> baseConsumer = getConsumerFor(Object.class);
public static void main(String[] args) {
MegaConsumer megaConsumer = new MegaConsumer();
//You can load your customed consumers
megaConsumer.loadConsumerInMapFor(Tomato.class);
megaConsumer.consumersMap.put(Apple.class, new Consumer<Apple>() {
#Override
public void consume(Apple e) {
System.out.println("I eat an " + e.getClass().getSimpleName());
}
});
//You can consume whatever
megaConsumer.consume(new Tomato());
megaConsumer.consume(new Apple());
megaConsumer.consume("Other class");
}
#Override
public void consume(Object e) {
Consumer consumer = consumersMap.get(e.getClass());
if(consumer == null) // No custom consumer found
consumer = baseConsumer;// Consuming with the default Consumer<Object>
consumer.consume(e);
}
private static <T> Consumer<T> getConsumerFor(Class<T> someClass){
return t -> System.out.println(t.getClass().getSimpleName() + " consumed!");
}
private <T> Consumer<T> loadConsumerInMapFor(Class<T> someClass){
return consumersMap.put(someClass, getConsumerFor(someClass));
}
}
I think that is what you are looking for.
You get this output:
Tomato consumed!
I eat an Apple
String consumed!

Java multi-type method parameter?

I wonder if it is possible to require that a java method parameter is of any type from finite set of types. For example - I am using a library where two (or more) types have common methods, but their lowest common ancestor in the type hierarchy is Object. What I mean here:
public interface A {
void myMethod();
}
public interface B {
void myMethod();
}
...
public void useMyMethod(A a) {
// code duplication
}
public void useMyMethod(B b) {
// code duplication
}
I want to avoid the code duplication. What I think of is something like this:
public void useMyMethod(A|B obj){
obj.myMethod();
}
There is similar type of syntax in java already. For example:
try{
//fail
} catch (IllegalArgumentException | IllegalStateException e){
// use e safely here
}
Obviously this is not possible. How can I achieve well designed code using such type of uneditable type hierarchy ?
What about passing the function as a parameter to your useMyMethod function?
If you are using Java < 8:
public interface A {
void myMethod();
}
public interface B {
void myMethod();
}
public void useMyMethod(Callable<Void> myMethod) {
try {
myMethod.call();
} catch(Exception e) {
// handle exception of callable interface
}
}
//Use
public void test() {
interfaceA a = new ClassImplementingA();
useMyMethod(new Callable<Void>() {
public call() {
a.myMethod();
return null;
}
});
interfaceB b = new ClassImplementingB();
useMyMethod(new Callable<Void>() {
public call() {
b.myMethod();
return null;
}
});
}
For Java >= 8, you could use Lambda Expressions:
public interface IMyMethod {
void myMethod();
}
public void useMyMethod(IMyMethod theMethod) {
theMethod.myMethod();
}
//Use
public void test() {
interfaceA a = new ClassImplementingA();
useMyMethod(() -> a.myMethod());
interfaceB b = new ClassImplementingB();
useMyMethod(() -> b.myMethod());
}
Try using Adapter design pattern.
Or, if it's possible, add some base interface:
public interface Base {
void myMethod();
}
public interface A extends Base {}
public interface B extends Base {}
...
public void useMyMethod(Base b) {
b.myMethod()
}
Also, you can use something similar to this
You could write an interface MyInterface with a single method myMethod. Then, for each type you want to consider as part of the finite set, write a wrapper class, like this:
class Wrapper1 implements MyInterface {
private final Type1 type1;
Wrapper1(Type1 type1) {
this.type1 = type1;
}
#Override
public void myMethod() {
type1.method1();
}
}
Then you just need to use a MyInterface rather than one of the finite set of types, and the appropriate method from the appropriate type will always get called.
Note that to actually use these wrapper classes to call the method myMethod you would have to write
myMethod(new Wrapper1(type1));
This is going to get a bit ugly as you are going to have to remember the name of the wrapper class for each type in the set. For this reason, you may prefer to replace MyInterfacewith an abstract class with several static factories that produce the wrapper types. Like this:
abstract class MyWrapper {
static MyWrapper of(Type1 type1) {
return new Wrapper1(type1);
}
static MyWrapper of(Type2 type2) {
return new Wrapper2(type2);
}
abstract void myMethod();
}
then you can call the method using the code
myMethod(MyWrapper.of(type1));
The advantage of this approach is that the code is the same no matter which type you use. If you use this approach you have to replace implements MyInterface in the Wrapper1 declaration with extends MyWrapper.
Well, the correct way to model your requirement would be to have myMethod() declared in a supertype interface C which both A and B extend; your method then accepts type C as its parameter. The fact that you have trouble doing this in the situation you describe indicates you are not modelling the class hierarchy in a way that actually reflects how they behave.
Of course, if you can't change the interface structure then you could always do it with reflections.
public static void useMyMethod(Object classAorB) throws Exception {
classAorB.getClass().getMethod("myMethod").invoke(classAorB);
}
This might not constitute a best practice, but could you make a new class (call it C), that contains the parts from A and B that are duplicated, and the make a new method that takes C, have your methods that take A and B make a C instance and call the new method?
So that you have
class C {
// Stuff from both A and B
}
public void useMyMethod(A a) {
// Make a C
useMyMethod(c);
}
public void useMyMethod(B b) {
// Make a C
useMyMethod(c);
}
public void useMyMethod(C c) {
// previously duplicated code
}
That would also let you keep any non duplicated code in the methods for A and B (if there is any).
This looks to me much like the template pattern:
public interface A {
void myMethod();
}
public interface B {
void myMethod();
}
public class C {
private abstract class AorBCaller {
abstract void myMethod();
}
public void useMyMethod(A a) {
commonAndUseMyMethod(new AorBCaller() {
#Override
void myMethod() {
a.myMethod();
}
});
}
public void useMyMethod(B b) {
commonAndUseMyMethod(new AorBCaller() {
#Override
void myMethod() {
b.myMethod();
}
});
}
private void commonAndUseMyMethod(AorBCaller aOrB) {
// ... Loads of stuff.
aOrB.myMethod();
// ... Loads more stuff
}
}
In Java 8 it is much more succinct:
public class C {
// Expose an "A" form of the method.
public void useMyMethod(A a) {
commonAndUseMyMethod(() -> a.myMethod());
}
// And a "B" form.
public void useMyMethod(B b) {
commonAndUseMyMethod(() -> b.myMethod());
}
private void commonAndUseMyMethod(Runnable aOrB) {
// ... Loads of stuff -- no longer duplicated.
aOrB.run();
// ... Loads more stuff
}
}
A dynamic proxy can be used to create a bridge between a common interface you define and the objects implementing the other interfaces that conform to the new interface. Then, you can have your useMyMethods convert the parameter to the new interface (as a dynamic proxy) and have your common code written in terms only of the new interface.
This would be the new interface:
interface Common {
void myMethod();
}
Then, with this invocation handler:
class ForwardInvocationHandler implements InvocationHandler {
private final Object wrapped;
public ForwardInvocationHandler(Object wrapped) {
this.wrapped = wrapped;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method match = wrapped.getClass().getMethod(method.getName(), method.getParameterTypes());
return match.invoke(wrapped, args);
}
}
You can have your methods like this:
public void useMyMethod(A a) {
useMyMethod(toCommon(a));
}
public void useMyMethod(B b) {
useMyMethod(toCommon(b));
}
public void useMyMethod(Common common) {
// ...
}
private Common toCommon(Object o) {
return (Common)Proxy.newProxyInstance(
Common.class.getClassLoader(),
new Class[] { Common.class },
new ForwardInvocationHandler(o));
}
Note that to simplify matters you could even elect one of your existing interfaces (A or B) to be used as the common interface.
(Look at another example here, and also at other ideas around this subject)
The correct way is to use Java Generics.
See http://docs.oracle.com/javase/tutorial/java/generics/bounded.html

Java abstract method with abstract parameter and inheritance

I recently fumbled into a problem with an API and an implementation where the following type of code appeared:
public abstract class A {
public A sum(A a) {
System.out.println("A.sum(A) called");
return null;
}
}
The implementation is a simple class:
public class B extends A {
public B sum(B b) {
System.out.println("B.sum(B) called");
return null;
}
}
When it comes to using it I write:
public class Main {
public static void main(String[] args) {
B b = new B();
A basa = new B();
b.sum(b);
basa.sum(b);
basa.sum(basa);
}
}
Which results in:
B.sum(B) called
A.sum(A) called
A.sum(A) called
I understand that B's sum does not override A's sum as its signature is different, but I'd like to provide an efficient implementation of sum for objects of effective type B. I think such design is quite classical and I would like to know how I should design my API and implementation so that it is efficient.
Of course I could provide sum(A a) in class B and check if b is an instanceof B before calling either sum(B b) or super, but I thought that instanceof was to be avoided for efficiency reasons. (if it is inefficient, it may be even less efficient with my abstract implementation)
instanceof can usually be avoided by using the visitor pattern. Depending on your needs, it may or may not be an overkill. It's flexible but quite verbose. In the example below I removed abstract from A to illustrate how it works with different types.
The trick is that when an object is asked to visit a visitor, the object itself chooses the correct accept method in the visitor. The "instanceof"-check is resolved through polymorphism. (I doubt that it's more efficient than an instanceof though.)
interface Visitor {
public A accept(A a);
public B accept(B b);
}
class A {
public A sum(A a) {
System.out.println("A.sum(A) called");
return null;
}
public A visit(Visitor sv) {
return sv.accept(this);
}
}
class B extends A {
public B sum(B b) {
System.out.println("B.sum(B) called");
return null;
}
public B visit(Visitor sv) {
return sv.accept(this);
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
B b = new B();
A basa = new B();
a.visit(new SumVisitor(b)); // a.sum(b);
b.visit(new SumVisitor(b)); // b.sum(b);
basa.visit(new SumVisitor(b)); // basa.sum(b);
basa.visit(new SumVisitor(basa)); // basa.sum(basa);
}
static class SumVisitor implements Visitor {
A arg;
SumVisitor(A arg) { this.arg = arg; }
public A accept(A a) { return a.sum(arg); }
public B accept(B b) { return b.sum(arg); }
}
}
Output:
A.sum(A) called
B.sum(B) called
B.sum(B) called
B.sum(B) called
Disclamer; It was a while ago I wrote a visitor, so please correct me if I have any bugs in this (almost untested) code snippet. Or better, edit the post yourself and improve it :)
Since B instances can be summed with A instances using myA.sum(myB), you should be able to change B's definition of sum so that it does override, unless of course sum is a placeholder and isn't something that should be commutative.
UPDATE:
If this is insufficient, you could start getting fancy with generics. Here's a rough pass at what I mean:
public abstract class A {
public <T extends A> T sum(T a) {
System.out.println("A.sum(A) called");
return null;
}
public static void main(String args[]) {
B b = new B();
b.sum(b);
A basa = new B();
basa.sum(b);
basa.sum(basa);
}
public static class B extends A {
#Override
public <T extends A> T sum(T b) {
System.out.println("B.sum(B) called");
return null;
}
}
}
#aioobe is right that the generally accepted work-around is to use the Visitor pattern. I'm offering these as less complete but less verbose alternatives.
So, what makes you think instanceof is slow? It's used in several places in the JDK where they want to provide a "fast path" for certain well-known implementations of an abstract class or interface. The usual advice applies here: "Test, don't guess."

Java: Superclass to construct a subclass on certain conditions, possible?

I have this condition
public class A {
public action() {
System.out.println("Action done in A");
}
}
public class B extends A {
public action() {
System.out.println("Action done in B");
}
}
when I create an instance of B, the action will do just actions in B, as it overrides the action of the superclass.
the problem is that in my project, the super class A is already used too many times, and I am looking for a way that under certain conditions, when i create an instance of A it makes a check and if it is true, replace itself with B.
public class A {
public A() {
if ([condition]) {
this = new B();
}
}
public action() {
System.out.println("Action done in A");
}
}
A a = new A();
a.action();
// expect to see "Action done in B"...
is this possible in some way?
I would say that doing this:
this = new B();
within the constructor for A would violate OO design principles, even it were possible to do (and it isn't).
That being said, if I were faced with this scenario:
the problem is that in my project, the super class A is already used too many times
I would solve it in one of the two following ways:
I have assumed that your condition is that you do not want too many objects of type A, otherwise feel free to substitute in any other condition.
Option 1 : Use a factory design pattern.
public class AFactory
{
private static count = 0;
private static final MAX_COUNT = 100;
public A newObject() {
if (count < MAX_COUNT) {
count++;
return new A();
} else {
return new B();
}
}
}
And then somehwere else you generate the objects like so:
A obj1 = factory.newObject();
A obj2 = factory.newObject();
Option 2 : Static counter + try&catch
Use a static counter within your A class that keeps track of the number of times A has been instantiated, by incrementing the static variable by one in the constructor. If it hits a limit for the max number of object of type A, throw an InstantiationError in A's constructor.
This would mean that whenever you instantiate A, you have to a try..catch block to intercept the InstantionError, and then create a new object of type B instead.
public class A {
private static count = 0;
private static final MAX_COUNT = 100;
public A() {
if (count > 100) {
throw new InstationError();
}
}
}
And when generating your objects:
A obj1, obj2;
try {
obj1 = new A();
} catch (InstantiationError ie) {
obj1 = new B();
}
try {
obj2 = new A();
} catch (InstantiationError ie) {
obj2 = new B();
}
Option 2 is closest to what you ask directly in the question. However, I would personally choose to use the factory design pattern, because it is much more elegant solution, and it allows you to achieve what you want to do anyway.
Not directly, no. Calling new A() will always create an instance of A. However, you could make the constructor of A protected, and then have a static method:
public static A newInstance() {
// Either create A or B here.
}
Then convert all current calls to the constructor to calls to the factory method.
It is possible to choose whether or not to use a superclass' constructor?
It is not possible to conditionally control whether or not to use a superclass' constructor, as one of the superclass' constructors must be called before constructing one's own object.
From the above, there is a requirement in Java, that the first line of the constructor must call on of the superclass' constructor -- in fact, even if there is no explicit call to a superclass' constructor, there will be an implicit call to super():
public class X {
public X() {
// ...
}
public X(int i) {
// ...
}
}
public class Y extends X {
public Y() {
// Even if not written, there is actually a call to super() here.
// ...
}
}
It should be stressed that it is not possible to call the superclass' constructor after performing something else:
public class Y extends X {
public Y() {
doSomething(); // Not allowed! A compiler error will occur.
super(); // This *must* be the first line in this constructor.
}
}
The alternative
That said, a way to achieve what is desired here could be to use the factory method pattern, which can select the kind of implementation depending on some kind of condition:
public A getInstance() {
if (condition) {
return new B();
} else {
return new C();
}
}
In the above code, depending on condition, the method can return either an instance of B or C (assuming both are a subclass of class A).
Example
The following is a concrete example, using an interface rather than a class.
Let there be the following interfaces and classes:
interface ActionPerformable {
public void action();
}
class ActionPerformerA implements ActionPerformable {
public void action() {
// do something...
}
}
class ActionPerformerB implements ActionPerformable {
public void action() {
// do something else...
}
}
Then, there would be a class which will return one of the above classes depending on a condition which is passed in through a method:
class ActionPeformerFactory {
// Returns a class which implements the ActionPerformable interface.
public ActionPeformable getInstance(boolean condition) {
if (condition) {
return new ActionPerformerA();
} else {
return new ActionPerformerB();
}
}
}
Then, a class which uses the above factory method which returns the appropriate implementation depending on a condition:
class Main {
public static void main(String[] args) {
// Factory implementation will return ActionPerformerA
ActionPerformable ap = ActionPerformerFactory.getInstance(true);
// Invokes the action() method of ActionPerformable obtained from Factory.
ap.action();
}
}
This would be possible if you used a factory method. When you use a constructor: nope, completely impossible.
Assuming you aren't willing to move it to an interface or factory its kind of ugly but you could keep a delegeate copy of B in A and rewrite your methods ot invoke the delegate:
public class A{
B delegate;
public A(){
if([condition]){
delegate = new B()
return;
}
...//normal init
}
public void foo(){
if(delegate != null){
delegate.foo();
return;
}
...//normal A.foo()
}
public boolean bar(Object wuzzle){
if(delegate != null){
return delegate.bar(wuzzle);
}
...//normal A.bar()
}
...//other methods in A
}

Why is super.super.method(); not allowed in Java?

I read this question and thought that would easily be solved (not that it isn't solvable without) if one could write:
#Override
public String toString() {
return super.super.toString();
}
I'm not sure if it is useful in many cases, but I wonder why it isn't and if something like this exists in other languages.
What do you guys think?
EDIT:
To clarify: yes I know, that's impossible in Java and I don't really miss it. This is nothing I expected to work and was surprised getting a compiler error. I just had the idea and like to discuss it.
It violates encapsulation. You shouldn't be able to bypass the parent class's behaviour. It makes sense to sometimes be able to bypass your own class's behaviour (particularly from within the same method) but not your parent's. For example, suppose we have a base "collection of items", a subclass representing "a collection of red items" and a subclass of that representing "a collection of big red items". It makes sense to have:
public class Items
{
public void add(Item item) { ... }
}
public class RedItems extends Items
{
#Override
public void add(Item item)
{
if (!item.isRed())
{
throw new NotRedItemException();
}
super.add(item);
}
}
public class BigRedItems extends RedItems
{
#Override
public void add(Item item)
{
if (!item.isBig())
{
throw new NotBigItemException();
}
super.add(item);
}
}
That's fine - RedItems can always be confident that the items it contains are all red. Now suppose we were able to call super.super.add():
public class NaughtyItems extends RedItems
{
#Override
public void add(Item item)
{
// I don't care if it's red or not. Take that, RedItems!
super.super.add(item);
}
}
Now we could add whatever we like, and the invariant in RedItems is broken.
Does that make sense?
I think Jon Skeet has the correct answer. I'd just like to add that you can access shadowed variables from superclasses of superclasses by casting this:
interface I { int x = 0; }
class T1 implements I { int x = 1; }
class T2 extends T1 { int x = 2; }
class T3 extends T2 {
int x = 3;
void test() {
System.out.println("x=\t\t" + x);
System.out.println("super.x=\t\t" + super.x);
System.out.println("((T2)this).x=\t" + ((T2)this).x);
System.out.println("((T1)this).x=\t" + ((T1)this).x);
System.out.println("((I)this).x=\t" + ((I)this).x);
}
}
class Test {
public static void main(String[] args) {
new T3().test();
}
}
which produces the output:
x= 3
super.x= 2
((T2)this).x= 2
((T1)this).x= 1
((I)this).x= 0
(example from the JLS)
However, this doesn't work for method calls because method calls are determined based on the runtime type of the object.
I think the following code allow to use super.super...super.method() in most case.
(even if it's uggly to do that)
In short
create temporary instance of ancestor type
copy values of fields from original object to temporary one
invoke target method on temporary object
copy modified values back to original object
Usage :
public class A {
public void doThat() { ... }
}
public class B extends A {
public void doThat() { /* don't call super.doThat() */ }
}
public class C extends B {
public void doThat() {
Magic.exec(A.class, this, "doThat");
}
}
public class Magic {
public static <Type, ChieldType extends Type> void exec(Class<Type> oneSuperType, ChieldType instance,
String methodOfParentToExec) {
try {
Type type = oneSuperType.newInstance();
shareVars(oneSuperType, instance, type);
oneSuperType.getMethod(methodOfParentToExec).invoke(type);
shareVars(oneSuperType, type, instance);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static <Type, SourceType extends Type, TargetType extends Type> void shareVars(Class<Type> clazz,
SourceType source, TargetType target) throws IllegalArgumentException, IllegalAccessException {
Class<?> loop = clazz;
do {
for (Field f : loop.getDeclaredFields()) {
if (!f.isAccessible()) {
f.setAccessible(true);
}
f.set(target, f.get(source));
}
loop = loop.getSuperclass();
} while (loop != Object.class);
}
}
I don't have enough reputation to comment so I will add this to the other answers.
Jon Skeet answers excellently, with a beautiful example. Matt B has a point: not all superclasses have supers. Your code would break if you called a super of a super that had no super.
Object oriented programming (which Java is) is all about objects, not functions. If you want task oriented programming, choose C++ or something else. If your object doesn't fit in it's super class, then you need to add it to the "grandparent class", create a new class, or find another super it does fit into.
Personally, I have found this limitation to be one of Java's greatest strengths. Code is somewhat rigid compared to other languages I've used, but I always know what to expect. This helps with the "simple and familiar" goal of Java. In my mind, calling super.super is not simple or familiar. Perhaps the developers felt the same?
There's some good reasons to do this. You might have a subclass which has a method which is implemented incorrectly, but the parent method is implemented correctly. Because it belongs to a third party library, you might be unable/unwilling to change the source. In this case, you want to create a subclass but override one method to call the super.super method.
As shown by some other posters, it is possible to do this through reflection, but it should be possible to do something like
(SuperSuperClass this).theMethod();
I'm dealing with this problem right now - the quick fix is to copy and paste the superclass method into the subsubclass method :)
In addition to the very good points that others have made, I think there's another reason: what if the superclass does not have a superclass?
Since every class naturally extends (at least) Object, super.whatever() will always refer to a method in the superclass. But what if your class only extends Object - what would super.super refer to then? How should that behavior be handled - a compiler error, a NullPointer, etc?
I think the primary reason why this is not allowed is that it violates encapsulation, but this might be a small reason too.
I think if you overwrite a method and want to all the super-class version of it (like, say for equals), then you virtually always want to call the direct superclass version first, which one will call its superclass version in turn if it wants.
I think it only makes rarely sense (if at all. i can't think of a case where it does) to call some arbitrary superclass' version of a method. I don't know if that is possible at all in Java. It can be done in C++:
this->ReallyTheBase::foo();
At a guess, because it's not used that often. The only reason I could see using it is if your direct parent has overridden some functionality and you're trying to restore it back to the original.
Which seems to me to be against OO principles, since the class's direct parent should be more closely related to your class than the grandparent is.
Calling of super.super.method() make sense when you can't change code of base class. This often happens when you are extending an existing library.
Ask yourself first, why are you extending that class? If answer is "because I can't change it" then you can create exact package and class in your application, and rewrite naughty method or create delegate:
package com.company.application;
public class OneYouWantExtend extends OneThatContainsDesiredMethod {
// one way is to rewrite method() to call super.method() only or
// to doStuff() and then call super.method()
public void method() {
if (isDoStuff()) {
// do stuff
}
super.method();
}
protected abstract boolean isDoStuff();
// second way is to define methodDelegate() that will call hidden super.method()
public void methodDelegate() {
super.method();
}
...
}
public class OneThatContainsDesiredMethod {
public void method() {...}
...
}
For instance, you can create org.springframework.test.context.junit4.SpringJUnit4ClassRunner class in your application so this class should be loaded before the real one from jar. Then rewrite methods or constructors.
Attention: This is absolute hack, and it is highly NOT recommended to use but it's WORKING! Using of this approach is dangerous because of possible issues with class loaders. Also this may cause issues each time you will update library that contains overwritten class.
#Jon Skeet Nice explanation.
IMO if some one wants to call super.super method then one must be want to ignore the behavior of immediate parent, but want to access the grand parent behavior.
This can be achieved through instance Of. As below code
public class A {
protected void printClass() {
System.out.println("In A Class");
}
}
public class B extends A {
#Override
protected void printClass() {
if (!(this instanceof C)) {
System.out.println("In B Class");
}
super.printClass();
}
}
public class C extends B {
#Override
protected void printClass() {
System.out.println("In C Class");
super.printClass();
}
}
Here is driver class,
public class Driver {
public static void main(String[] args) {
C c = new C();
c.printClass();
}
}
Output of this will be
In C Class
In A Class
Class B printClass behavior will be ignored in this case.
I am not sure about is this a ideal or good practice to achieve super.super, but still it is working.
Look at this Github project, especially the objectHandle variable. This project shows how to actually and accurately call the grandparent method on a grandchild.
Just in case the link gets broken, here is the code:
import lombok.val;
import org.junit.Assert;
import org.junit.Test;
import java.lang.invoke.*;
/*
Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.
Please don't actually do this... :P
*/
public class ImplLookupTest {
private MethodHandles.Lookup getImplLookup() throws NoSuchFieldException, IllegalAccessException {
val field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
field.setAccessible(true);
return (MethodHandles.Lookup) field.get(null);
}
#Test
public void test() throws Throwable {
val lookup = getImplLookup();
val baseHandle = lookup.findSpecial(Base.class, "toString",
MethodType.methodType(String.class),
Sub.class);
val objectHandle = lookup.findSpecial(Object.class, "toString",
MethodType.methodType(String.class),
// Must use Base.class here for this reference to call Object's toString
Base.class);
val sub = new Sub();
Assert.assertEquals("Sub", sub.toString());
Assert.assertEquals("Base", baseHandle.invoke(sub));
Assert.assertEquals(toString(sub), objectHandle.invoke(sub));
}
private static String toString(Object o) {
return o.getClass().getName() + "#" + Integer.toHexString(o.hashCode());
}
public class Sub extends Base {
#Override
public String toString() {
return "Sub";
}
}
public class Base {
#Override
public String toString() {
return "Base";
}
}
}
Happy Coding!!!!
I would put the super.super method body in another method, if possible
class SuperSuperClass {
public String toString() {
return DescribeMe();
}
protected String DescribeMe() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return "I am super";
}
}
class ChildClass extends SuperClass {
public String toString() {
return DescribeMe();
}
}
Or if you cannot change the super-super class, you can try this:
class SuperSuperClass {
public String toString() {
return "I am super super";
}
}
class SuperClass extends SuperSuperClass {
public String toString() {
return DescribeMe(super.toString());
}
protected String DescribeMe(string fromSuper) {
return "I am super";
}
}
class ChildClass extends SuperClass {
protected String DescribeMe(string fromSuper) {
return fromSuper;
}
}
In both cases, the
new ChildClass().toString();
results to "I am super super"
It would seem to be possible to at least get the class of the superclass's superclass, though not necessarily the instance of it, using reflection; if this might be useful, please consider the Javadoc at http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getSuperclass()
public class A {
#Override
public String toString() {
return "A";
}
}
public class B extends A {
#Override
public String toString() {
return "B";
}
}
public class C extends B {
#Override
public String toString() {
return "C";
}
}
public class D extends C {
#Override
public String toString() {
String result = "";
try {
result = this.getClass().getSuperclass().getSuperclass().getSuperclass().newInstance().toString();
} catch (InstantiationException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(D.class.getName()).log(Level.SEVERE, null, ex);
}
return result;
}
}
public class Main {
public static void main(String... args) {
D d = new D();
System.out.println(d);
}
}
run:
A
BUILD SUCCESSFUL (total time: 0 seconds)
I have had situations like these when the architecture is to build common functionality in a common CustomBaseClass which implements on behalf of several derived classes.
However, we need to circumvent common logic for specific method for a specific derived class. In such cases, we must use a super.super.methodX implementation.
We achieve this by introducing a boolean member in the CustomBaseClass, which can be used to selectively defer custom implementation and yield to default framework implementation where desirable.
...
FrameworkBaseClass (....) extends...
{
methodA(...){...}
methodB(...){...}
...
methodX(...)
...
methodN(...){...}
}
/* CustomBaseClass overrides default framework functionality for benefit of several derived classes.*/
CustomBaseClass(...) extends FrameworkBaseClass
{
private boolean skipMethodX=false;
/* implement accessors isSkipMethodX() and setSkipMethodX(boolean)*/
methodA(...){...}
methodB(...){...}
...
methodN(...){...}
methodX(...){
if (isSkipMethodX()) {
setSKipMethodX(false);
super.methodX(...);
return;
}
... //common method logic
}
}
DerivedClass1(...) extends CustomBaseClass
DerivedClass2(...) extends CustomBaseClass
...
DerivedClassN(...) extends CustomBaseClass...
DerivedClassX(...) extends CustomBaseClass...
{
methodX(...){
super.setSKipMethodX(true);
super.methodX(...);
}
}
However, with good architecture principles followed in framework as well as app, we could avoid such situations easily, by using hasA approach, instead of isA approach. But at all times it is not very practical to expect well designed architecture in place, and hence the need to get away from solid design principles and introduce hacks like this.
Just my 2 cents...
IMO, it's a clean way to achieve super.super.sayYourName() behavior in Java.
public class GrandMa {
public void sayYourName(){
System.out.println("Grandma Fedora");
}
}
public class Mama extends GrandMa {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName();
}else {
System.out.println("Mama Stephanida");
}
}
}
public class Daughter extends Mama {
public void sayYourName(boolean lie){
if(lie){
super.sayYourName(lie);
}else {
System.out.println("Little girl Masha");
}
}
}
public class TestDaughter {
public static void main(String[] args){
Daughter d = new Daughter();
System.out.print("Request to lie: d.sayYourName(true) returns ");
d.sayYourName(true);
System.out.print("Request not to lie: d.sayYourName(false) returns ");
d.sayYourName(false);
}
}
Output:
Request to lie: d.sayYourName(true) returns Grandma Fedora
Request not to lie: d.sayYourName(false) returns Little girl Masha
I think this is a problem that breaks the inheritance agreement.
By extending a class you obey / agree its behavior, features
Whilst when calling super.super.method(), you want to break your own obedience agreement.
You just cannot cherry pick from the super class.
However, there may happen situations when you feel the need to call super.super.method() - usually a bad design sign, in your code or in the code you inherit !
If the super and super super classes cannot be refactored (some legacy code), then opt for composition over inheritance.
Encapsulation breaking is when you #Override some methods by breaking the encapsulated code.
The methods designed not to be overridden are marked
final.
In C# you can call a method of any ancestor like this:
public class A
internal virtual void foo()
...
public class B : A
public new void foo()
...
public class C : B
public new void foo() {
(this as A).foo();
}
Also you can do this in Delphi:
type
A=class
procedure foo;
...
B=class(A)
procedure foo; override;
...
C=class(B)
procedure foo; override;
...
A(objC).foo();
But in Java you can do such focus only by some gear. One possible way is:
class A {
int y=10;
void foo(Class X) throws Exception {
if(X!=A.class)
throw new Exception("Incorrect parameter of "+this.getClass().getName()+".foo("+X.getName()+")");
y++;
System.out.printf("A.foo(%s): y=%d\n",X.getName(),y);
}
void foo() throws Exception {
System.out.printf("A.foo()\n");
this.foo(this.getClass());
}
}
class B extends A {
int y=20;
#Override
void foo(Class X) throws Exception {
if(X==B.class) {
y++;
System.out.printf("B.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("B.foo(%s) calls B.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
}
class C extends B {
int y=30;
#Override
void foo(Class X) throws Exception {
if(X==C.class) {
y++;
System.out.printf("C.foo(%s): y=%d\n",X.getName(),y);
} else {
System.out.printf("C.foo(%s) calls C.super.foo(%s)\n",X.getName(),X.getName());
super.foo(X);
}
}
void DoIt() {
try {
System.out.printf("DoIt: foo():\n");
foo();
Show();
System.out.printf("DoIt: foo(B):\n");
foo(B.class);
Show();
System.out.printf("DoIt: foo(A):\n");
foo(A.class);
Show();
} catch(Exception e) {
//...
}
}
void Show() {
System.out.printf("Show: A.y=%d, B.y=%d, C.y=%d\n\n", ((A)this).y, ((B)this).y, ((C)this).y);
}
}
objC.DoIt() result output:
DoIt: foo():
A.foo()
C.foo(C): y=31
Show: A.y=10, B.y=20, C.y=31
DoIt: foo(B):
C.foo(B) calls C.super.foo(B)
B.foo(B): y=21
Show: A.y=10, B.y=21, C.y=31
DoIt: foo(A):
C.foo(A) calls C.super.foo(A)
B.foo(A) calls B.super.foo(A)
A.foo(A): y=11
Show: A.y=11, B.y=21, C.y=31
It is simply easy to do. For instance:
C subclass of B and B subclass of A. Both of three have method methodName() for example.
public abstract class A {
public void methodName() {
System.out.println("Class A");
}
}
public class B extends A {
public void methodName() {
super.methodName();
System.out.println("Class B");
}
// Will call the super methodName
public void hackSuper() {
super.methodName();
}
}
public class C extends B {
public static void main(String[] args) {
A a = new C();
a.methodName();
}
#Override
public void methodName() {
/*super.methodName();*/
hackSuper();
System.out.println("Class C");
}
}
Run class C Output will be:
Class A
Class C
Instead of output:
Class A
Class B
Class C
If you think you are going to be needing the superclass, you could reference it in a variable for that class. For example:
public class Foo
{
public int getNumber()
{
return 0;
}
}
public class SuperFoo extends Foo
{
public static Foo superClass = new Foo();
public int getNumber()
{
return 1;
}
}
public class UltraFoo extends Foo
{
public static void main(String[] args)
{
System.out.println(new UltraFoo.getNumber());
System.out.println(new SuperFoo().getNumber());
System.out.println(new SuperFoo().superClass.getNumber());
}
public int getNumber()
{
return 2;
}
}
Should print out:
2
1
0
public class SubSubClass extends SubClass {
#Override
public void print() {
super.superPrint();
}
public static void main(String[] args) {
new SubSubClass().print();
}
}
class SuperClass {
public void print() {
System.out.println("Printed in the GrandDad");
}
}
class SubClass extends SuperClass {
public void superPrint() {
super.print();
}
}
Output: Printed in the GrandDad
The keyword super is just a way to invoke the method in the superclass.
In the Java tutorial:https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super.
Don't believe that it's a reference of the super object!!! No, it's just a keyword to invoke methods in the superclass.
Here is an example:
class Animal {
public void doSth() {
System.out.println(this); // It's a Cat! Not an animal!
System.out.println("Animal do sth.");
}
}
class Cat extends Animal {
public void doSth() {
System.out.println(this);
System.out.println("Cat do sth.");
super.doSth();
}
}
When you call cat.doSth(), the method doSth() in class Animal will print this and it is a cat.

Categories

Resources