I'm trying to create a generic container which has a copy-constructor. I'm having trouble using the clone method even though I have coded it in. Here's what I have so far:
public class MyBox<T>
{
private List<T> list;
public MyBox()
{
list = new ArrayList<T>();
}
public void add(T item )
{
list.add(item);
}
public MyBox(MyBox<T> other) throws CloneNotSupportedException //this is giving me trouble
{
for(T item : other.list)
{
list.add((T) item.clone());
}
}
}
How can I get my copy-constructor to work?
Usually you don't need to clone the item.
public MyBox(MyBox<T> other)
{
list = new ArrayList<T>(other.list);
}
When you add an item from collection A to collection B, the item is now referenced by both two collection A and B.
How about restricting the generic to Clonable, then it's certain that the cloning of the items will be allowed:
public class MyBox<T extends Clonable> {
...
public MyBox(MyBox<T> other)
{
this.list = new ArrayList<T>(other.getList());
}
but you must add a getter for your list first in this case.
UPD. this makes shallow copy.
Unfortunately in Java, there is no generic way to clone an object. Some classes have a public clone() method, which allows you to clone, but there is no common superclass or interface with a public clone() method. (In fact, because there is no common interface; classes don't even have to call it clone(); they could name it copy() or something else.) You could use reflection to see if there is a public clone() method, but that might be overkill.
Related
I am new to generics. If I have already created a generic interface IList. But I want to create a method that only works on a list of Students(Student is also another class I created for that problem). Where should I put this method.
P.S. I tried to put this method inside IList class but that doesn't compile since the elements are T rather that Student.
What should I do?
It is not possible to make 'conditional' methods, as in, it is not possible to make a method which only exists for some of the types. A Foo<T> object doesn't change what methods it has based on the T.
You can create a subtype:
public class Foo<T> {
private List<T> elems = ...;
void bar();
}
public class StudentFoo extends Foo<Student> {
void baz() {
for (Student s : elems) {}
}
}
works fine. But that isn't going to magically give all Foo<Student> objects a baz method; you'd have to make them specifically as new StudentFoo(), not as new Foo<Student>().
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.
I'm trying to repair the following class so it will become immutable:
public class ImmutableList<E> implements Iterable<E> {
private List<E> internal;
public ImmutableList(List<E> l) {
this.internal = l;
}
public int size() {
return this.internal.size();
}
public E get(int i) {
return this.internal.get(i);
}
public Iterator<E> iterator() {
return this.internal.iterator();
}
}
but at the moment i'm not successful, my problem is that i don't know the type of E so i don't know how to deep copy it.
I wanted to know if it possible to make the class immutable?
thanks in advance
Your class is nearly "as immutable as possible." There's no fully general way to deal with arbitrary generic types, so you should just not worry about it.
Two remaining issues:
You need to copy l -- a shallow copy will suffice. this.internal = new ArrayList<E>(l) will do.
If internal.iterator() supports remove(), then consumers of your list type can remove elements.
Make your class final so it cannot be subclassed in a mutable way.
This is in java.
Alright so I am inheriting the abstract method getElementAt(int). I want to override this method so that it finds an element at a specified index within an ArrayList. Since I am not actually passing an ArrayList into the method, I don't know how to reference it.
someArrayList.getElementAt(int n);
How does it access someArrayList within the method?
As for what I'm inheriting from
public class ListEngine extends AbstractListModel
and I am overriding the class
getElementAt(int n)
Well AbstractListModel does not provide an implementation on how the items are stored, etc.
What you thus need to do is use/implement a List object (or perhaps some kind of Collection) and then "redirect" calls to it:
Example (with ArrayList):
public class ListEngine<T> extends AbstractListModel {
private final ArrayList<T> innerData = new ArrayList<T>();
public ListEngine () {
}
#Override
public T getElementAt(int index) {
return innerData.get(index);
}
#Override
public int size() {
return innerData.size();
}
}
Or you could use another List (like LinkedList<T>).
The above implementation is quite useless of course, since the initialized innerData is always empty. Furthermore if something is modified to the innerData, you need to call fireContentsChanged to notify the listereners (this is the responsibility of the inheriting class, doing not so can result in severe problems since some listeners may count on this).
In a class, I have a container:
public class MyClass implements MyClassInterface {
private LinkedList<OtherClass> list; //Need to use 'OtherClass' instead of 'OtherClassInterface here
#Override
public Iterator iterator() {
return list.iterator; //Problem!
}
}
The interface:
public interface MyClassInterface {
//Is
public Iterator iterator();
//Should be
public Iterator<OtherClassInterface>();
}
Then again, OtherClass also has an interface OtherClassInterface.
I want only the interfaces to be used by whom who works with the code.
The problem is that I want to use the full OtherClass inside MyClass but pass an iterator over LinkedList<OtherClassInterface> to the caller of MyClassInterface.iterator().
I could not cast the existing LinkedList<OtherClass> to LinkedList<OtherClassInterface> inside MyClass to return the desired iterator.
How to handle such a situation?
EDIT
Reason why I want this behaviour
For another developer, I want to provide two interfaces: The first gives him access to a higher data structure which contains a lower data structure which he should access by the second interface. In the implementing class of the higher interface I use the type of the lower data structure directly, not over the lower interface.
As mentioned, the other developer wants to use both interfaces. Over the higher one I want to provide an iterator that gives access to elements of the lower interface - but not to the class that implements the interface.
Additional needs
I also want the returned iterator to be "Iterable" i.e. so that I can use the "for each" construct. Is this also possible with *waxwing*s solution? If possible, I wouldn´t like to implement an own iterator - for me this seems not neccessary because I just want to give an iterator over elements of the interface instead of the implementing class.
You could write your own Iterator implementation that converts between the interface and the concrete implementation when returning from next()
The problem with converting List<OtherClass> to List<OtherClassInterface> is that there is no way to prevent the user of the conversion result to put something other than OtherClass objects into the list (of course those elements must implement the OtherClassInterface as well)
Can you define the interface like this?
public interface MyClassInterface {
public Iterator<? extends OtherClassInterface>();
}
list.iterator() should be a valid return value for that method, even when list is List<OtherClass>.
Can you change the interface?
public interface MyClassInterface<T> {
public Iterator<T> iterator();
}
You can always implement your own iterator :
public class MyClass implements MyClassInterface<T> {
private LinkedList<T> list;
#Override
public Iterator iterator() {
return new Iterator<T>() {
int index;
public boolean hasNext() {
return index < list.size();
}
public T next() {
return list.get(index++);
}
public void remove() {
}
};
}
}
didn't test the code
The interface can be defined like this:
public interface MyClassInterface {
public LinkedList<? extends OtherClassInterface> list();
}
Then the implementation should look like this:
#Override
public LinkedList<OtherClass> list() {
return list; //this is the container of type LinkedList<OtherClass>
}
This has the following advantages:
When calling list() by an OtherClass object you will get a LinkedList<OtherClass>
When calling list() by an OtherClassInterface object you will get a LinkedList<OtherClassInterface>
The return value of each can be used in the for-each loop
The iterator can be obtained by list().iterator()