Overriding abstract methods when using generics - java

I have the following classes:
Base class
public abstract class ArrayManipulation {
public <T> T[] largestSubArray(T[] a){
(((CharacterArrayManipulation)this).compare(a[0],a[1]);
return a;
}
abstract <T> boolean compare(T a,T b);
}
Sub class
public class CharacterArrayManipulation extends ArrayManipulation<Character> {
public Character[] largestSubArray(Character[] input){
super.largestSubArray(input));
}
//This is not seen as overriding
protected boolean compare(Character a, Character b){
return a==b;
}
}
I want to override the compare function in the sub-class CharacterArrayManipulation. When I try to do that, I get
CharacterArrayManipulation must either be declared abstract or implement abstract method compare(T,T) in ArrayManipulation
EDIT
I changed it to the following after the comments, it still seems to give the same error:
Base class
public abstract class ArrayManipulation<T> {
public T[] largestSubArray(T[] a){
this.compare(a[0],a[1]);
return a;
}
abstract boolean compare(T a,T b);
}
Sub class
public class CharacterArrayManipulation extends ArrayManipulation<Character> {
public Character[] largestSubArray(Character[] input){
super.largestSubArray(input));
}
//This is not seen as overriding
#Override
boolean compare(Character a, Character b){
return a==b;
}
}

First of all, your super class should not have any knowledge of its sub classes, and so the implementation of ArrayManipulation.largestSubArray() should be left empty and abstract, or non-empty with a body that does not do any casting to sub classes (the casting is unnecessary as all sub classes of ArrayManipulation will have an overridden version of compare(), not just CharacterArrayManipulation).
Your super class isn't generic, as you haven't added the T generic to the class header.
public abstract class ArrayManipulation<T> { ... }
You should then remove the generic declaration from the largestSubArray() method and the compare() method.
public T[] largestSubArray(T[] a){ ... }
boolean compare(T a, T b);
You can't use an access modifier in the overriding version that is different to the overridden version.
// Note the lack of `protected`
boolean compare(Character a, Character b){ ... }
Side-note: You should use the #Override annotation when overriding methods. It will give you more applicable error messages and explicitly says that you are attempting to override a method.

When you declare a method with a generic placeholder you get a generic method. Even when you use the same name for the placeholder as in the surrounding class this is not the same.
The problem is:
abstract <T> boolean compare(T a,T b);
This T is different (try, it will give the same error when renamed to U).
When understanding your code right, simply removing the declaration of this additional generic variable will solve your problem:
abstract boolean compare(T a,T b);
now the generic placeholder of the class is used which is what you expected I think.

Related

Java - generic classes hierarchy and generic methods overloading

I have a (non abstract) generic base class A<L,M>, an abstract generic sub class B<K, L, M> extends A<L,M> and a (non abstract) class C extends B<Integer, Integer, Void> :
public class A<L,M> { }
public abstract class B<K, L, M> extends A<L,M> { }
public class C extends B<Integer, Integer, Void> { }
I have a utils class that has a few methods, two are relevant here:
public static <K, L, M> void doSomething(B<K, L, M> b) {...}
public static <L, M> void doSomething(A<L, M> a) {...}
To be clear, both methods have the same name.
If I call doSomething(c); (where C c) it goes as expected to the 1st method.
My issue is with the following code (at another class that uses the utils):
private void doSomethingMoreComplex(A a) { // a is actually C
Utils.doSomething(a);
}
So here a is actually C but it goes to the second method, I am not sure if I made a mistake in the code or this is actually the expected behavior.
This is the expected behavior. The runtime type of a is inconsequential, as this method resolution is done in compile time. Since doSomething(B) cannot be applied to an argument of type A, the method is resolved to doSomething(A).
You could handle this yourself by explicitly downcasting a:
private void doSomethingMoreComplex(A a) { // a is actually C
if (a instanceof B) {
Utils.doSomething((B) a);
} else {
Utils.doSomething(a);
}
}
... but, well, in a word - yuck.
The more idiomatic way to address this would be to have doSomething as a method of A and override (not overload) it in B.
or this is actually the expected behavior.
Yes, it's the expected behavior.
The compiler chooses which method is run, and it doesn't know that it is a B (because you've said it's an A). So it doesn't know if the first overload is safe to invoke, but it knows the second overload is.

Sort ArrayList of objects that are instance of sub classes of abstract class

this my main structure:
Some of the interface methods are implemented in class A, all the rest are implemented in sub classes.
public interface I
{
// some methods
//
}
public abstract class A implements I
{
// some variables and methods
//
}
public class B extends A
{
// some variables and methods
//
}
public class C extends A
{
// some variables and methods
//
}
public abstract class D extends A
{
// some variables and methods
//
}
public class E extends D
{
// some variables and methods
//
}
public class Test
{
public static void main(String[] args)
{
ArrayList<I> la = new ArrayList<I>();
la.add(new B(..));
la.add(new C(..));
la.add(new C(..));
la.add(new B(..));
la.add(new E(..));
}
}
There are constructors in B, C and E classes.
I need to sort la by variable of class A, the variable is int data type.
I try to change to
public abstract class A implements I, Comparable<A>
But I get an error because of missing public int compareTo(A o) method in all nonabstract classes.
What I need to do ?
Thanks.
I solved it by adding
public interface I extends Comparable<I>
and in class A I changed the method compareTo to
public int compareTo(I obj)
{
return someVariable - obj.someVariable;
}
public abstract class A implements I, Comparable<A> {
// some variables and methods
#Override
public int compareTo(A o) {
return someVariable - o.someVariable;
}
}
You don't need no constructor in A to implement a compareTo method, and you have got some variables you may use for comparison. compareTo is just a method, so since you can have methods in A, you can also have a compareTo method. Since I don't know what varables you've got nor the sort order you require, you will have to fill out the method yourself.
On the other hand it could well be a good idea to have a constructor in A, but this is a completely independent question.
Edit: I didn’t think this through at first: you will of course want to do
Collections.sort(la);
This is not as straightforward as it may sound. Collections.sort() is a generic method declared according to the docs as:
static <T extends Comparable<? super T>> void sort(List<T> list)
This means that for the compiler to be happy about a call to the method, the declared element type of the list must be one that implements Comparable<U> for some type U that is either the element type or a supertype of it. Your element type is I, and I doesn’t implement Comparable. This is why you get the error message.
The solution? I don’t think the perfect solution exists. Assuming you don’t want to declare la an ArrayList<A>, another option is to declare that I is comparable:
public interface I extends Comparable<I>
Strictly speaking this is promising more about A than we can fulfil. We can compare two A objects (even when they are instances of subclasses of A), but there might be other implementations of I, and we may not know how to compare them to A. One way out is:
#Override
public int compareTo(I o) {
A oa = (A) o; // will throw ClassCastException if o is not an A
return someVariable - oa.someVariable;
}
Since A extends I and I extends Comparable<I>, we now have to declare o an I, not an A. If somebody gives us some foreign I implementation, we throw a ClassCastException, and the sorting would propagate that to the caller. However, we know that in your list all elements are instances of subclasses of A, so this won’t happen. With the above, both your call to S.sortBySome() and its call to Collections.sort() will work.

The return type is incompatible with LinkedList<T>

Eclipse is giving me a return type incompatible error on an inherited method that I've overridden.
I have a generic SomeQueue class that extends LinkedList and implements a generic this is my generic SomeList class
public abstract class SomeQueue<T> extends LinkedList<T> implements SomeList<T>{
private int capacity=100;
public SomeQueue(){
super();
Queue<E> tqueue=new LinkedList<T>();
T front=null;
T back=null;}
#Override
public boolean isEmpty(){}
#Override
public E get(int index){}
#Override
public int size(){}
#Override
public void add(T thing){}
#Override
public E removeEnd(){}
#Override
public void addFirst(T thing){}
#Override
public T remove(int index){}
}
and here's my SomeList interface
public interface SomeList<T>{
public boolean isEmpty();
public T get(int index);
public int size();
public void add(T item);
public T removeEnd();
public void addFirst(T thing);
public T remove(int index);}
Eclipse gives me an error on the add(T thing) method in the QueueLis<T> class.
that explicitly says that
The return type is incompatible with LinkedList<T>.add(T)
and suggests to change the return type to boolean which I don't want to do. The #Override above the add(T thing) method in SomeQueue doesn't seem to be working.
This error is appearing because the extending/implementing class has two methods with the same name and argument types (signature), and different return types. In this case the compiler is complaining specifically about the add(T) method.
Your LinkedStack class is probably extending LinkedList, and therefore its boolean add(T) method. The void add(T) method inherited from SomeList and overriden in SomeQueue is incompatible with the one in LinkedList, because they have different return types (and the same name and arguments).
Putting it shortly, When you called SomeQueue.add(T), the compiler wouldn't know if you want to call the method that returns a boolean or the one that returns an int.
In other words, when you define void add(T t), the #Override doesn't match LinkedList.add(T) (which returns a boolean), and if you made it return a boolean the #Override wouldn't match SomeList.add(T), which must return void.
As a side note, by just having a class implement SomeList and extend LinkedList, without defining an add method:
public abstract class SomeQueue<T>
extends LinkedStack<T>
implements SomeList<T>{ /* Empty class definition */ }
, the compiler should already give an error along the lines of the following
The return types are incompatible for the inherited methods LinkedStack.add(E), LinkedList.add(E)
You should really consider if you need that add method as is in the SomeList interface (you could also change its name), and if you really need it to be as is now, then detach your class from the whole Collection hierarchy.
Related question: Can two Java methods have same name with different return types?

Method with typed list and inheritance

I have some troubles with a method having a typed List parameter, inherited from another (typed) class.
Let's keep it simple :
public class B<T> {
public void test(List<Integer> i) {
}
}
The B class has a useless generic T, and test() want an Integer List.
Now if I do :
public class A extends B {
// don't compile
#Override
public void test(List<Integer> i) {
}
}
I get a "The method test(List) of type A must override or implement a supertype method" error, that should not happen.
But removing the type of the list works... although it doesn't depend on the class generic.
public class A extends B {
// compile
#Override
public void test(List i) {
And also defining the useless generic below to use the typed list
public class A extends B<String> {
// compile
#Override
public void test(List<Integer> i) {
So I'm clueless, the generic of B should have no influence on the type of the test() list. Does anyone have an idea of what's happening?
Thanks
You're extending the raw type of B, not the generic one. The raw one effectively does not have a test(List<Integer> i) method, but a test(List) method.
If you switch to raw types, all generics are replaced by raws, regardless of whether their type was filled in or not.
To do it properly, do
public class A<T> extends B<T>
This will use the generic type B<T>, which includes the method you want to override.
When you remove use a class without generics (and use it raw), all generics from class methods are forgotten.
Due this reason when you inform the generic type on the second case you get it working.
This:
class T<G> {
public void test(G g);
}
in this case:
class A extends T {
}
will look like this:
class T {
public void test(Object g);
}
This was a java puzzle presented on Google IO 2011 you can see video here

java constructor in super classes

The following code is a testing program. Why i can't use A(int a), in this program?
public class A {
int a;
void meth(int b) {
a+=b;
}
A(int a) {
this.a=a;
}
}
class B extends A {
int a;
void meh2(int b) {
a+=b;
}
}
why can't pass parameter to constructor? What the reasons? Netbeans error message:
constructor A in class tma1.A cannot be applied to given types;
required: int
found: no arguments
reason: actual and formal argument lists differ in length
In the class B, you need constructor. If you mean that you can't call A from B, that's just because you're extending class A, so you need to use super, which refer to the superclass. For example B could be:
class B extends A {
B(int a) {
//You can put additional code here
// This calls the constructor of A
super(a);
//You can put additional code here
}
int a;
void meh2(int b) {
a+=b;
}
}
Otherwise you need to assign something to the variable a in class B, if you're not omitting something in code
Unless a class has a defined constructor, it automatically has a no-arg constructor that merely calls super().
The complaint from your compiler seems to be: "your no-arg constructor [that you can't see] is calling up to a parent no-arg constructor that doesn't exist."
Class A doesn't have a no-arg constructor because there's another one defined (so java doesn't have to create one).

Categories