Just playing around with interfaces and I have a question about something which I can't really understand.
The following code doesn't run, which is the behaviour I expect as the interface method requires the method to work for any object and the implemented method has the signature changed to only allow string objects.
interface I {
public void doSomething(Object x);
}
class MyType implements I {
public void doSomething(String x) {
System.out.println(x);
}
}
However, using the following block of code, I was shocked to see that it did work. I thought it would not work as we are expecting to return an object and the implemented method will only return a string object. Why does this work and what is the difference between the two principles here of passed parameters and return types?
interface I {
public Object doSomething(String x);
}
class MyType implements I {
public String doSomething(String x) {
System.out.println(x);
return(x);
}
}
public Object doSomething(String x);
has to return something. Anything, in fact, so long as it is some type of object. So if you implement
public String doSomething(String x) {stuff}
that's fine, because it does in fact return an Object. The fact that the object it will return will always be a String is no big deal.
The reason the first example doesn't work, is because accepting only strings is more limiting than accepting any object. But returning only strings is fine.
For an analogy, let's say you got a contract to paint a building, and you're gonna hire some employees to help you out. The contract requires that you hire any painter that applies, regardless of how tall they are, but doesn't specify what color paint to use. If you only hired painters over 6 ft tall (that's the input, accepting only String instead of all Object), you'd be violating the contract. But choosing to paint with only blue paint (returning only strings) is just fine, because the contract didn't specify color, only that you must paint the building.
It works because a String is an Object.
This has to do with covariant return types, introduced in Java SE 5.0.
You can see more details in http://docs.oracle.com/javase/tutorial/java/javaOO/returnvalue.html
From the java language specification:
Return types may vary among methods that override each other if the return types are reference types. The notion of return-type-substitutability supports covariant returns, that is, the specialization of the return type to a subtype.
So in other words, it works as you did it, but it would not work if the return type in the interface is String, and in the implementing class is Object.
The principle behind this behaviour is called covariant return type. In this particular case, the overrriding type may "narrow" the originally declared parameter type.
This means that as String is subclassing Object, Object may be substituted by String.
The reason why the first example doesn't work and the second example does, is because function prototypes are defined by the name and all parameters only, but not the return type. In the first example, there is a difference, so the compiler thinks they are two different functions.
In the second example, the implemented function does not broaden the type, but instead specializes the type (String is a specialization of Object), so it works.
Likewise you can limit the visibility of the implemented method, but not broaden it.
Furthermore, Java has generics, which are useful in this context.
Example:
interface I<T>
{
public void doSomething(T x);
}
class MyType implements I<String>
{
public void doSomething(String x)
{
System.out.println(x);
}
}
method signature does not take into account the return type. (Though is is an error to declare two methods with the same signature but different return type). So:
void doSomething(Object)
void doSomething(String)
Are simply two methods and none overrides or implements the other
string class is inherited from object class, so only this code works.
Related
I just came into a problem with designing an interface whose methods may have variable numbers of input arguments.
public interface FoobarSerialization<T> {
Foobar serialize(T obj);
}
The problem is, for the classes that implement this interface, they require different numbers of input arguments.
public class FoobarA implements FoobarSerialization<FoobarA> {
#Override
public Foobar serialize(FoobarA obj, int bar) {
//...
}
}
public class FoobarB implements FoobarSerialization<FoobarB> {
#Override
public Foobar serialize(FoobarB obj, Date date, String str) {
//...
}
}
Is there a good design or any genuine way to solve this problem? I know the method in the interface can be declared as:
Foobar serialize(T... obj);
But I'm not sure if this was a good practice to design an interface like this.
Any thought?
Update: My intention of using an interface came from the collection of classes that need to be serialized and deserialized for different purposes. They serve as components under the same domain. But their serialization methods are quite different, especially considering their dependencies on objects and services that don't share any common features nor classes.
I guess the right question to ask here is: in terms of design, what's the best approach when there exits a set of classes which share the same behaviors (serialize, deserialize, doSomething, etc) but have different input args?
Composition pattern to the rescue.
In your particular case I would create interface which accepts just 1 parameter:
public interface Serializer<T> {
Foobar serialize(T object);
}
Now, if you need to serialize several fields, you just create an object which has all fields you need to serialize:
class FoobarBundle {
String stringField;
int intField;
byte[] arrayField;
/* ... */
}
And write bunch of serializers: FoobarBundleSerializer, StringSerializer, IntegerSerializer, ByteArraySerializer. In the end combine all serializers in FoobarBundleSerializer like that:
class FoobarBundleSerializer implements Serializer<FoobarBundle> {
StringSerializer stringSerializer;
IntegerSerializer integerSerializer;
ByteArraySerializer byteArraySerializer;
/* constructor here */
#Override
public Foobar serialize(FoobarBundle bundle) {
Foobar foobarString = stringSerializer.serialize(bundle.stringField);
Foobar foobarInteger = integerSerializer.serialize(bundle.intField);
Foobar foobarByteArray = byteArraySerializer.serialize(bundle.byteArrayField);
return combineFoobarSomehow(foobarString, foobarInteger, foobarByteArray);
}
}
Your mileage may vary, but usually confusing use (e.g. same number, but different types of arguments) of methods with the same name should be avoided. Though one can take help of method overloading, it is considered less than desirable. If the list of parameters is manageable, you should name the method differently to avoid ambiguities. See Item 26 in Effective Java 2.
The vararg methods are alright, but in Java, the best practice is to specify at least one concrete argument followed by a variable number of arguments of the same type. This is perhaps not applicable in your case, since there is no vararg syntax for a method like public Foobar serialize(FoobarB obj, Date date, String str);. It might be acceptable to use a syntax like (Object ... objects), but this practice is not considered generally applicable.
Contrast this with a method like printf which can and should be able to output a variable number of arguments of any type (including primitives) to an output stream.
I'm currently brushing up my Java and reading up on Generics. Since they were not treated extensively in my Java class, I'm still having some trouble wrapping my mind about it, so please keep that in mind when answering.
First of all, I'm pretty sure that what I'm trying to is not possible. However, I'd like to find out where my thinking is wrong and how I should go about achieving what I want.
What I'm trying to do is manipulating an object that implements a generic interface from another class that has no knowledge about the instantiated type. Thus, I have something like the following classes:
public interface CalledInterface<E> {
public E get() { ... }
public set(E e) { ... }
}
public class Called implements CalledInterface<String> {
...
}
Now what I want to do is:
public class Caller {
protected CalledInterface<?> c;
public Caller (CalledInterface<?> arg) {
c = arg;
}
public void run(){
// I can do this:
c.set(c.get());
// But I'd want to be able to do something like:
<?> element = c.get();
c.set(element);
}
}
What is the fundamental flaw in my thinking, if there is one? And what approach should I rather be taking?
First of all, keep in mind that generics is a compile time thing not a runtime.
Now in your Caller you defined Called c. Called is defined to implement CalledInterface<String>, so automatically, Called has the following methods generated at compile time:
String get();
void set(String e); //i assume you wanted to return void
So essentially this doesn't really make sense:
<?> element = c.get();
The Caller class isn't even aware Called is using generics internally, for it, Called just deals with strings.
UPDATE
Based on your comment, since you don't want Caller to use Called directly but use CalledInterface first thing you have to do is change the type of c to that. In this case you should not use generics, because the whole point of generics is that the same class is used in different scenarios with different types (again determined at compile time), enforcing types without having repeated code.
If I understand correctly you don't want to restrict Caller to use String, so what you have to do is change CalledInterface to not use generics, and change the methods to:
Object get();
void set(Object o);
This is how we used to do things before Generics in Java 1.4. You obviously run the risk of not having type safety, so think through whether what you want really makes design sense, because it probably does not because you have to do instanceof anyway to check the type to use the Object in a useful way (i.e. to access its methods).
If on the other hand you just change the c member (and the constructor argument of Caller) to:
CalledInterface<String> c;
Your Caller will be interacting with the CalledInterface rather than the implementation and at the same time still be type safe. So you can still pass an instance of Called and set it to c.
After your edit:
// I can do this:
c.set(c.get());
No you can't. It won't compile with c being CalledInterface<?>. (Have you even tried it?)
To do this, you can use a "capture helper":
private static <T> void helper(CalledInterface<T> c) {
c.set(c.get());
}
public void run(){
helper(c);
}
Which also solves your second problem:
private static <T> void helper(CalledInterface<T> c) {
T element = c.get();
c.set(element);
}
public void run(){
helper(c);
}
There are a few minor mistakes in your code:
protected Called c;
public Caller (CalledInterface arg) {
c = arg;
}
You are not allowed to assign arg here, because the type CalledInterface is not a subtype of Called (it is the other way around)
Also you should give type information when using CalledInterface (it is allowed to leave it out, but only for legacy purposes).
Now to the part you are wondering about. For the type Called, the compiler knows get() returns a String, if you are not interested in that, you can of course always use Object as the type of element. The compiler also knows that set() takes a String as argument, so it requires you to give one. In generics is essentially the same as using Object in a case without generics (even though it isn't allowed on the location you use it, because it doesn't make sense). This means that you would be telling the compiler to forget the type on the first line (calling get()) and to unforget it on the line below.
I don't understand the overloading in Java. Is there a relation with polymorphism ? It seems very abstract for me.
I come more from Javascript language ? Would this apply so in Javascript ?
Overloading means that the same method name can be defined with more than one signature — the list of formal parameters (and their types).
Overloading means different things in different languages. Java is strongly typed (some might say "fiercely typed" in fact). It just means that there can be different versions of a function and the compiler can tell which one is intended by looking at the types of parameters in a call to the function (method).
JavaScript is not like that; the formal parameters to a function are just references by name in the function body, but otherwise there's nothing special about them and any function can be called with any arguments and any number of them.
Some languages use "overloading" as a runtime concept. In Erlang, it's not the types of arguments that matter when picking from several alternative versions of a function; it's the values.
edit — #MarkoTopolnik points out that the issue isn't so much about the "strength" (or "ferocity" :-) of the type system, but about how static it is. Java insists on types being explicitly declared pretty much everywhere, while JavaScript (excepting some of the new typed array constructs) doesn't.
Overloading is feature that allows having 2 methods with the same name and different signature in one class, e.g.
public void foo();
public void foo(int i);
Now you can call method foo() without arguments or with one int argument and different methods will be executed.
You are probably confused with overloading and overriding. Overriding indeed relate to polimorphysm. This is ability to overrride (change) functionality of base class into subclass. For example if Child extends Base and both have method foo() the foo() of child overrides implementation of Base. Similar feature indeed exists in JavaScript.
if you have following method in your class
public void calculate() {}
Following are some overloaded versions of it.(Note same name)
public void calculate(int i) {}
public void calculate(int i, int j) {}
But following is not an overloaded one of above method. This method differs from the original method only just because the return type. Methods with same signature but with different return types are not allowed in java.
public int calculate(int i) {}
The method which have same name with multiple definition is known as overloading
may be its differ from argument type and number of arguments.
Example
import java.io.*;
class demoOverloading
{
int add(int x,int y) //method definition
{
return (x+y);
}
double add(double x,double y) //method definition
{
return (x+y);
}
}
public class JavaApplication4
{
public static void main(String[] args)
{
demoOverloading demo=new demoOverloading(); //creating object for above class
System.out.println("Sum of Integer "+demo.add(10,20)); //calling integer add method
System.out.println("Sum of double "+demo.add(33.44,67.5)); //calling double add method
}
}
The above example having two methods having same name add but one contains int and another contains double arguments, like this we can made with different argument,,
Also possible made difference in number of arguments..
Thank you
This code is invalid:
interface Foo
{
public void foo(final String string);
}
public class Bar implements Foo
{
// Error: does not override.
#Override public void foo(final Object object)
{
}
}
Because every String is obviously an Object, I would expect this code to be perfectly fine: any code that depends on giving foo() a String would stil function when foo() actually takes an Object.
It appears, though, that method signatures have to be identical to those of the methods they're overriding. Why?
What if
interface Foo
{
void foo(String string);
void foo(Object string);
}
Then which method is overridden by Bar?
'loosening' as you put it should not impact on someone expecting to use your interface defined method in a particular way, as any methods you call on that object should in theory be callable on the specified object, but Eugene's point stands, becaause there would probably be a little compiler headache to deal with in determining what method you actually intended to override if you just vaguely want to stick to the interfaces specification. Also, why whould this be desireable if you are going to stick to moving up the inheritance heirarchy, because surelely you will be able to do all you want to the thing further down the hierarchy as to 'Object' for example? Possibly casting inside your method would solve your problem? If it is possible to do what you want to do, you will also probably start treading on the polymorphism paradigm.
I think this is a classical contravariance issue. Your interface requires a string to be passed as parameter, you want an implementation that accepts an object (because, after all, strings are also objects).
The problem is that if you allowed that, then you could no longer guarantee that the parameter being required by the interface is a string or any one of its ancestors. You might just as well pass any object to your implementation and you would be breaking the contract of the interface, putting in danger the type safety and type coherence of your design.
You do have options, though:
public class Bar implements Foo
{
#Override public void foo(final String object)
{
}
public void foo(final Object object)
{
foo((String) object);
}
}
By this, you would be ensuring that object is actually a string, making possible to the type system to check that you are actually complying with the interface contract established in the method signature.
Is there a particular scenario in which you would consider your contravariance example to be requirement?
It's just the constructs of the Java programming language. The structure of Java programs will grow on you. So for now just try and adjust.
As a practical example of the general question in the subject, I'd like to implement the containsAll method in the Set interface with
public boolean containsAll(Iterable<?> c) { /* ... */ }
I figure this should be allowed, since Collection is Iterable meaning such a containsAll would cover the interface requirement. Likewise, more generally being able to implement interfaces with argument superclasses seems like it should work.
However, Eclipse says no way (haven't tried just javac straight-up) - can someone explain the reason for that? I'm sure there's something in the spec which makes it the way it is, but I'd like to understand the motivation for requirement as well. Or am I missing something like Iterable<?> not being a superclass of Collection<?>?
As a side question - given I'm declaring two methods would the method with the Iterable signature always be preferred on calls with a Collection argument?
Eclipse Error:
If I remove the method with the Collection signature, just leaving the Iterable one (see after error), I get the following:
The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)
The exact implementation being:
#Override public boolean containsAll(Collection<?> c) {
for (Object o : c) if (!contains(o)) return false;
return true;
}
public boolean containsAll(Iterable<?> c) {
for (Object o : c) if (!contains(o)) return false;
return true;
}
Since the interface you are implementing declares the (abstract) method containsAll(Collection<?>), you must implement it with this exact signature. Java does not allow you to implement/override a method with a wider parameter type than the original. This is why you get the error you show when you comment out your method with the Collection signature.
You don't show the other error you claim to get when the method is not commented out, but I guess it might have to do something with ambiguous method overloading.
My guess as to why java has this restriction is, say you have:
class A {
void foo(String s) { ... }
}
class B extends A {
// Note generalized type
#Override void foo(Object s) { ... }
}
Now if you have class C extends B and it wants to override foo, it's not clear what argument it should take.
Say for example C extended A directly at first, overriding void foo(String s), and then it was changed to extend B. In this case C's existing override of foo would become invalid because B's foo should be able to handle all Objects, not just Strings.
The argument types are part of the method signature so the jvm needs a method with exact the same signature to find overrides. A containsAll( Iterable) will have a different signature than containsAll(Collection).
If I remember right the compiler has to use some workarounds to make generics work in spite of this limitation.
To your second question, the compiler would prefer the Collection argument since it is a subtype of Iterable, this makes the Collection method more specific than the Iterable one.