How to implement a method with an unknown number of arguments? - java

I have 1 interface and 3 class. I would like the class to be able to both implement the interface which need a transform method. This method must exist but there can't be more than one per class. I don't know the number of parameters taken by this class.
Example :
public interface A{
public void transform(Object ... args);
}
public class B implements A{
public void transform(String a){
System.out.println(a);
}
}
public class C implements A{
public void transform(Integer a, Character b){
System.out.println(a+b);
}
}
// super generic case if possible with Objects + primitive
public class D implements A{
public void transform(int a, String b){
System.out.println(a+b);
}
}
This doesn't work. But I hope you got the idea. Is something like this possible in java ? How should I call them in a generic way ? Let's say if I have an other method like :
void callTransf(A a, Object ... objs){
Method m = a.getClass().getMethods()[0];
m.invoke(a, objs)
}

A practicable solution would be to declare the interface as a generic one:
public interface Transformation<S, R> {
R transform(S source);
}
The type parameter S plays the source role; the type parameter R plays the result role.
You now can create source and result classes for each different transformation. An example:
public final class TransformationSourceForA {
// Here you declare whatever fields and methods you need for an A source.
// For example:
int a;
String b;
}
public final class TransformationResultForA {
// Here you declare whatever fields and methods you need for an A result.
}
With that you declare the transformation as following:
public final class TransformationA implements Transformation<TransformationSourceForA, TransformationResultForA> {
#Override
public TransformationResultForA transform(TransformationSourceForA source) { ... }
}
The principle is to delegate the needs for different fields to a class and not to the method's parameter.

You can achieve what you want, with some changes and some help of functional programming...
TL;DR
The main idea is that the transform method doesn't receive any arguments. Instead, it will return an instance of some functional interface.
The implementation of this functional interface will consist of the code that would have been executed by the transform method if it had arguments.
To represent arguments of different types and/or a different number of arguments for each subclass of the A interface, we'll use covariance in the return type of the method transform.
This means that the functional interface will be generic (so that the type of the arguments can be different for each subclass of A), and that there will be subinterfaces that will extend this functional interface, each one accepting a different number of arguments in its single abstract method. This will allow the transform() method's return value to have either 1, 2, 3, ... etc arguments.
To execute the code returned by the transform() method, we'll do:
instanceOfB.transform().execute("hello");
instanceOfC.transform().execute(1, 'a');
instanceOfD.transform().execute(1, "hello");
Finally, in order to be able to execute the code in a generic way, the base functional interface defines a varargs method executeVariadic(Object... args), which will be implemented as a default method by every child functional interface, delegating to its execute method and casting the arguments as needed.
Now the long version...
Let's start by renaming your A interface to something more descriptive. As it defines a method called transform, let's name it Transformer.
Then, let's create a functional interface that will represent the transform method of the Transformer interface. Here it is:
#FunctionalInterface
public interface Transformation {
void executeVariadic(Object... args);
}
This interface just defines one single abstract method (SAM) that receives an Object... varargs argument. It is there so that subinterfaces can override it.
Now, let's create a Transformation1 functional interface that extends the Transformation interface:
#FunctionalInterface
public interface Transformation1<A> extends Transformation {
void execute(A a);
#Override
#SuppressWarnings("unchecked")
default void executeVariadic(Object... args) {
this.execute((A) args[0]);
}
}
This Transformation1<A> functional interface is generic and defines the single abstract method execute, which takes one argument of type A. The executeVariadic method is overriden as a default method that delegates its execution to the execute method, casting the first argument accordingly. This cast generates a warning, but oh, well... we'd better learn to live with it.
Now, let's create an analogous interface with two generic type parameters and an execute method that receives two arguments whose types match the generic type parameters:
#FunctionalInterface
public interface Transformation2<A, B> extends Transformation {
void execute(A a, B b);
#Override
#SuppressWarnings("unchecked")
default void executeVariadic(Object... args) {
this.execute((A) args[0], (B) args[1]);
}
}
The idea is the same: the Transformation2 interface extends the Transformation interface and we override the executeVariadic method so that it is delegated to the execute method, casting the arguments accordingly (and suppressing the annoying warning).
For completeness, let's introduce the Transformation3 interface, which is analogous to the previous TransformationX ones:
#FunctionalInterface
public interface Transformation3<A, B, C> extends Transformation {
void execute(A a, B b, C c);
#Override
#SuppressWarnings("unchecked")
default void executeVariadic(Object... args) {
this.execute((A) args[0], (B) args[1], (C) args[2]);
}
}
Hope the pattern is clear by now. You should create as many TransformationX interfaces as arguments you want to support for the transform method of your Transformer interface (A interface in your question, remember I've renamed it).
So far so good, I know this answer is long, but I needed to define the interfaces above so that they can now be used to put all the pieces together.
Remember your A interface? Let's not only keep its name changed to Transformer, but also the signature of its transform method:
#FunctionalInterface
public interface Transformer {
Transformation transform();
}
So this is your base interface now. The transform method no longer has arguments, but returns a Transformation instead.
Let's see how to implement your B, C and D classes now. But first, allow me to rename them to TransformerB, TransformerC and TransformerD, respectively.
Here's TransformerB:
public class TransformerB implements Transformer {
#Override
public Transformation1<String> transform() {
return a -> System.out.println(a); // or System.out::println
}
}
The important thing here is the use of covariance in the return type of the transform method. And I'm using the Transformation1<String> type, which is a subtype of Transformation and indicates that, for the TransformerB class, the transform method returns a transformation that accepts one argument of type String. As the Transformation1 interface is a SAM type, I'm using a lambda expression to implement it.
Here's how to invoke the code inside the TransformerB.transform method:
TransformerB b = new TransformerB();
b.transform().execute("hello");
b.transform() returns an instance of Transformation1, whose execute method is immediately invoked with the String argument it expects.
Now let's see the implementation of TransformerC:
public class TransformerC implements Transformer {
#Override
public Transformation2<Integer, Character> transform() {
return (a, b) -> System.out.println(a + b);
}
}
Again, covariance in the return type of the transform method allows us to return a concrete Transformation, in this case Transformation2<Integer, Character>.
Usage:
TransformerC c = new TransformerC();
c.transform().execute(1, 'A');
For the TransformerD example, I've used a three-argument transformation:
public class TransformerD implements Transformer {
public Transformation3<Integer, Double, String> transform() {
return (a, b, c) -> System.out.println(a + b + c);
}
}
Usage:
TransformerD d = new TransformerD();
d.transform().execute(12, 2.22, "goodbye");
This is all type-safe, because the generic types can be specified in the TransformationX return type of each concrete transform method implementation. It's not possible to use primitive types, though, because primitive types cannot be used as generic type parameters.
Regarding how to call the transform method in a generic way, it's straightforward:
void callTransf(Transformer a, Object... args) {
a.transform().executeVariadic(args);
}
This is why the executeVariadic method exists. And it's overriden in each TransformationX interface, so that it can be used polymorphically, as in the code above.
Calling the callTransf method is straightforward too:
callTransf(b, "hello");
callTransf(c, 1, 'A');
callTransf(d, 12, 2.22, "goodbye");

What you are asking isn't possible.
If interface method uses Varargs then others must too. So one solution would be to have both classes use this interface. Here is general idea:
public interface A{
public void transform(char ... args);
}
public class B implements A{
public void transform(char ... args){
String s = "";
for(char c : args){
s += c;
}
System.out.println(s);
}
}
public class C implements A{
public void transform(char ... args){
System.out.println(args[0] + args[1]);
}
}
Now when you are calling method in B then you must convert string to char array:
String str = "example";
char[] charArray = str.toCharArray();
When calling method in A you make sure to convert integer to char:
int i = 5;
transform((char)Character.forDigit(i, 10), 'a'); // 10 stands for number radix which is probably 10
This isn't perfect solution but it is working one.
But a bit simpler solution without varargs is using just char array, but again you need to convert inputs to char array.
public interface A{
public void transform(char[]);
}
public class B implements A{
public void transform(char[] args){
String s = "";
for(char c : args){
s += c;
}
System.out.println(s);
}
}
public class C implements A{
public void transform(char[] args){
System.out.println(args[0] + args[1]);
}
}
Anyway you do it, you will end up with a bit complicated code, even if using generics you must remember that 1 method takes 1 parameter and other one 2. I actually think that it would be best to simply make this methods separate.

It's a very old question but I don't see a correct implementation in any of the solution. OP was going the right way and is the correct implementation but needs to be written like this -
public interface A<T>{
public T transform(Object ... args);
}
public class B implements A{
public void transform(Object ... args){
System.out.println((String)args[0]);
}
}
public class C implements A{
public void transform(Object ... args){
Integer a = (Integer)args[0];
Integer b = (Integer)args[1];
System.out.println(a+b);
}
}
public static void main(String [] vals){
//Interface A
A b = new B();
A c = new C();
b.transform("Hello");
c.transform(new Integer(1), 'c');
}
You will see it's importance if you use Spring or other DI framework then all you need to do is
#Inject
#Qualifier("B") // For Implementation class B
A b;
#Inject
#Qualifier("C") // For Implementation class C
A C
I see accepted answer is very convuluted and in the end, it is just directly calling the implementation class -
Ex:TransformerB b = new TransformerB;
b.transform();
What's the point of creating all the interfaces???

this is a very interesting Question.you can use method overloading concept if you know the maximum number of arguments coming.
lets say you know that at max user can give 2 parameters then you can do something like this.
public void implementation(){
System.out.println("method with zero args")
}
public void implementation(String arg1){
System.out.println("method with one args and is:-"+arg1)
}
public void implementation(String arg1,String arg2){
System.out.println("method with two args and are :-"+arg1+" "+arg2)
}
if you dont know the maximum number of args you can implement in multiple ways.
1.create a collection and store them in collection object and pass the object as argument.
List args= new List();
l.add(arg1)
----------
----------
----------
l.add(argn)
now pass this as argument to the function call as
objecReference.implementation(l)
2.using var arg methods.
this is the very easy way to solve this kind of problems from java 1.8.
in implementation
public String implementation(int(change to required datattype)...x){
//here x will act like an array
for(int a:x){//iam assuming int values are coming
System.out.println(a)
}
}
now you can call this function with atleast 0 args like
objecReference.implementation()
objecReference.implementation(10)
objecReference.implementation(10,20)
objecReference.implementation(12,23,34,5,6)

As per your requirement you want to override method from your interface in class B and C , but you cannot do the way you have done that.
One way to do is as :
public interface A<T> {
public void transform(T ... args);
}
public class B implements A<String> {
#Override
public void transform(String... args) {
}
}
public class C implements A<Integer> {
#Override
public void transform(Integer... args) {
}
}

One possible solution could be to use Marker Interfaces. A marker (or tagging) interface is an interface that has no methods or constants inside it. It provides run-time type information about objects.
Here is an example that uses Input interface as transform method parameter. An instance of a class that implements this marker interface can be used as transform method argument.
public interface Input {
}
public interface Transformable {
void transform(Input input);
}
public class InputForA implements Input {
int a;
String b;
public int getA() {
return a;
}
public InputForA setA(int a) {
this.a = a;
return this;
}
public String getB() {
return b;
}
public InputForA setB(String b) {
this.b = b;
return this;
}
}
public class TransformerA implements Transformable {
#Override
public void transform(Input input) {
InputForA inputForA = (InputForA) input;
System.out.println(inputForA.getA() + inputForA.getB());
}
}

Related

Why when I implement a lambda expression in the main method, the compiler doesn't say the interfaces are implemented?

When I implement interfaces as a Lambda expression in my main method, it doesn't count as if it was implemented.
I know I can implement it outside of the main method, but I don't see why I should use Lambda expressions if I have to implement it outside of the main anyway.
public class Driver implements Interface1, Interface2, Interface3 {
public static void main(String[] args) {
//Implementing Interface1
double x;
Interface1 obj = () -> 5.5;
x = obj.foo();
System.out.println(x);
//Implementing Interface2
String str;
Interface2 obj2 = (a) -> String.format("The number is %d", a);
str = obj2.foo(356);
System.out.println(str);
//Implementing Interface3
boolean tF;
Interface3 obj3 = (i, s) -> i == Integer.parseInt(s);
tF = obj3.foo(30, "30");
System.out.print(tF);
}
Here, I get an error message at line 1 telling me that the Interfaces are not implemented. It still compiles and works, I just don't understand why I get this message.
The output is currently:
5.5
The number is 356
true
All you have done is define local variables in the main method whose type happens to coincide with the interfaces that the class must implement.
You must define methods in the class that provide implementations for all the interfaces of the class. For example:
public class Driver implements Interface1, Interface2, Interface3 {
public static void main(String[] args) {
// all code in here is irrelevant to the class implementing Interface1, Interface2, Interface3
}
public void interface1Method() {
// whatever
}
public void interface2Method() {
// whatever
}
public void interface3Method() {
// whatever
}
}
Note that you can't use lambdas for this; Driver must actually declare implementations for the missing methods from all the interfaces its declares it is implementing.

Does a class which implements an interface's method (without explicitly implementing that interface) extend that specific interface?

I am implementing a class to store objects that can be assigned a double value. For this reason, I have created a HasDoubleValue interface, that contains a single method:
public interface HasDoubleValue{
public double doubleValue();
}
My main class is defined as such:
Data <O extends HasDoubleValue> {...}
Now, when I try to initialize this class to store Integers, I get a "type argument Integer is not within bounds of type-variable O" error, although Integer implements the doubleValue() method by default.
I suppose that this happens because Integer does not explicitly implement my HasDoubleValue interface, although it has the method I am looking for. Is this right? What would a natural workaround be?
Yes, it is right. Java doesn't use duck-typing as JavaScript or TypeScript.
A solution is to create an adapter class that wraps a Integer, delegates to it, and actually implement the interface.
Or, since inthis case your interface is a functional interface, to use a lambda or a method reference to create an instance of HasDoubleValue from an Integer.
public interface HasDoubleValue{
double doubleValue();
}
final class IntegerHasDoubleValueAdapter implements HasDoubleValue {
private final Integer i;
public IntegerHasDoubleValueAdapter(Integer i) {
this.i = i;
}
#Override
public double doubleValue() {
return i.doubleValue();
}
}
class Data<O extends HasDoubleValue> {
void put(O o) {}
public static void main(String[] args) {
Integer i = 42;
Data<IntegerHasDoubleValueAdapter> d1 = new Data<>();
d1.put(new IntegerHasDoubleValueAdapter(i));
Data<HasDoubleValue> d2 = new Data<>();
d2.put(() -> i.doubleValue());
Data<HasDoubleValue> d3 = new Data<>();
d3.put(i::doubleValue);
}
}

Can you automatically cast an object of one class to a subclass and call an overloaded method in Java?

I have the following setup:
class Base {};
class ImplA extends Base {};
class ImplB extends Base {};
class ImplC extends Base {};
Base baseFactory(int type) {
switch(type) {
case 0:
return new ImplA();
case 1:
return new ImplB();
case 2:
return new ImplC();
}
Base a = baseFactory(0);
Base b = baseFactory(1);
Base c = baseFactory(2);
List<Base> list = new ArrayList<Base>();
list.add(a);
list.add(b);
list.add(c);
// Somewhere else I have:
interface BaseHandler {
process(ImplA a);
process(ImplB b);
process(ImplC c);
};
Now, what I would like to be able to do is something along the lines of:
class Processor {
BaseHandler bh;
Processor(BaseHandler bh) {
this.bh = b;
}
void processList(List<Base> list) {
for (Base x : list) {
bh.process(x);
}
}
And then have a user implement BaseHandler and be able to construct a Processor to operate on each element in the Base list.
But, this does not work as process(Base) is not defined. It may seem simple to just add 3 if statements, but I already have a switch like structure in building instances of classes extending the Base. It seems unnecessary to repeat this over and over. Is there a way to achieve this idea without writing an intermediate step that determines the runtime class of each Base in the list and calls the appropriate method (in effect another switch case -- but it would be if's)?
I think one work around idea would be to make each Base have an abstract process method which needs to be implemented by the Impl classes. However, this is not acceptable in my situation since the user will not be implementing the Impl classes. Basically, I need process to be a user-defined callback. Further, it does not make sense for process to be a member of the Impl or Base classes since it is in no way related. It's a separate callback that needs to respond dynamically to the type it is called with. And the type is always guaranteed to be a subclass of Base.
You do need the "intermediate step" that you describe, but it need not be if statements. What you're looking for is double dispatch using the visitor pattern. Basically your Base class would have a method:
void accept(BaseHandler handler);
and each subclass would implement it as:
handler.process(this);
where this would resolve to the correct type in each subclass at compile-time.
What you're looking for is the Visitor pattern. You put an abstract method on Base, but all it does is call the appropriate method in BaseHandler:
public interface Base {
void acceptHandler(BaseHandler handler);
}
Then your concrete implementations override acceptHandler and call the correct overload.
public class ImplA implements Base {
public void acceptHandler(BaseHandler handler) {
handler.process(this);
}
}
At this point there's not much value in the overloading, and you'd be better off just giving your methods descriptive names.
It sounds like what you want is the Visitor pattern here:
public interface BaseVisitor {
void caseA(ImplA a);
void caseB(ImplB b);
void caseC(ImplC c);
}
public class MyVisitor implements BaseVisitor {
void visit(List<Base> bases) {
for (Base b : bases) {
b.accept(this);
}
}
public void caseA(ImplA a) { // ... }
public void caseB(ImplB b) { // ... }
public void caseC(ImplC c) { // ... }
}
public abstract class Base {
abstract void accept(BaseVisitor visitor);
}
public class ImplA {
public void accept(BaseVisitor visitor) {
visitor.caseA(this);
}
}
public class ImplB {
public void accept(BaseVisitor visitor) {
visitor.caseB(this);
}
}
public class ImplC {
public void accept(BaseVisitor visitor) {
visitor.caseC(this);
}
}

Method overloading using derived types as parameters in Java

Let's say I have existing code which I want to extend but also to avoid changing it as much as possible.
Somewhere around this code there is a method that receives some type.
Engine.method(Base b)
Now, I want to extend this functionality. So I extends Base into a type called Derived which holds some more data I need and I also implements another method that receives the Derived type and do something different with it.
Engine.method(Derived d)
But I don't want to change the original call to "method". I somehow managed to instansiate the correct type (Base or Derived) by using a flag but since the original call is taking the Base then my new method will not be called.
Base b = null;
if(flag) {
b = new Derived()
} else{
b = new Base()
}
Engine.method(b)
The problem is that now my Engine.method(Derived d) will not be called. I worked-around it by using casting
if(flag)
Engine.method((Derived)b)
But that's wrong and stupid. Any suggestions?
I can always do:
if(flag) {
Engine.methodForBase(new Base())
} else{
Engine.methodForDerived(new Derived())
}
But can you think of something better?
Thanks
That happens because Java uses single dispatch. This ends meaning that in your case, the method called depends on the type of reference "b", which is Base, and not on the type of the instance that "b" holds. Therefore, method xpto.(Base b) will always be called.
You really have to cast it or use the last approach you wrote.
Write this:
class Engine {
public static void method(Base argument) {
if (argument instanceof Derived) {
// ...
}
else {
// ...
}
}
}
But probably, you should extend your Engine class to allow for more polymorphism, e.g. do something like this:
interface Engine<T extends Base> {
void method(T argument);
}
And have implementations for Base and Derived like this:
class BaseEngine implements Engine<Base> {
#Override
public void method(Base argument) { ... }
}
class DerivedEngine implements Engine<Derived> {
#Override
public void method(Derived argument) { ... }
}
Why not simply call the method with a parameter of the correct type?
Base b = null;
if (flag) {
Derived d = new Derived()
Engine.method(d); // so the correct method will be used for Derived
b = d;
} else{
b = new Base()
Engine.method(b)
}
You could also consider reusing the method(Base b):
public void method(Derived d) {
method((Base)b);
...
}

Java; casting base class to derived class

Why can't I cast a base class instance to a derived class?
For example, if I have a class B which extends a class C, why can't I do this?
B b=(B)(new C());
or this?
C c=new C();
B b=(B)c;
Alright let me be more specific as to what I'm trying to do. Here's what I have:
public class Base(){
protected BaseNode n;
public void foo(BaseNode x){
n.foo(x);
}
}
public class BaseNode(){
public void foo(BaseNode x){...}
}
Now I want to create a new set of classes which extend Base and Basenode, like this:
public class Derived extends Base(){
public void bar(DerivedNode x){
n.bar(x);//problem is here - n doesn't have bar
}
}
public class DerivedNode extends BaseNode(){
public void bar(BaseNode){
...
}
}
So essentially I want to add new functionality to Base and BaseNode by extending them both, and adding a function to both of them. Furthermore, Base and BaseNode should be able to be used on their own.
I'd really like to do this without generics if possible.
Alright so I ended up figuring it out, partly thanks to Maruice Perry's answer.
In my constructor for Base, n is instantiated as a BaseNode. All I had to do was re-instantiate n as a DerivedNode in my derived class in the constructor, and it works perfectly.
because if B extends C, it means B is a C and not C is a B.
rethink what you are trying to do.
The existing answers are fine in terms of an abstract argument, but I'd like to make a more concrete one. Suppose you could do that. Then this code would have to compile and run:
// Hypothetical code
Object object = new Object();
InputStream stream = (InputStream) object; // No exception allowed?
int firstByte = stream.read();
Where exactly would the implementation of the read method come from? It's abstract in InputStream. Where would it get the data from? It simply isn't appropriate to treat a bare java.lang.Object as an InputStream. It's much better for the cast to throw an exception.
In my experience it's tricky to get "parallel class hierarchies" like the one you're describing to work. You may find that generics help, but it can get hairy very quickly.
You need to use the instanceof keyword to check the type of object referenced by n and typecast the object and call the bar() method. Checkout Derived.bar() method bellow
public class Test{
public static void main(String[] args){
DerivedNode dn = new DerivedNode();
Derived d = new Derived(dn);
d.bar( dn );
}
}
class Base{
protected BaseNode n;
public Base(BaseNode _n){
this.n = _n;
}
public void foo(BaseNode x){
n.foo(x);
}
}
class BaseNode{
public void foo(BaseNode x){
System.out.println( "BaseNode foo" );
}
}
class Derived extends Base{
public Derived(BaseNode n){
super(n);
}
public void bar(DerivedNode x){
if( n instanceof DerivedNode ){
// Type cast to DerivedNode to access bar
((DerivedNode)n).bar(x);
}
else {
// Throw exception or what ever
throw new RuntimeException("Invalid Object Type");
}
}
}
class DerivedNode extends BaseNode{
public void bar(BaseNode b){
System.out.println( "DerivedNode bar" );
}
}
You can create a constructor for B that takes C as a parameter.
See this post for ideas to do what you're trying to do.
Base classes shouldn't know anything about classes derived from them, otherwise the problems highlighted above will arise. Downcasting is a 'code smell', and downcasting in the base class to a derived class is particularly 'smelly'. Such designs can lead to difficult to resolve circular dependencies too.
If you want a base class to make use of derived class implementations use the Template method pattern i.e add a virtual or abstract method in your base class and override and implement it in the derived class. You can then safely call this from the base class.
You can't do that because C does not necessarily implement the behaviours you created when you extended it in B.
So, say C has a method foo(). Then you know that you can call foo() on a B, as B extends C, so you can cast accordingly a treat a B as if it was a C with (C)(new B()).
However - if B has a method bar(), nothing in the subclass relationship says that you can call bar() on C too. Thus you cannot treat a C as if it were a B, and so you cannot cast.
In your exemple, you can cast n into a DerivedNode if you are certain that n is an instance of DerivedNode, or you can use generics:
public class Base<N extends BaseNode> {
protected N n;
public void foo(BaseNode x){
n.foo(x);
}
}
public class BaseNode {
public void foo(BaseNode x){...}
}
public class Derived extends Base<DerivedNode> {
public void bar(DerivedNode x){
n.bar(x); // no problem here - n DOES have bar
}
}
public class DerivedNode extends BaseNode {
public void bar(BaseNode){
...
}
}
Because if B extends C, then B might have stuff that isn't in C (like instance variables you initialize in the constructor that are not in new C())

Categories

Resources