First time implementing a java interface, can't get a successful compile - java

I need to implement a bag data structure using the interface java.util.Collection.
I'm not asking for help on the actual implementation of the data structure. I just can't get my program to compile. I just want to get a blank implementation of the interface (with non functional signatures of the methods) to compile before I start actually implementing methods.
class Bag<T> implements java.util.Collection<T>
{
public void Collection () {
}
public boolean add(E e) {
}
public boolean addAll (Collection<? extends E> c) {
}
public void clear() {
}
public boolean contains(Object o) {
}
public boolean containsAll(Collection<?> c) {
}
public boolean equals(Object o) {
}
public int hashCode() {
}
public boolean isEmpty() {
}
public Interator<E> interator() {
}
public boolean remove(Object o) {
}
public boolean removeAll(Collection<?> c) {
}
public int size() {
}
public Object[] toArray() {
}
public <T> T[] toArray(T[] a) {
}
}
Compiler can't find class E in the parameters of methods like add. Am I supposed to define a class for E, or is there something I'm not understanding about what E actually is? Compiler says it can't find class Collection (in the parameters of methods like addAll) Do I import java.util.Collection or is there something else I should know? Compiler also has no idea about class Iterator and neither do I.
I know this is all probably elementary, but I could not find anything via Google, etc yesterday and my professor's lectures don't follow the projects at all. I'm lost on this one. Thanks for any help!
Edit: Also, I haven't searched as much on this but if someone could tell me anything useful about the "?"s such as public boolean addAll (Collection<? extends E> c) {}, that would be greatly appreciated.

Either use T or E as the type parameter, and then use it consistently throughout your class definition.
The Java documentation uses E, so you could for example change the first line to:
class Bag<E> implements java.util.Collection<E>
You will also need to either return values or throw an exception for those methods that don't return void.
public int size() {
throw UnsupportedOperationException();
}

E should be T, which is the generic type you are going to store. Your constructor should be for your class not the interface. Also you will need to add at least stubbed returns in your methods that have a return value, e.g. "return false" if the return is a boolean.
Hope this helps.

Try changing the import statement to import java.util.*;

Because you don't have E declared , use T instead and also you need to return wherever it is declared to return.

You are gonna have to do a lot of basic learning before you can implement an interface in JAVA. May be read "thinking in java" or something
In you program there are multiple problems
import of the Collection class is missing
no return statements are there in any of the methods
replace the E with T

Your generic parameter is called T and you're using E in your methods' implementations. If you go with T as the element type, update the method signatures.
It probably still won't compile without at least dummy implementations such as return null; or return false; in non-void methods.
The java.util.Iterator is an interface that describes a set of methods which allow you to iterate over the elements in your collection. You would return an instance of a class that implements that interface and its methods. YourListIterator will probably keep a reference or index to where in the list you are, return the corresponding element and move forward through the list.
Generics (including the use of ?) are discussed in this tutorial.

Related

How can i make an interface in java with a function that accepts a parameter of the type that extends the interface?

How can i make an interface in java with a function that accepts a parameter of the type that extends the interface?
For example take the interface ISelfComparable
if class A extends it then i would expect it to implement
bool compareTo(A other)
but if class B extends it then i would expect it to implement
bool compareTo(B other)
I know i can use a generic interface but it seems incorrect because it doesn't make any sense for A to extend ISelfComparable<B>
If this is impossible, what is the best practice in this kind of situation?
The usual solution is self-bounded generics, as seen in the Enum class.
interface Example<T extends Example<T>> {
void foo(T t);
}
public class ExampleImpl implements Example<ExampleImpl> {
#Override
public void foo(ExampleImpl example) {
}
}
How it works is a bit dizzying, but is explained very well here for example. There is also a very good answer on the subject here.
Note that it isn't foolproof, as it allows this:
public class ExampleImpl2 extends Example<ExampleImpl {
#Override
public void foo(ExampleImpl example) {
}
}
But in practice the self-bounded idiom is used to express exactly the sort of thing you're after.
If you really, really, really need the parameter object to always be the exact same class as this, you have to do a runtime check. (It also raises the question of why you need this, but that would take us way off topic.)
Have a look at the class java.lang.Comparable: it has an argument with the type of the objects that can be used int compareTo.
By analogy:
public interface ISelfComparable<T extends ISelfComparable<T>> {
boolean compareTo(T other);
}
There is a way to check the type of parameter but only in runtime. For example you can implement type checking in default method:
interface ISelfComparable {
default boolean compareTo(ISelfComparable param) {
if (this.getClass() != param.getClass()) {
throw new IllegalArgumentException();
}
...
}
}
Then each implementation of this interface should look like this:
class A implements ISelfComparable {
#Override
public boolean compareTo(ISelfComparable param) {
ISelfComparable.super.compareTo(param);
...
}
}
In this case if you call new A().compareTo(new B()); then java.lang.IllegalArgumentException will be thrown

Generic type on remove method of collection in Java

For some weird reason, I want to implement a Collection from Java Util and with a generic type of everything, includes remove and contains, which for backward compatibilities reasons, they didn't do it at all, so I want to try myself. Here is what the code I want to look like:
public class MyTest<E> implements Collection<E>{
#Override
public <T> boolean remove(T t){
return true;
}
#Override
public <T> boolean contains(T t){
return true;
}
}
As my research going on, I understand that this code eventually going to have the erasure like remove(Object) of type Collection<E>
but java simply seems like not accepting it instead but keep asking to override the method with Object as argument. So I'm asking if anyone knows anyway to work around it or directly with this
You cannot have this implementation of Collection as in Java the arguments cannot use covariance or be redefined and Collection defines these two methods like that :
boolean remove(Object o);
boolean contains(Object o);
If you want to implement the Collection interface, you should implement these method as these are specified :
public class MyTest<E> implements Collection<E>{
...
#Override
public boolean remove(Object o){
. . .
}
#Override
public boolean contains(Object o){
. . .
}
...
}

Error in adding generic collection sort method

I am trying to call Collections.sort(c); but I am getting an error:
The method sort(List<T>) in the type Collections is not applicable
for the arguments (Collection<capture#1-of ? extends E>)
Here is my code:
import java.lang.*;
public class SortedLinkedList<E extends Comparable<E>> extends LinkedList<E> {
LinkedList<Object> list = new LinkedList();
SortedLinkedList()
{
}
SortedLinkedList(Collection<? extends E> c)
{
//return sorted linked list of c
Collections.sort(c);
}
public int compareTo(Collection<? extends E> c) {
// TODO Auto-generated method stub
return 0;
}
}
I've declared the class with the generic type extending comparable interface.
But this still wouldn't help the error. I followed the post that was mentioned when this was marked duplicate but it couldn't help much. This is my first attempt to learn generics in java. Any help is much appreciated.
-Thanks!
The type <E extends Comparable<E>> is fine, but there are several other problems:
c is a Collection, but you can't sort a Collection unless that Collection is a List, because only Lists allow the arranging and rearranging of elements in specific orders. Other types of Collection, such as a Set or bag, do not. You could typecast c to List, but still it would be the wrong object to sort. It looks like you want to put the contents of c into your linked list and then sort that:
SortedLinkedList(Collection<? extends E> c)
{
list.addAll(c);
Collections.sort(list);
}
The list is declared LinkedList<Object> but should be LinkedList<E>, (or maybe List<E>), so that it is declared to contain sortable objects.
The assignment of new LinkedList(); should be new LinkedList<E>() , which can be shortened to new LinkedList<>().
That's enough changes to make the code compile, but let's delve deeper. I infer that what you're trying to do here is create a generic container collection that is a linked list with an invariant that its elements are always maintained in sorted order. In that case, some changes you'll want to make are:
The list variable should be private to prevent other classes futzing about with it. If you do not want to re-assign the variable after initialization it would also be nice to make it final, which protects against accidental re-assignment and clarifies that that is how you're using it.
The constructors should be public to allow access from other packages.
I'm not sure what you intend the compareTo method there for. (How do you define a comparison of one entire collection against another?) Possibly it should be removed.
Currently you're both encapsulating and extending LinkedList, which doesn't make sense. Each instance of your class has two LinkedLists, one in the list variable, and one inherited from the parent. You need to decide on one or the other.
If you want to extend LinkedList then you can get rid of the list variable entirely and call the superclass methods instead. E.g.:
public SortedLinkedList(Collection<? extends E> c)
{
super.addAll(c);
Collections.sort(this);
}
In this case you will need to override any mutative methods of the parent class to make sure that none of them can be used to subvert the invariant that your class maintains its elements in sorted order. E.g., override add(E element) and make it insert the new element in the correct place. Whereas add(int position, E element) should be overridden to throw an UnsupportedOperationException since inserting an element at a specified index position doesn't make sense, because an element's position in a sorted list is already implied by its value.
A disadvantage of extending LinkedList is that is possible for new mutative methods to be added to the LinkedList class in future, which could then allow users to subvert your collection's invariant.
If you want to encapsulate a LinkedList with your list variable, then you should delete extends LinkedList<E> and instead have implements List<E>.
In this case you will need to provide an implementation for all the methods of the interface, but you can instantly implement most of them correctly by extending one of the abstract skeletal classes that the Java Collections Framework provides, such as AbstractSequentialList.
Third possibility: neither extend nor encapsulate LinkedList but write a linked list from scratch.
The line import java.lang.*; is unnecessary. Everything in the java.lang package is imported by default.
The following is an example based on the above fixes:
import java.util.*;
public class SortedLinkedList<E extends Comparable<E>>
extends AbstractSequentialList<E> implements List<E> {
private final LinkedList<E> list = new LinkedList<>();
public SortedLinkedList() {}
public SortedLinkedList(Collection<? extends E> c)
{
list.addAll(c);
Collections.sort(list);
}
#Override
public boolean add(E element) {
list.add(element);
Collections.sort(list);
return true;
}
#Override
public ListIterator<E> listIterator(int index) {
// Rather than returning list.listIterator(index) directly, we
// encapsulate it to block the add and set methods:
return new ListIterator<E>() {
private final ListIterator<E> base = list.listIterator(index);
#Override
public boolean hasNext() {
return base.hasNext();
}
#Override
public E next() {
return base.next();
}
#Override
public boolean hasPrevious() {
return base.hasPrevious();
}
#Override
public E previous() {
return base.previous();
}
#Override
public int nextIndex() {
return base.nextIndex();
}
#Override
public int previousIndex() {
return base.previousIndex();
}
#Override
public void remove() {
base.remove();
}
#Override
public void set(E e) {
// prevent unsorting the list
throw new UnsupportedOperationException();
}
#Override
public void add(E e) {
// prevent unsorting the list
throw new UnsupportedOperationException();
}
};
}
#Override
public int size() {
return list.size();
}
}
The bulk of the List methods get implemented with no effort thanks the magical superclass AbstractSequentialList and its superclasses. However if you check the source you'll find things you can improve if you override those methods because the inherited implementations are designed principally to minimize effort in extending the class. E.g. to clear the list it iterates each element and carefully removes them one at a time (via ListIterator.remove()), whereas deferring to the LinkedList's clear() method would be faster.
Also, instead of re-sorting the entire list after adding an element, it would be much more efficient to insert it directly in the correct place. You can do this via ListIterator.add, but I'll leave that to you :)
Another nice feature would be to allow your class to be constructed with a custom Comparator to be used for sorting elements. This would allow use of element types that do not implement Comparable, as well as the ability to override the default ordering (e.g., users of the class could supply a Comparator for case-insensitive ordering of Strings). TreeMap is an example of a class that supports this sort of feature.
I hope the example is helpful for showing the concepts, anyway.

Overriding a method using type erasure

Today I stumbled upon something interesting.
Assume the following Java 6 class:
public class Ereasure {
public Object get(Object o) {
return null; // dummy
}
public static class Derived<T> extends Ereasure{
// (1)
#Override
public Object get(T o) {
return super.get(o);
}
// (2)
/*
#Override
public Object get(Object o) {
return super.get(o);
}*/
}
}
If you try to compile the above example, the compiler says
Ereasure.java:9: method does not override or implement a method from a supertype
#Override
If you remove the #Override annotation(which should not be necessary!), it says
Ereasure.java:8: name clash: get(T) in Ereasure.Derived and get(java.lang.Object) in Ereasure have the same erasure, yet neither overrides the other
This is a bit contradictional, since T should erease to Object and therefor override the parent classes get method.
If you leave (1) unannotated and uncomment (2) so (1) overloads (2) it would not work either.
Compiler output:
Ereasure.java:15: get(T) is already defined in Ereasure.Derived
public Object get(Object o) {
As a conclusion, T is being ereased to Object, but cannot override the parent get Method.
My question is now, why dooesn't at least one of the examples compile?
You can see in the example below why it is impossible to do what you want:
public class Erasure {
public void set(Object o) {
return;
}
// method overloading: (which is valid)
public void set(String s) {
return;
}
public static class Derived<S> extends Erasure {
// Oops... which one am I supposed to override?
// (It would actually be overloading if S was a concrete type
// that is neither Object nor String.)
#Override
public void set(S o) { // does not compile
super.set(o);
}
}
}
The solution to your problem is that Erasure should be a parameterized class.
At a simple guess the compiler does not use the generic view when calculating overloads which of course would not make sense, because sometimes T might be Object other times its another type. The overridding would then become dependent on a moving target T which is downright wrong, especially if there were multiple methods all called "get" but with different single parameter types. In such a case it just wouldnt make sense and at a guess they chose to just keep things simple.
Consider a case where you have both a getter and a setter overridden as generics.
Derived<String> d = new Derived<String();
Erasure e = d;
e.set(new Object());
String s = d.get(); //Class cast exception
The fundamental principal of generics is that a class cast exception can only happen if there is either (a) an explicit cast or (b) a warning. If you were allowed to do what you wanted, the above would throw an exception without either.

Problem overriding ArrayList add method

I have a class that is extending Java's ArrayList. I'm currently using Java build 1.6.0_22-b04. Looks like this:
public class TokenSequence extends ArrayList<Token>{
public TokenSequence (Collection<Token> tokens) {
super(tokens);
}
public void add(Object o) {
if (o instanceof Token){
add( (Token)o );
}
else if (o instanceof TokenSequence)
add( (TokenSequence)o );
else
add( new Token( o.toString() ) );
}
}
My problem in the above code is the add(Object o) method. Java won't let me compile the code because it says
"Name clash: The method add(Object) of type TokenSequence has the same erasure as add(E) of type ArrayList<E> but does not override it"
This same code works with no problems in another computer under Java build 1.6.0_17-b04.
Anyone has any idea on a quick fix?
Try adding the #Override annotation to your add() method and make sure to have the same signature (boolean return type)
public class TokenSequence extends ArrayList<Object> {
#Override
public boolean add(Object e) {
return super.add(e);
}
}
Or if you want it to be void, take another method param.
cheers
Change it to public boolean add(Token o). (Note return and parameter type)
In order to override a method, your override must have the exact same signature, including the return type.
Since your method has a different return type, it doesn't actually override the base add method.
The reason that it won't even compile is that because it doesn't override the base method, you end up with two different add methods, both of which are callable by your derived class.
However, due to type erasure, they both actually take an Object parameter, which is illegal.
Absolutely - use the #Override annotation, and ideally use the strongly typed signature:
#Override
public void add(Token token) {
...
}
The error message already provided a large hint here.
I haven't tried it, but I believe the correct implementation would be:
public void add(Token o) {
}
because Token is the E in your extends statement.
You need to do:
public boolean add(Token o) {
}
Because ArrayList is a generic.
First of all, in the current implementation it will go to infinite recursion when you will try to call add function with instance of TokenSequence. Did you mean to call "addAll" in that case?
Second, forget about
void add(Object)
in you case you need to add 2 methods (make them return boolean, if you want to be consistent):
public void add(String o) {
add(new Token(o.toString()));
}
public void add(TokenSequence t){
addAll(t);
}
and the add(Token) is already implemented by ArrayList
on the other hand, if you want a single method, you can declare, for example:
public void add(Serializable t)
this method will be called for both TokenSequence and String.
unfortunately to make the same method executed for Token (as oppose to the one provided by ArrayList), you will need:
make sure Token implements Serializable
cast Token to serializable
i.e:
add((Serializable)new Token())
create a custom ArrayList class and override the add the method as follows
public class CustomArrayList<E> extends ArrayList<E>{
#Override
public boolean add(E e) {
String temp = (String)e;
if(temp==null || temp.isEmpty()){
return false;
}
return super.add(e);
}
}
with this class, following example will add only 1 element and print size as 1
public static void main(String args[]) {
ArrayList<String> lst = new CustomArrayList<String>();
lst.add("aaaa");
lst.add(null);
lst.add("");
System.out.println(lst.size());
}

Categories

Resources