Create an object with a String and method overloading - java

I have a String which can either be of Double or Integer type or some other type. I first need to create a Double or Integer object and then send it over to a overloaded method. Here's my code so far;
public void doStuff1(object obj, String dataType){
if ("Double".equalsIgnoreCase(dataType)) {
doStuff2(Double.valueOf(obj.toString()));
} else if ("Integer".equalsIgnoreCase(dataType)) {
doStuff2(Integer.valueOf(obj.toString()));
}
}
public void doStuff2(double d1){
//do some double related stuff here
}
public void doStuff2(int d1){
//do some int related stuff here
}
I'd like to do this without if/else, with something like this;
Class<?> theClass = Class.forName(dataType);
The problem is 'theClass' still can't be cast to either double or int. I would be gratefull for any ideas.
Thanks.
Found a related thread; Overloading in Java and multiple dispatch

This is not just a problem of dealing with primitive types.
Which method to call is decided in compile time, that is, if you want to be able to call different methods depending on the type of the arguments, you'll need several calls (i.e. you need the if-construct).
In other words, it wouldn't work even if doStuff2 took Integer and Double as arguments (your code is basically as good as it gets).
(In fancy words, this is due to the fact that Java has single dispatch. To emulate multiple dispatch you either need to use conditional statements or a visitor pattern.)

Since the method call is decided at compile time as the another answer told you, overloading won't work for you. I think that this problem can be solved with inheritance. So you write a base class with yourMethod() and override it in your derived classes.

As aioobe says, the choice between overloaded methods is made at compile time based on the static types of the arguments.
If you want to simulate overload choice at runtime, you will need to do some complicated runtime analysis of the different possible methods. It would go something like this:
get all declared methods of the class that declared doStuff2.
filter out the methods whose name is not doStuff2.
filter out the methods whose argument type cannot be assigned from the (dynamic) type of the argument value.
of the remaining methods, pick the one that is the best match ... taking care to deal with "ties" as ambiguous.
This will be tricky to code, and trickier if you also throw in handling of primitive types. It will also make the method calls expensive.
Frankly, some kind of hard-wired dispatching is much simpler. If you don't like if / else tests (or switching on a String in Java 7), then you could do something like this.
Map<String, Operation> map = ...
map.put("Double", new Operation(){
public void doIt(Object obj) {
doStuff2((Double) obj);
}});
map.put("Integer", new Operation(){
public void doIt(Object obj) {
doStuff2((Integer) obj);
}});
...
map.get(typeName).doIt(obj);
... which at least allows you to "plug in" support for new types dynamically.

If you resort to reflection, you'll only have to deal specially with primitive types. So your technique can work, but with the addition of a few explicit tests. If you need to reflectively find a method that accepts a primitive double, use double.class.

Related

java - use Object as parameter in method signature versus method overloading

I have a method in which I need to pass to it either a single domain object or a collection of them. Processing of the parameter passed differs slightly depending on whether it's a single instance or a collection.
May I ask for advice on the best approach ? Should I make the method signature accept an Object type and then process with instanceof and downcasting as below ?
private static synchronized void mymethod(Object obj) {
if (obj instanceof List ) {
...
}
else if (obj instanceof MyObjectClass) {
...
}
}
Or should I use overloading ? Any pitfalls in each case ?
I understand the first case is a bit dangerous as it could accept anything passed to it, however my code is not meant to be used as an API or extended etc.
There are different approaches to this kind of design "problem".
Using method overloads:
void myMethod(final MyObject myObject);
void myMethod(final List<? extends MyObject> myObjects);
Using a var-args input parameter:
void myMethod(final MyObject... myObject);
-> myMethod(myObject);
-> myMethod(myObject, myOtherObject);
-> myMethod(myObjectsArray); // myObjectsArray = new MyObject[]
Using a Collection/List as input parameter:
void myMethod(final Collection<? extends MyObject> myObjects);
-> myMethod(Collections.singletonList(myObject));
-> myMethod(myObjectCollection); // List<MyObject>, Set<MyObject>, Collection<MyObject>
Personally I'd go with method overloads, as the internal logic usually changes, slightly maybe, but it changes. The intent is more clear, and JavaDoc can be customized for the single method.
I'm a "picky" developer, and I prefer explicitly stating that there can be two forms of input. I prefer overloads even when it might be not necessary (at the moment). In that case I just delegate to the Collection<?> method, or the opposite.
void myMethod(final MyObject object) {
myObject(Collections.singletonSet(object));
}
But that is based on opinions.
I'd say the most important aspect is, don't duplicate code!
Overloading is usually the way to go in such situations. Remember that the generic type of the list is actually 'type erased' at runtime, so you won't really know that your List is actually a List<MyObjectClass>. Overloading will give you compile time checks, so it's safer.
When using generics also think if your MyObjectClass is going to be extended in some way. And you might get a collection of those objects instead.
Also, as a general pattern, try to avoid repeating code in both overloaded methods. So if you are doing the same thing on all objects when you pass a List you can call one method from the other as follows:
private static synchronized void mymethod(MyObjectClass obj) {
//todo: do the logic on the object
}
private static synchronized void mymethod(Collection<? extends MyObjectClass> collection) {
//assuming the logic is the same, otherwise do whatever you need to do here
collection.forEach(obj -> mymethod(obj));
}
Downcasting and instanceof are usually symptoms of design decisions that do not quite fit what you need. Sometimes it is difficult to get out of them, and you have to resort to them, but in general it is ideal to let the compiler verify your types and do the right method resolution for the behaviour you want.
Method overloading suffice your need. I can think of following ways
private static synchronized void mymethod(MyObjectClass myObj){
...
}
private static synchronized void mymethod(Collection<MyObjectClass> myObj){
...
}
TreffnonX has already given more detailed and generic-based correct approach while i was editing my answer. Refer to it :)
Overloading the method seems more correct here, though both versions would work. That way, the compiler can evaluate the code as far as possible. However your code seems a bit incomplete, to be honest. My personal approach would be to go even further and generalize the method with a generic Type:
private static synchronized <T extends MyObjectClass> void mymethod(T obj) {
...
}
private static synchronized <T extends MyObjectClass> void mymethod(Collection<T> obj) {
...
}
The advantage of this version is, that whatever you do inside your mymethod, you can return stuff related to the type, and modern IDEs can greatly help your evaluation and resolve Lambdas better.
Also, why specifically a List? Does a Collection do? Usually when you limit yourself to lists, you miss out on Sets and other important collections.

Why a boolean can be in some cases converted to a string, and in other cases not?

I used a method that took a String and I wanted to pass a primitive boolean. I expect it to take that boolean and convert it to a String containing either "true" or "false".
Assume the following method:
public void method(String input) { ... }
I first tried something like this:
boolean myBoolean = true;
method(myBoolean.toString());
This gave me an error during compilation. But then when I added following additional overloaded method, this worked again:
public void method(Boolean input) {
method(input);
}
I was confused to discover that in that case, calling method(myBoolean) worked just fine.
Why is this?
First thing to understand is that primitives do not have methods. At least not as of date, and might change with implementation of Project Valhalla. To be able to call the toString() on it, you will first require to box it either by autoboxing or by wrapping it explicitly.
Given a method public void takeString(String input) {}:
takeString(true) will fail, although
takeString(""+true) will work, as it is equivalent to
takeString(""+Boolean.valueOf(true).toString()), which works.
takeString(Boolean.valueOf(true).toString()) will work as well, but note that
takeString(Boolean.valueOf(true)) will fail again for the same reason as in (1).
It might be curious that in case (2), it was able to apply autoboxing and implicitly call the toString(), while it was not able to do so for (1).
But there is good reason for it, as in the case of (2), it is clear to the compiler that the method signature will have a parameter type of String, so it can do the needed implicit conversions. While for (1), it would be dangerous to do so given that we can have multiple overloaded versions of takeString. It just makes the compiler's job simpler, and avoids issues when the overloaded version would be added later on. It is safer to fail on (2).
Example, we do not want logic to suddenly change because we add following method: public void takeString(boolean input) {}.
Possibly you could consider adding following method:
public void takeString(Boolean b) {
takeString(b.toString());
}
The intent of "conversion-only" is clear here, and will reduce the chance of adding in additional unintended logic.
In that case, it might also be wiser to provide an overloaded version for the native boolean parameter to avoid surprises later on as the API evolves.
Then all your cases, except true.toString() will work. Seems like a case to ask to implement conversions in Java, the way we have them in Scala. That will avoid a lot of overload boilerplate.
Primitive types (boolean for example) do not have methods. That is why an error occured when you tried boolean.toString(). Wrapper classes than though (Boolean.toString() for example).
Now for the method, if your method is like this:
public void method(String s)
then you must have made another method like this:
public void method(boolean b)
to be able to perform method(boolean). Without the method(boolean b), your compiler would say method cannot be applied to boolean or something along those lines.

Modelling number types and arithmetic operations between them in Java

What I'm trying to do:
I'm creating a class hierarchy that represents and has utilities for a lot of linear algebra concepts (both to practice linear algebra and to practice Java, which I'm learning right now).
All went pretty well until I decided to add the different types of numbers, that is, integers, rationals, reals and complex (for now).
What I want is to be able to operate with them (for example, inside a Matrix class) without having to care about which number type I'm operating with, and implement all the operations inside different classes representing each number type.
What I thought/tried:
I thought it was a good idea to make an interface called "AnyNumber" (since Number is already taken by the Java API) on which I'd define all the necessary abstract methods, and then implement that interface on each number type class.
The problem is, I can't figure out how to handle class types.
Here is what the interface declaration would look like:
public interface AnyNumber {
public AnyNumber add(AnyNumber other);
public AnyNumber subtract(AnyNumber other);
public AnyNumber multiply(AnyNumber other);
public AnyNumber divide(AnyNumber other);
}
This way, I'd be able to operate with any objects that implement the interface by simple calling methods like:
number1 = number1.add(number2)
The problems I had
The problem comes when trying to implement the interface methods on a particular class.
I thought Java understood that the type "AnyNumber" could be any type that implements the interface, so I tried declaring the methods like this:
public IntegerNumber add(IntegerNumber other) {
return new IntegerNumber(this.value + other.value);
}
But Eclipse complained that I did not not implement the following method:
AnyNumber add(AnyNumber other)
Then I though that I could just change the return and argument types to "AnyNumber", but soon realized I couldn't access the variable "value" inside "other" because the interface doesn't define it.
So I thought maybe what I needed was an abstract class that defined all the necessary fields and abstract methods for all the different types of number, but I'm not sure if that's a good approach, since integer numbers just need one field, while rationals need two, and complex need also two but I'd like to name them different. Also, something keeps telling me that an interface makes a lot of sense in this situation..
..So I though maybe what I needed were generics. But I don't yet fully understand them and all my attempts to use them to solve this problem have miserably failed.
Please help
I realized I'll not be able to solve this alone... I really want to continue working on this project and learn how to deal with this kind of situations in Java.
Your help is very much appreciated!
When you implement an interface method, the parameter types need to be exactly the same as they are in the interface. The return type doesn't have to be the same--it can be a subclass (this is called covariance). But the parameter types can't be subclasses (this is called contravariance and Java doesn't allow it).
The reason is that there's nothing preventing the types of the two AnyNumber objects to be different.
AnyNumber n1 = new IntegerNumber(123);
AnyNumber n2 = new RealNumber(23.4);
Then later, you could say:
IntegerNumber n3 = n1.add(n2);
Or you can pass n1 and n2 as parameters to some other method that tries to do the above. The point here is that since n1 and n2 are declared as AnyNumber, the compiler cannot tell, at that point, whether the two objects have the same class.
This means that if you require that the two objects have the same class, you'll have to enforce it yourself, at runtime.
Your implementing class needs to look like
public class IntegerNumber implements AnyNumber {
public IntegerNumber add(AnyNumber other) { // NOTE: Must be AnyNumber!!
IntegerNumber otherInteger = (IntegerNumber)other;
// will throw a ClassCastException at runtime if "other" is, say, RealNumber
...
}
}
The rest of the method can use otherInteger, which the compiler knows will be an IntegerNumber at that point, since you've checked. There are other things you can do; you can use instanceof to check, and control what exception you throw (or what else you do) instead of letting the cast throw the exception. You could also add mechanisms to handle adding of different AnyNumber types, if you choose.

Why is the return type of method not included in the method-signature?

Why does return type of method not included in signature?
An example
public void method1(String arg){...}
public String method1(String arg){...}
It will cause an error.
This is done because the compiler would not be able to figure out the overload in all contexts.
For example, if you call
String x = method1("aaa");
the compiler knows that you are looking for the second overload. However, if you call
method1("aaa");
like this, the compiler has no idea which one of the two methods you wanted to invoke, because it is OK to call a method returning String and discard the result. To avoid ambiguities like this, Java prohibits overloads that differ solely on the return type.
Since your question doesn't address any particular programming language in the title (I know it does in the tag) I'll share my recent experience with Swift.
In Swift function/method signature actually includes return type. So compiler throws an error only if you call this function/method without explicitly specifying return type, e.g.:
func some() -> Bool {
return true;
}
func some() -> Int {
return 1;
}
let valBool: Bool = some()
let valInt: Int = some()
// this doesn't work: Ambiguous use of 'some'
some()
On top of this Swift even makes it more interesting. It allows you to have 2 functions/methods with the same parameters and return types only if parameters names are different, e.g.:
func some(#foo: Bool) -> Bool {
return foo;
}
func some(#bar: Bool) -> Bool {
return bar;
}
some(foo: true)
some(bar: false)
Thus it gives you semantic differentiation in methods signature
UPD. Since Swift 2.0 external parameter name was changed and now you have to provide external and local names twice even if it's the same
func some(foo foo: Bool) -> Bool {
return foo;
}
func some(bar bar: Bool) -> Bool {
return bar;
}
some(foo: true)
some(bar: false)
You can't overload a method only on it's return type. It's simply illegal. Let's assume for a moment that overloading methods using return type would be legal and you defined two method1 methods. Now we want to call that which returns the String object:
String string = method1(sth);
The JVM theoretically would be able to recognize which method you inteded to call, but what about such call:
method1(sth);
As you can see both methods could be invoked and such operations is unambiguous. The JVM doesn't know which method it should call. This is why such overloading is forbidden.
Because it is impossible to resolve which of the overloaded methods should be called in a case like this:
public static void main(String... args) {
method1("aaa");
}
There are several points to consider when designing things like overload resolution.
Reasons to omit overloading on return type:
Simplify ignoring the function return value (like people often do with the error codes).
Makes program easier to digest for human readers. In particular, that is the reason in Python they do not have function overloads at all. (matter of taste)
C legacy. When language comes from C-family and designers do not consider something to be a big deal it is left as it has always been...
Reasons to add overloading on return type:
Make it difficult to ignore returned values. This may be convenient and saves some typing, but will definitely bite you one day.
Expressivness (of course as opposed to ease of digesting :)). Did you ever wanted to write things like int x = json.get("int_value"); float y = json.get("float_value");? In some languages (like C++) that is still possible to achieve with proxies and cast operators, but overload on return type would be so much easier.
Expressiveness. Every time you pass retun value as a reference to your function just to reuse its resources this could be an overload on return type (with like hidden parameter). Consider string s; getline(cin, s); vs string s = getline(cin);. And this is where expressiveness comes together with referential transparency, and eventually, ease of code digesting.
Now back to your question 'why?'. Since you were asking about Java, the answer is obviously because James valued reasons to omit return type overloads over the reasons to include them in the language.
I had this very same question myself at one point, and while I can see how the compiler wouldn't know which function to call when you don't assign the return value to a variable of the appropriate type, why throw the error at the function level? Why not at the point the function(s) are called? Basically, once you've committed to having the signature differ only by the return value, it's up to you to make sure you use them that way, and then, and only then, would the compiler complain. Of course, it may take some extra work to get this to work with a strict one-pass compiler, but I think it could fly.
you can call function as procedure: method1("arg"); where method1 is the second method in your list (String method1(String arg){}). Compiler then would be unable to distinguish it from the first one (void method1(String arg){}).
Compiler takes care of method binding. When ever it encounters methodName() it has to bind to some method definition, at that point it may not know the return type of method. So method return type is not included in the method signature. Compiler binds the method according to the method signature.
When compiler encounters the method call. It statically binds the method call to one of the methods defined.
Lets see what happens if the return type is included in the method signature
class Example{
public void method1(String arg){ return arg}
public String method1(String arg){}
public static void main(String[] args){
Example e = new Example();
e.method1("abc");
}
}
e.method1("abc") The compiler will not know which method to bind to if return type is included in the method signature.
Method overloading is checked on the basis of number and type of arguments not on the basis of return type. That's why you are getting the error.

How to prevent a method from overloading in Java?

Overriding a method can be prevented by using the keyword final, likewise how to prevent overloading?
You can't. Because it's almost pointless.
If you want to overload the method handle(..) but you are disallowed to, you'd create doHandle(..) instead.
Which overloaded method is used is determined at compile time (in contrast to overridden methods, which are determined at runtime). So the point of overloading is sharing a common name for common operations. Disallowing that is a matter of code-style, rather than anything else.
You can't do that in Java.
An overloaded method is basically just another method.
An attempt could look (something) like this
void yourMethod(String arg) { /* ... */ }
void yourMethod(String arg, Object... prevent) {
throw new IllegalArgumentException();
}
but it won't work since Java resolves overloading by looking at the "best match" or "most specific signature".
The method could still be overloaded with a
void yourMethod(String arg, String arg2) { /* ... */ }
which would be called when doing yourMethod("hello", "world").
Btw, why would you want to prevent overloading? Perhaps there is another way of doing what you want?
Err... what's the point in not allowing to Overload the method?
Protection from Overriding is allowed because it can be done by another programmer who is supposedly working on another part of code and his class is inherited from your class.
Overloading is done in the same class and is logically supposed to be done by a programmer who knows this code and is working on the same part of the code. So, if he knows this code (theoretically) and there is some inherent danger in overloading, then he should know this already because he knows the code.
That said, overloading cannot be stopped as others have already described.
Mark the class final and it can't be extended. That may defeat some other purpose though.
If you overload a method, you've created a method with the same name but different parameter types. In Java, a method is defined (partly) in terms of its parameters, and thus if two methods have the same name but different parameters, then they are apples and oranges, i.e., not the same. In short, you can't prevent someone from creating new methods in a class, which is essentially what you're asking for.
simple! don't call that overloaded method.
public class Test
{
public void m(int a)
{
*your definition*
}
public void m(float a)
{
*your definition*
}
}
public static void main(Strings [] args)
{
Test t=new Test();
t.m(5);
}
Overriding and Overloading are different techniques. Overloading is a way of declaring multiple methods with the same names but different parameter types or different no of parameters.
You can prevent a method from being overwritten by making it final, but you cannot prevent a method from being overloaded. Well technically you could make the class itself final, so that no methods at all can be added by creating a subclass but I don't think that's a good design.

Categories