Mon programme a donc besoin d’un type de ArrayList circulaire.
La seule chose circulaire à ce sujet doit être la méthode get (int index), c'est l'original:
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
Si index est -1, il doit obtenir l'élément d'index ArrayList.size () - 1 et si index est ArrayList.size (), il doit obtenir l'élément d'indice 0.
Le moyen le plus simple d’atteindre cet objectif, qui m’est venu à l’esprit, consiste simplement à étendre ArrayList à partir du package Java.util et à redéfinir simplement get (int index) afin qu’il ne lève pas IndexOutOfBoundsException pour les deux index ci-dessus, mais les remplace par ce que je veux. Il déclencherait IndexOutOfBoundsException pour tout autre index hors limites.
Cependant, depuis elementData (index) access a
private transient Object[] elementData;
Je ne peux pas le faire fonctionner, parce que ma classe ne le voit pas car c'est privé.
De plus, je ne veux pas utiliser de bibliothèques externes pour cela, simplement parce que je pense qu’aucune ne correspond à mes besoins, car je ne veux pas d’un vrai circularArray, mais seulement une partie de ses fonctionnalités, le reste étant de la liste de tableaux normale.
J'ai donc deux questions:
Comment puis-je faire ce travail? Y a-t-il un moyen de le faire sans copier toute la classe ArrayList avec AbstractCollection, Collection et Iterable dans mon programme? Cela semble être une mauvaise conception même pour moi.
Si je peux le faire fonctionner, y at-il autre chose que je devrais surveiller? Si j'apporte les modifications décrites ci-dessus, cela changerait-il le comportement de la classe uniquement comme je le souhaite, ou pourrait-il y avoir d'autres changements de comportement indésirables?
EDIT: .__ Merci pour la réponse, voici ce que j'ai fait:
import Java.util.ArrayList;
public class CircularArrayList<E> extends ArrayList<E>
{
private static final long serialVersionUID = 1L;
public E get(int index)
{
if (index == -1)
{
index = size()-1;
}
else if (index == size())
{
index = 0;
}
return super.get(index);
}
}
Il s’enroulera autour de ArrayList, mais par un seul. Je veux qu'il jette une exception si j'essaie d'accéder à tout autre élément que le premier et le dernier avec quoi que ce soit sauf leurs index ArrayList habituels.
Ne pouvez-vous pas dériver de ArrayList et substituer la méthode get (int index) le long de ces lignes:
@Override
public E get(int index)
{
if(index < 0)
index = index + size();
return super.get(index);
}
Qu'est-ce que je rate?
Notez que cette implémentation ne plierait pas des index arbitraires dans votre plage d'index valide, mais vous permettrait seulement d'adresser correctement votre liste des côtés gauche et droit (avec des index positifs et négatifs respectivement, un peu comme en Python).
Vous pouvez étendre la classe ArrayList pour modifier les fonctionnalités de la méthode get
sans avoir à accéder au champ elementData
:
public class CircularList<E> extends ArrayList<E> {
@Override
public E get(int index) {
return super.get(index % size());
}
}
La méthode super.get
effectuera toujours les vérifications de plage (mais celles-ci n'échoueront jamais).
Vous devez savoir que cela peut donner aux index instables ArrayList. Si la taille de la liste change, tous les index en dehors de la plage normale changeront. Par exemple, si vous avez une liste ['a','b','c','d','e']
, alors get(7)
renverra c
. Si vous faites ensuite add('f')
, alors get(7)
renverra soudainement b
, car get
fonctionnera désormais modulo 6 au lieu de modulo 5.
Ce que vous avez décrit consiste essentiellement à obtenir le module de l'index souhaité et à accéder à cet élément dans une liste.
Vous pouvez faire ce qui suit avec la composition sur l'héritage:
List<T>
, appelons-la ListWrapper maintenant wrapped
Pourquoi toutes ces conneries? Ceci est indépendant de la mise en œuvre. Un jour, vous voudrez peut-être utiliser cette commodité pour une autre implémentation. Ensuite, vous devrez dupliquer le code, et l'enfer commence. Si vous avez également besoin d'une 3ème implémentation et que vous ajoutez ensuite une toute nouvelle fonctionnalité, vous êtes condamné.
Avec une classe wrapper entre:
N'oubliez pas que nous écrivons des programmes qui devront être maintenables!
Classe d'emballage
public abstract class ListWrapper<T> implements List<T> {
protected final List<T> wrapped;
public ListWrapper(List<T> wrapped) {
this.wrapped = wrapped;
}
public T get(int index) {
return wrapped.get(index);
}
//omitting the other wrapper methods, for sake of brevity.
//Note: you still have to add them.
// Eclipse: Source menu, Generate Delegate methods does the trick nicely
}
Maintenant la vraie nouvelle classe
public class ModList<T> extends ListWrapper<T> {
public ModList(List<T> list) {
super(list);
}
@Override
public T get(int index) {
int listSize = wrapped.size();
int indexToGet = index % listSize;
//this might happen to be negative
indexToGet = (indexToGet < 0) ? indexToGet+listSize : indexToGet;
return wrapped.get(indexToGet);
}
}
IL FAUT SE M&EACUTE;FIER
La réponse choisie ne gère pas le cas où l’indice est un nombre négatif avec une très grande magnitude et la taille de la liste est petite, c.-à-d.
Taille => 10 Index => -1000000
Voici une implémentation qui devrait gérer toutes les tailles et tous les index
import Java.util.ArrayList;
import Java.util.Collection;
/**
* A list the loops round to the first element when {@link CircularList#get(int)} is called with an
* index that is greater than the max index of the list and vice versa.
*
* @author Stuart Clark
*/
public class CircularList<E> extends ArrayList<E> {
public CircularList() {
super();
}
public CircularList(int initialCapacity) {
super(initialCapacity);
}
public CircularList(Collection<? extends E> c) {
super(c);
}
@Override
public E get(int index) {
if (isEmpty()) {
throw new IndexOutOfBoundsException("The list is empty");
}
while (index < 0) {
index = size() + index;
}
return super.get(index % size());
}
}
Est-ce que quelqu'un connaît cette extension AbstractList: com.Sun.appserv.management.util.misc.CircularList<T>
. Jetez un coup d'oeil. C'est la solution de communauté GlassFish Java.net. Il devrait être puissant, car il est utilisé dans la planification des threads dans le conteneur GlassFish.