Interfaces as parameters (Restrictions) - java

I came across an AP CSA question which had me puzzled for a while. It was basically an incomplete method that looked like this:
public static void methodMan(Comparable c) {.....}
The question first asked if it was valid to use the comparable interface in the parameter listing, then it asked if there were any restrictions on the comparable object. I was stuck between the choices that said either the object c that is being passed needs to be casted or initialized as a comparable or the object c could be any object that implements the comparable interface. Which one is it, and if it isn't either, what would be a restriction on the object c?

Yes it is valid to use interfaces as a parameter in methods and yes object c can be any object that implements the interface. The only caveat to the second portion is if there is a special method that needs to be invoked that the interface does not implement then you will need to cast it to the class first to get the method For Example:
public class MyComparable implements Comparable<String> {
private String item;
public MyComparable(String item) {
this.item = item;
}
#Override
public int compareTo(String o) {
return this.item.compareTo(o);
}
public Integer doThis() {
return 100;
}
public Integer compareSample(Comparable<String> c) {
if (c instanceof MyComparable) {
return ((MyComparable)c).doThis();
}
return c.compareTo(this.item);
}
}

compiles like a charm:
public static void methodMan (Comparable c) {
out.println ("we ignore c");
}
public static void main (String args[])
{
Comparable c1 = new String ();
methodMan (c1);
methodMan ((Comparable) c1);
String s2 = new String ();
methodMan (s2);
methodMan ((Comparable) s2);
}
and runs like a charm.

Related

Make a copy of a List with abstract type to a List with specific type

first of all my code below just delivers an abstract view of my classes so that you can easily understand what my question is about :) -so also no equals, hashcode.
I have an ABC extended from Observable which has a List of AbstractObservers
Then I have some classes B and C inherit from AbstractObservers. AbstractObservers implements Observer.
The focus is now at the Recover class.
With the method recover() I try to return a List with the concrete type (B or C) instead of AbstractObservers.
I am not satisfies with my solution, I think it could be better, easier?
Have you any idea how I could solve that problem better? The Abstract classes must stay due to Hibernate.
Thank you in advance
public abstract class ABCObservable extends Observable {
List<AbstractObserver> abstractObserverList = new LinkedList<>();
public List<AbstractObserver> getAbstractObserverList() {
return abstractObserverList;
}
#Override
public synchronized void addObserver(Observer o) {
super.addObserver(o);
abstractObserverList.add((AbstractObserver) o);
}
}
AbstractObserver
public abstract class AbstractObserver implements Observer {
#Override
public void update(Observable o, Object arg) {
}
}
B
public class B extends AbstractObserver {
}
C
public class C extends AbstractObserver {
}
Recover
public class Recover {
public List<? extends AbstractObserver> recover(ABCObservable abcObservable) {
List<AbstractObserver> returnList = new LinkedList<>(); //does that delivers a List with AbstractObserver or B or C?
if (abcObservable.getAbstractObserverList().get(0) instanceof B) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
} else if (abcObservable.getAbstractObserverList().get(0) instanceof C) {
returnList = new LinkedList<>();
returnList.addAll(abcObservable.getAbstractObserverList());
}
return returnList; // returns a List with B or C elements
}
}
In Java, you can't convert a list to a new type, what you can do, however, is create a new one and add the values to it. If you use a generic method, you should be able to accomplish this. I haven't test this code, but theoretically it should work:
public <T> List<T> recover(T abcObservable) {
List<AbstractObserver> list = abcObservable.getAbstractObserverList();
List<T> returnList = new LinkedList<>();
returnList = new LinkedList<>();
for(AbstractObserver a : list) {
if(a instanceof T) {
returnList.add(a);
}
}
return returnList;
}
Instead of using a defined class, this snippet uses T, you can find out more about how Java Generic Methods work on this Java Tutorial by Oracle.
EDIT: I think I'm confused about what you are asking for, this doesn't answer your question, if I understand it correctly.

Why is it considered bad practice to define a covariant compareTo method?

Here's an example from my code:
Baseclass:
abstract class AbstractBase implements Comparable<AbstractBase> {
private int a;
private int b;
public int compareTo(AbstractBase other) {
// compare using a and b
}
}
Implementation:
class Impl extends AbstractBase {
private int c;
public int compareTo(Impl other) {
// compare using a, b and c with c having higher impact than b in AbstractBase
}
FindBugs reports this as an issue. But why is that? What could happen?
And how would I correctly implement a solution?
Impl#compareTo(Impl) is not overriding AbstractBase#compareTo(AbstractBase) since they don't have the same signature. In other words, it won't be called when using Collections#sort for example.
EDIT: Added solution without casting
If you don't want to cast you could try the following.
Alter your baseclass to:
abstract class AbstractBase<T extends AbstractBase<?>> implements Comparable<T> {
//...
public int compareTo(T other) {
//...
}
}
And you Impl class to:
class Impl extends AbstractBase<Impl> {
//...
#Override
public int compareTo(Impl other) {
//...
}
}
Solution with casting:
A possible solution would be to override the compareTo(AbstractBase) method in the Impl class and explicitly check if an instance of Impl is passed in:
class Impl extends AbstractBase {
//...
#Override
public int compareTo(AbstractBase other) {
if (other instanceof Impl) {
int compC = Integer.compare(c, ((Impl) other).c);
if (compC == 0) {
return super.compareTo(other);
}
return compC;
}
return super.compareTo(other);
}
}
The following is something that I tried. Not exactly sure this is the reason why findbugs gives the error.
See the following code with a hypothetical implementation of the compareTo method.
Comparing the same objects results in different outputs.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints -2
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return (a + b) - (other.a + other.b);
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
public int compareTo(Impl other)
{
return super.compareTo(other) + (c - other.c);
}
}
Building on my hypothetical compareTo, following seems to be a good solution. You can try to have a method similar to getSum which gives the object instance a value.
public class Main
{
public static void main(String[] args)
{
Impl implAssignedToImpl = new Impl(1, 2, 3);
Impl otherImpl = new Impl(3, 2, 1);
System.out.println(implAssignedToImpl.compareTo(otherImpl)); // prints 0
AbstractBase implAssignedToAbstract = implAssignedToImpl;
System.out.println(implAssignedToAbstract.compareTo(otherImpl)); //prints 0
}
}
class AbstractBase implements Comparable<AbstractBase>
{
private int a;
private int b;
public AbstractBase(int a, int b)
{
super();
this.a = a;
this.b = b;
}
public int compareTo(AbstractBase other)
{
return getSum() - other.getSum();
}
public int getSum()
{
return a + b;
}
}
class Impl extends AbstractBase
{
private int c;
public Impl(int a, int b, int c)
{
super(a, b);
this.c = c;
}
#Override
public int getSum()
{
return super.getSum() + c;
}
}
As sp00m said, your Impl#compareTo(Impl) has a different signature than AbstractBase#compareTo(AbstractBase), so it's not overloading it.
The key point is in understanding why it doesn't work, even when you try to sort() comparing with another Impl, where the more specific signature do matches.
As you defined Comparable<AbstractBase>, you need to define how your
instances compareTo AbstractBase instances. And so you need to implement compareTo(AbstractBase).
You can think that, being Impl a subtype of AbstractBase, the more specific method would be used when a comparison between two Impls takes place. The problem is Java has static binding, and so the compiler defines at compile time which method would use for solving each method call. If what you were doing was sorting AbstractBases, then the compiler would use the compareTo(AbstractBase), that is the one AbstractBase's interface define when it implements the Comparable(AbstractBase) interface.
You can make Impl implement the Comparable<Impl> interface for using the compareTo(Impl) method, but that would only work if you explicitly sort things that are known to be Impls at compile time (ie, an Impl object or Collection<Impl>).
If you really want to apply a different comparison whenever your two objects are Impls, you should fall to some kind of double-dispatch in your Impl#compareTo(AbstractBase) like:
Impl >>>
int compareTo(AbstractBase other) {
return other.compareToImpl(this);
}
int compareToImpl(Impl other) {
// perform custom comparison between Impl's
}
AbstractBase >>>
int compareTo(AbstractBase other) {
// generic comparison
}
int compareToImpl(Impl other) {
// comparison between an AbstractBase and an Impl.
//Probably could just "return this.compareTo(other);", but check for loops :)
}
This requires you add some Impl information in your AbstractBase, which is not pretty, though, but solves the problem the more elegant way it could - using reflection for this is not elegant at all.
The Liskov substitution principle (http://en.wikipedia.org/wiki/Liskov_substitution_principle) states: if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.)
In your case, you are overriding the compareTo method from the Base class in a way that breaks the behaviour of the original method. This is probably why FindBugs has an issue with it.
If you want to be proper about it:
abstract class AbstractBase {
}
class Impl1 extends AbstractBase implements Comparable<Impl1> ...
class Impl2 extends AbstractBase implements Comparable<Impl2> ...
OR
even better, do not use the Comparable interface at all - use a Comparator at sort time instead.
However, in real life there are situations where you need to get around it (maybe you don't have access to the source of AbstractBase, or maybe your new class is just a POC). In these special cases, I would go with the "ugly" cast solution proposed by John.

Java - Interfaces and methods

I'm looking through some interfaces at the moment and I'm wondering why this does not work:
interface I {
public void doSomething(String x);
}
class MyType implements I {
public int doSomething(String x) {
System.out.println(x);
return(0);
}
}
Basically, why can't I implement the method in the interface? THey have different signatures as one has a return type? Isn't the name, parameters and return type what make a method unique?
You can't have different return types. Imagine the following
class Foo implements I {
public int doSomething(String x) {
System.out.println(x);
return(0);
}
}
class Bar implements I {
public void doSomething(String x) {
System.out.println(x);
return;
}
}
List<I> l = new ArrayList();
l.add(new Foo());
l.add(new Bar());
for (I i : l) {
int x = i.doSomething(); // this makes no sense for Bar!
}
Therefore, the return types must also be the same!
Yeah, you're basically correct. Java doesn't allow overloading methods by return type, which would be neat. However, the interface return type must still match.
The method signature consists of the method's name and the parameters types, so you can't declare more than one method with the same name and the same number and type of arguments, because the compiler cannot tell them apart.
Think of a typical use for interfaces: e.g. anything implementing the java List interface must implement boolean add(Object o)
The caller is probably going to do something like:
if (!impl.add(o)) { /* report error */ }
If you were allowed to change the return type, you'd hit all types of problems.
void add(Object o)
if (!impl.add(o)) { // ... your method returns void, so this makes no sense
float add(Object o)
if (!impl.add(o)) { // float to boolean ? are you sure that is what you meant?

Java How does this interface code actually work?

I've put together the code below using ideas giving to me by fellow members and then changing a couple of the containers. For the life of me i cant really get my head around some of this. The reason for the code is that i wished to pass a function as a parameter. The part of code i especially don't understand is:
doFunc(numbers, new IFunction() {
public void execute(Object o) {
Integer anInt = (Integer) o;
anInt++;
System.out.println(anInt);
}
});
I understand to some extent that we're using an interface to represent a function using an object (i think?). This is the full code:
public static void main(String[] args) {
Integer[] strArray = new Integer[]{1,2,3,4,5};
List numbers = Arrays.asList(strArray);
doFunc(numbers, new IFunction() {
public void execute(Object o) {
Integer anInt = (Integer) o;
anInt++;
System.out.println(anInt);
}
});
for(int y =0; y<numbers.size();y++){
System.out.println(numbers.get(y));
}
}
public static void doFunc(List c, IFunction f) {
for (Object o : c) {
f.execute(o);
}
}
public interface IFunction {
public void execute(Object o);
}
I guess i just need someone to go a little slower explaining it. Thanks for bearing with me.
That's an anonymous inner class. You could do as good as follows:
public static void main(String[] args) {
Integer[] strArray = new Integer[]{1,2,3,4,5};
List numbers = Arrays.asList(strArray);
doFunc(numbers, new ConcreteFunction());
for(int y =0; y<numbers.size();y++){
System.out.println(numbers.get(y));
}
}
public static void doFunc(List c, IFunction f) {
for (Object o : c) {
f.execute(o);
}
}
public interface IFunction {
public void execute(Object o);
}
public class ConcreteFunction implements IFunction {
public void execute(Object o) {
Integer anInt = (Integer) o;
anInt++;
System.out.println(anInt);
}
}
The difference is that a concrete class is reuseable while an anonymous inner class is not.
See also:
Java tutorial - Inner classes
The main concept here is that since the second object you're passing to doFunc is anonymous, you don't need to instantiate an object here - just the interface. Here's what each part of the code is saying:
public interface IFunction {
public void execute(Object o);
}
This says that any object which implements the interface IFunction has one method, execute, which it runs on another Object.
public static void doFunc(List c, IFunction f) {
for (Object o : c) {
f.execute(o);
}
}
This function takes a List c and any Object which implements IFunction, then runs the execute method - guaranteed to be in the second object by the IFunction interface - over all the objects in c.
doFunc(numbers, new IFunction() {
public void execute(Object o) {
Integer anInt = (Integer) o;
anInt++;
System.out.println(anInt);
}
});
This snippet from main takes a list of numbers and creates an anonymous object in-place which implements the IFunction interface. Since it's not any concrete object type, it doesn't need to have any other methods, just execute, which it defines inline.
The end result is that your IFunction object declared inside the call to doFunc is effectively a functor - it's a throwaway object that encapsulates a function, which can be run over a list of objects.
IFunction, in this case, specifies an interface that anyone who implements the interface must define.
public void execute(Object o);
This means that any object that is an IFunction has this method. The anonymous IFunction being defined in your example casts it's argument to an integer and then increments it and prints the value.
As doFunc requires a List of objects and an object that implements IFunction, the call in main passes numbers, a list of numbers, and the anonymous IFunction which increments them and prints their value.
doFunc then takes these objects in the list and passes them as an argument to the IFunction f.

Java generics (template) specialization possible (overriding template types with specific types)

I'm wondering what are the options to specialize generic types in Java, i.e. in a templated class to have specific overrides for certain types.
In my case I was a generic class (of type T) to return null usually, but return "" (the empty string), when T is the String type, or 0 (zero) when its the Integer type, etc.
Merely providing a type-specific overload of a method produces a "method is ambiguous" error:
e.g.:
public class Hacking {
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
Bar<String> barString = new Bar<String>();
// OK, returns null
System.out.println(barInt.get(new Integer(4)));
// ERROR: The method get(String) is ambiguous for the type Bar<String>
System.out.println(barString.get(new String("foo")));
}
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
}
Is the only option to subclass the generic class with a specific type (see StringBar in the following example?
public static void main(String[] args) {
Bar<Integer> barInt = new Bar<Integer>();
StringBar barString2 = new StringBar();
// OK, returns null
System.out.println(barInt.get());
// OK, returns ""
System.out.println(barString2.get());
}
public static class Bar<T> {
public T get() {
return null;
}
}
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
}
Is this is the only way, it's a bit of a pain to have to create a subclass for every type I want to specialize instead of an overload of get() in the Bar class.
I'm guessing I could check the instanceof in the Bar.get() method, e.g.
T get(T t) {
if (t instanceof String) return "";
if (t instanceof Integer) return 0;
else return null;
}
However I've been taught to avoid instanceof and use polymorphism when possible.
All things considered, the concensus appears to be that the StringBar method mentioned in the question is the only way to go.
public static class StringBar extends Bar<String> {
public String get() {
return "";
}
}
Generics in Java are very different from templates in C++ in this respect. It is not possible to write a specific version of a generic class to do something different for a particular case, as C++ can do. It is also not possible to determine at run time what T is - this is because that information is not passed into the byte code (object code) and so doesn't even exist at runtime. This due to something called "type erasure".
BarString and BarInt would be the obvious way of doing this, but there are improvements you can make. For example you can write a generic Bar to cover the common cases, and then write specialized BarString and BarInt to implement special cases. Ensure that the instances can only be created through a factory, which takes the class of the object to be processed:
class Bar<T> {
class BarString extends Bar<String> {
// specialist code goes here
}
static Bar<T> createBar(Class<T> clazz) {
if (clazz==String.class) {
return new BarString();
} else {
return new Bar<T>;
}
That probably won't compile, but I don't have the time to work out the exact syntax. It does illustrate the principle.
The compiler is actually correct, because the following code is compile-time checked (Bar<String> barString = new Bar<String>();) when compiled, from
public static class Bar<T> {
public T get(T x) {
return null;
}
public String get(String x) {
return "";
}
}
to
public static class Bar<String> {
public String get(String x) {
return null;
}
public String get(String x) {
return "";
}
}
and is ambiguous as you can't have 2 identical methods with the same return types and the same parameter arguments.
See an explanation by Jon Skeet's:
What is the concept of erasure of generics in java?
Java Generics - Types erasures - when and what happens?
You can subclass Bar<T> and create StringBar (note I removed the static keyword) and override get() method.
public class BarString extends Bar<String> {
#Override
public String get(String x) {
return "";
}
}
Generics in Java aren't made for specialization. They're made for generalization! If you want to specialize for certain types, you should be specializing...through a subclass.
Often you don't need to do something in a specialized manner however. Your StringBar example is kind of contrived because you could have this:
public class Bar<T> {
private final T value;
public T get() {
return value;
}
}
I don't see why you need to specialize for a String here.

Categories