How do I properly extend this abstract class? - java

Hi I'm inexperience with Java. I understand the concepts of inheritance but I think the syntax is eluding me. I'm seeking some help to get me started in extending this abstract class:
I need to create a concrete object from it.
What this class should do is take in a type during initialization and store a list of objects of that type. Sort them and then return a list of n top objects when showTopN is called.
I have not started implementing the logic yet.
abstract class Foo<T extends Comparable<T>> {
int n;
Foo(int n){ // constructor; sets object property n
this.n = n;
}
abstract void push(T object); //object method to store a new object in the list
abstract List<T> showTopN(); // object method to return top n entries in the list, sorted.
}
I've tried to extend this into a concrete object this way:
class ConcreteFoo extends Foo {
private List<Foo> fooList;
public void push(Foo object) {
}
#Override
public List<Foo> showTopN() {
return fooList;
}
#Override
public int compareTo(ConcreteFoo other) {
return 0;
}
}
But the compiler is complaining that I have not overridden the push method.
What is wrong?

There are two things going on here. One is the "abstractness" of Foo, but the other is the Generics. You have neglected the generics aspect.
If you know the type of object that your Concrete foo cares about, you can just use that:
class ConcreteFoo extends Foo<SomeKnownClass> {
private List<SomeKnownClass> list = new ArrayList<SomeKnownClass>();
void push(SomeKnownClass skc) {}
List<SomeKnownClass> showTopN() { return list; }
}
Now, if you don't know the type of it, you can still use generics:
class ConcreteFoo<T extends Comparable<T>> extends Foo<T> {
private List<T> list = new ArrayList<T>();
void push(T skc) {}
List<T> showTopN() { return list; }
}
Note that neither Foo nor ConcreteFoo implement Comparable, so you don't need the compareTo method.

The push method specifies that it will accept a T object, which is Foo's generic type, which you haven't declared. If you want Foo to be a List of itself, which I'm not certain that you do, you'd have to declare it as
class ConcreteFoo extends Foo<Foo> {
But I think you need to re-examine your basic principles.

You're conflating a container with the objects that it contains. The class structure that you want is something like:
class Foo implements Comparable<Foo> { ... }
abstract class GenericContainer<T> {
abstract void push(T object); //object method to store a new object in the list
abstract List<T> showTopN(); // object method to return top k entries in the list, sorted.
}
class FooContainer extends GenericContainer<Foo> {
private List<Foo> fooList;
...
}
Your showTopN method can then be something like:
public List<Foo> showTopN() {
return Collections.sort(fooList).subList(0, n);
}

Related

Using self-referential generic types in Java

Consider the following Java method:
<T extends List<T>> List<T> getMyList() {
return Collections.emptyList();
}
I can assign its output to a variable with a raw type, like so:
List x = getMyList();
List<List> y = getMyList();
But, I can't think of any way to assign its output to a fully parameterized type. In particular, I can't think of a non-raw, concrete type T that would satisfy List<T> z = getMyList();
Can we create such a T ?
If not, why not?
For context, I created this question while trying to understand how Enums are implemented in Java.
Here's an example of a concrete type that both works and starts to hint at a possible use-case (registration of some sort). The type consists acts like both an instance of some type, and as a container for all instances of that type.
public class WeirdEnum extends AbstractList<WeirdEnum> {
private static List<WeirdEnum> underlyingList = new ArrayList<>();
#Override
public WeirdEnum get(int index) { return underlyingList.get(index); }
#Override
public int size() { return underlyingList.size(); }
static <T extends List<T>> List<T> getAList() {
return Collections.emptyList();
}
public WeirdEnum() {
underlyingList.add(this); // Sufficient for our example but not a good idea due to concurrency concerns.
}
static List<WeirdEnum> foo = WeirdEnum.getAList();
}
Not sure if I fully understand your question, but here's an example:
class Example<T> implements List<Example<T>> {
...
}
...
List<Example<String>> list = getMyList();
Every enum in Java extends from the base-enum-class Enum<T extends Enum<T>>, where T is the actual type of the implementing enum.
When writing SomeClass<T extends SomeClass<T>> you can enforce that the type-parameter is always the implementing class itself.
Let's say you have this interface:
public interface MyInterface<T extends MyInterface<T>> {
T getSelf();
}
And this implementing class:
public class MyClass implements MyInterface<MyClass> {
public MyClass getSelf() {
return this;
}
}
In MyClass it is not possible to use any other type-parameter than MyClass itself.

Java: Specifying generic type restrictions in a subtype

I have a question regarding generic types in Java. Specifically, at present, I have some code similar to this:
public interface Foo {
public <T> void bar(T[] list)
}
public class FooImpl implements Foo{
#Override
public <T extends Comparable<? super T>> void bar(T[] list) {
...
}
}
The problem is, that the compiler now complaints, that I have not implemented the bar-method in my FooImpl class.
What I want is to put some extra restriction on the generic type, specifically that they should be comparable. But I don't want to put that restriction in my Foo interface, as all implementations does not need that restriction.
Is this possible, and what should I do to fix it?
Thanks a lot in advance!
EDIT 1: Fixed typos Class --> class and Interface --> interface. But the return types are still void, not T, which is irrelevant, I suppose. My actual return type is a boolean.
EDIT 2: The actual code, as requested:
public interface SortedCriteria {
public <E> boolean isSorted(E[] list);
}
public class AscendingCriteria implements SortedCriteria {
#Override
public <E extends Comparable<? super E>> boolean isSorted(E[] list) {
int length = list.length;
for (int i = 1; i < length; i++) {
if (list[i].compareTo(list[i-1]) < 0) return false;
}
return true;
}
}
What you want to do is rejected because it would completely break polymorphism. A caller having a Foo instance could have an instance of your subclass or an instance of any other subclass. And since the interface guarantees that the method can be called with any kind of array as argument, your subclass can't break this contract by limiting the kind of array it accepts (unless it does that at runtime, by checking the type of the array and by throwing an exception, of course).
This boils down to the Liskov substitution principle, which is the basis of polymorphism and OO.
But maybe what you actually want is to make Foo a generic type:
public interface Foo<T> {
public void bar(T[] list);
}
public class FooImpl<T extends Comparable<? super T>> implements Foo<T> {
#Override
public void bar(T[] list) {
...
}
}

Setting Java generics of iterators

I've noticed something funny Java does (or at least Netbeans) when I use classes implementing ArrayList and changing the generics type of the elements. I basically created an abstract class that extends ArrayList and some subclasses that are supposed to work with String objects (so something like ArrayList<String>). One of the things I did to try to achieve that was this:
public abstract class A extends ArrayList {
...
}
#Override
public abstract class B extends A {
public Iterator<String> iterator() {
return super.iterator();
}
}
Another one was this:
public abstract class A extends ArrayList {
...
}
public abstract class B<String> extends A {
#Override
public Iterator<String> iterator() {
return super.iterator();
}
}
The first one overrides successfully the iterator() method assigning a String value to it. The other one somehow cancels out the type casting. The funny thing is that none of them works when it comes to for loops. This receives type Object instead of String.
for (String s : B) {
...
}
Do you have any idea why this happens and how can I fix it without implementing my own iterator?
Not sure what you are trying to do but if I understand correctly you want a class that extends ArrayList and has a Generic type of String... Perhaps you are looking for this:
public abstract class A<T> extends ArrayList<T> {
...
}
public abstract class B extends A<String> {
...
}
Then in your code, this:
B myList = ...;
for ( String s : myList ) {
...
}
Will work just fine. Though I think you could come up with a much better solution. Do you have more specifics about your problem?
Use composition instead of Inheritance
public class A implements Iterable<String>{
List<String> myList = new ArrayList<String>();
//do operations on myList
public Iterator<String> iterator() {
return myList.iterator();
}
}
If you extend generic class you should care about generics. I mean that your declaration should look like
public abstract class A extends ArrayList<String> {
...
}
if you want to use strings or
public abstract class <T> A extends ArrayList<T> {
...
}
if you want your class to be generic.
In both cases you do not have to override iterator() method: you can invoke its from super class and it will return you "good" iterator. Your declaration is equivalent to
public abstract class A extends ArrayList<Object> {
...
}
This is the reason for "strange" behavior.
BTW may I ask you why are you extending ArrayList? It really sounds strange.
OMG this is terrible:
public abstract class B<String> extends A {
#Override
public Iterator<String> iterator() {
return super.iterator();
}
}
String is not the class String, rather, you are declaring a new type variable called String (like T) that shadows the class String

Generic class implementing Iterable

I want to have a generic class that implements Iterable (let's call it ImplIterable) of type T that implements an Iterable interface over some class (that isn't of the generic class type); for example:
public class ImplIterable <T> implements Iterable<A> {
private A[] tab;
public Iterator<A> iterator() {
return new ImplIterator();
}
// doesn't work - but compiles correctly.
private class ImplIterator implements Iterator<A> {
public boolean hasNext() { return true; }
public A next() { return null; }
public void remove() {}
}
}
Where A is some class. Now, this code won't compile:
ImplIterable iable = new ImplIterable();
for (A a : iable) {
a.aStuff();
}
But this will:
Iterable<A> = new ImplIterable();
for (A a : iable) {
a.aStuff();
}
I don't understand why the latter doesn't compile and why can't I iterate over ImplIterable if it properly implements iterable. Am I doing something wrong/is there some workaround for this type of problems?
When you use a generic class without a generic parameter, all generics in that class are disabled.
Since ImplIterable is generic, and you're using it as a non-generic class, the generic parameters inside of it vanish, and it becomes an Iterable (non-generic) of Objects.

How would one go about dealing with generic enums in Java?

So, I have an abstract class like:
public abstract class AbstractParent <E extends Enum<E>> {...}
Somewhere in a non-abstract method inside AbstractParent, I would like to iterate over the values of E. Is this possible?
For a better example:
public abstract class AbstractParent <E extends Enum<E>> {
...
protected void doSomething() {
//iterate over the values of E and perform an action using them
}
}
public class Child extends AbstractParent<Child.Index> {
public static enum Index {
...
}
public Child() {
super();
this.doSomething(); //this should iterate over Index's values
}
}
EDIT:
So, thanks to mdma, this works awesomely:
public abstract class AbstractParent <E extends Enum<E>> {
...
protected void doSomething() {
//iterate over the values of E and perform an action using them
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
Type t = pt.getActualTypeArguments()[0];
E[] enumValues = ((Class<E>)t).getEnumConstants();
// enumValues is now an iterable array of the values inside Index
}
}
public class Child extends AbstractParent<Child.Index> {
public static enum Index {
...
}
public Child() {
super();
this.doSomething(); //this should iterate over Index's values
}
}
Thanks LOADS to mdma, you deserve more points than I can give.
EDIT2: Generics on superclasses and interfaces are not erased. You can get the generic type at runtime and use that to fetch the enum values. See Class.getGenericSuperclass. This will save you having to pass the value or a class in the constructor.
Original:
You cannot do this with generics. However, if you pass in the corresponding class also, e.g. a constructor like
AbstractParent(Class<E> enumClass)
{
this.enumClass = enumClass;
}
Then you can use that to fetch the corresponding enum values via
public E[] getValues()
{
return this.enumClass.getEnumConstants();
}
EDIT: Although the clients are not professional programmers, the compiler will ensure the correct class is passed. You can also make the usage clear by providing examples, and unit tests.
You could also have the constructor take and actual value of the Enum, and derive the class from that. This might be simpler to use, since the parameter is then an E rather than the more "scary" Class<E>.
E.g.
AbstractParent(E enumValue)
{
this.enumClass = enumValue.getClass();
}
Since generics are erased at runtime, the only way this is possible is by having a constructor that requires a Class<E> parameter on which you can then call getEnumConstants().

Categories

Resources