Ordinare Arraylist di oggetti di interfaccia

di il
11 risposte

Ordinare Arraylist di oggetti di interfaccia

Salve a tutti,
premetto che sono alle prime armi con i Java, ho un problema che non riesco a risolvere. Ho cercato per varie ore sia su questo forum che su Google ma non ho trovato la risposta al mio quesito: nel mio esercizio sono presenti:

- un'interfaccia "Operazione", con metodi esegui e getRisultato
- una classe astratta Utility che ha: un attributo double val, i costruttori e il metodo astratto confronta(Operazione o) (questo metodo dovrà poi essere implementato in modo che restituisca -1, 0 o 1 a seconda che this.getRisultato()<=>o.getRisultato() )
- Quattro classi (Somma, Sottrazione, Moltiplicazione e Divisione) che implementano Operazione ed estendono Utility.

Nel main ho creato alcuni oggetti della 4 sottoclassi, poi l'esercizio chiede di inserirli in un'arraylist, ed io ho creato un'arraylist sull'interfaccia:

ArrayList<Operazione> lista = new ArrayList<Operazione>();

dopodiché ho aggiunto gli elementi alla lista (lista.add(e1);....).
Fin qui tutto funziona, ho visualizzato l'array in un ciclo di System.out.println(lista.get(i).getRisultato());


Il problema è che ora dovrei ordinare in senso crescente l'array usando ilo metodo confronta. Come si fa? Ho letto e riletto delle interfacce Comparable e Comparator, ma in questo caso l'array da ordinare è un'array costruito non su una classe ma su un'interfaccia. Se provo a scrivere
Collections.sort(lista); ho: "no suitable method found for Sort(ArrayList<Operazione>). Suppongo che sia perché l'override di compareTo non sia dentro l'interfaccia ma dentro le sottoclassi...

Non so se sono stato chiaro, mi rendo conto che la mia terminologia in Java è dello stesso livello della mia preparazione... ciò iniziale!

Grazie mille per l'attenzione e per eventuali suggerimenti.

11 Risposte

  • Re: Ordinare Arraylist di oggetti di interfaccia

    Posta il codice anche se non compila
  • Re: Ordinare Arraylist di oggetti di interfaccia

    NoCode ha scritto:


    - un'interfaccia "Operazione", con metodi esegui e getRisultato
    - una classe astratta Utility che ha: un attributo double val, i costruttori e il metodo astratto confronta(Operazione o) (questo metodo dovrà poi essere implementato in modo che restituisca -1, 0 o 1 a seconda che this.getRisultato()<=>o.getRisultato() )
    - Quattro classi (Somma, Sottrazione, Moltiplicazione e Divisione) che implementano Operazione ed estendono Utility.
    Questo sarebbe da chiarire meglio perché "potrebbe" essere discutibile.

    NoCode ha scritto:


    Ho letto e riletto delle interfacce Comparable e Comparator
    Già letto Comparazione e ordinamento degli oggetti in Java?

    NoCode ha scritto:


    ma in questo caso l'array da ordinare è un'array costruito non su una classe ma su un'interfaccia.
    Dal punto di vista del criterio di comparazione non cambia nulla. Ciò che compone questo criterio potrà arrivare solo da ciò che "vedi" di disponibile (in termini di metodi) nella interfaccia.

    NoCode ha scritto:


    Se provo a scrivere
    Collections.sort(lista); ho: "no suitable method found for Sort(ArrayList<Operazione>). Suppongo che sia perché l'override di compareTo non sia dentro l'interfaccia ma dentro le sottoclassi...
    Quel sort si basa sull'ordinamento "naturale" degli oggetti, ovvero su Comparable. Infatti la sua definizione è:

    public static <T extends Comparable<? super T>> void sort(List<T> list)

    Quindi T è vincolato a rappresentare genericamente un qualunque tipo che implementi Comparable. In pratica NON compila se passi una lista di un tipo che il compilatore deduce non appropriato perché non implementa Comparable.
  • Re: Ordinare Arraylist di oggetti di interfaccia

    Grazie mille.

    L'interfaccia Operazione:

    public interface Operazione{
    public void esegui(double val1, double val2);
    public void esegui(double val1, double val2, double val3);
    public double getRisultato();
    }


    L'interfaccia Utilita:


    public abstract class Utilita {
    private double val;
    Utilita()
    {
    this.val=0;
    }
    Utilita(double val)
    {
    this.val=val;
    }
    public abstract void stampa();
    public abstract int confronta(Operazione o);
    }




    La classe Somma (le altre operazioni sono analoghe):



    public class Somma extends Utilita implements Operazione, Comparable<Somma>{

    private double ris;

    public void esegui(double val1, double val2)
    {
    this.ris=val1+val2;
    }
    public void esegui(double val1, double val2, double val3)
    {
    this.ris=val1+val2+val3;
    }
    public double getRisultato()
    {
    return this.ris;
    }

    public void stampa()
    {
    System.out.println(this.ris);
    }
    public int confronta(Operazione o)
    {
    if(this.getRisultato()<o.getRisultato())
    return -1;
    else if(this.getRisultato()==o.getRisultato())
    return 0;
    else return 1;
    }
    @Override
    public int compareTo(Somma o)
    {
    if(this.getRisultato()<o.getRisultato())
    return -1;
    else if(this.getRisultato()==o.getRisultato())
    return 0;
    else return 1;
    }
    }





    E infine la classe con il main: (ultima riga commentata)

    public class EsOperazioni {

    public static void main(String[] args) {
    Somma s1 = new Somma();
    s1.esegui(5, 4);
    s1.stampa();
    System.out.println(s1.getRisultato());
    s1.esegui(3, 4, 5);
    s1.stampa();
    Somma s2 = new Somma();
    s2.esegui(6, 6);
    if(s1.confronta(s2)==-1)
    System.out.println("s1 < s2");
    else if(s1.confronta(s2)==0)
    System.out.println("s1 = s2");
    else
    System.out.println("s1 > s2");
    Sottrazione sot1 =new Sottrazione();
    sot1.esegui(8, 3);
    sot1.stampa();
    Sottrazione sot2 =new Sottrazione();
    sot2.esegui(8, 4);
    sot2.stampa();
    if(sot1.confronta(sot2)==-1)
    System.out.println("sot1 < sot2");
    else if(sot1.confronta(sot2)==0)
    System.out.println("sot1 = sot2");
    else
    System.out.println("sot1 > sot2");
    Moltiplicazione m1 = new Moltiplicazione();
    m1.esegui(3, 3);
    m1.stampa();
    Moltiplicazione m2 = new Moltiplicazione();
    m2.esegui(2, 4, 3);
    m2.stampa();
    Divisione d1 = new Divisione();
    d1.esegui(7, 2);
    d1.stampa();
    Divisione d2 = new Divisione();
    d2.esegui(12, 2, 2);
    d2.stampa();
    ArrayList<Operazione> lista = new ArrayList<Operazione>();
    lista.add(s1);
    lista.add(s2);
    lista.add(sot1);
    lista.add(sot1);
    lista.add(m1);
    lista.add(m2);
    lista.add(d1);
    lista.add(d2);
    System.out.println("Ciclo for sull'array: ");
    double S=0;
    for (int i = 0; i < lista.size(); i++)
    {
    lista.get(i).esegui(10, 50);
    System.out.println(lista.get(i).getRisultato());
    S=S+lista.get(i).getRisultato();
    }
    System.out.println("Somma degli elementi dell'array: "+S);
    //System.out.println("\nLISTA ORDINATA:");
    //Collections.sort(lista);
    }
    }



    Qualunque suggerimento sarà benvenuto!
  • Re: Ordinare Arraylist di oggetti di interfaccia

    Grazie anche ad andbin: sì, ho letto anche l'articolo che hai linkato, probabilmente il mio problema è proprio che no so usare bene ereditarietà (extends) e implementazioni di interfacce. Il fatto è che sono costretto (lo dice il testo dell'esercizio) ad usare quella struttura: interfaccia, classe astratta e sottoclassi che implementano una ed estendono l'altra. Io ho creato un'Arraylist con l'interfaccia perché mi sembrava l'unico modo per inserire oggetti istanziati su (sotto)classi diverse, sbaglio? Diciamo che l'importante sarebbe poter inserire gli oggetti in un'arraylist per poi ordinarla. Forse ho sbagliato proprio l'approccio (cioò fare un arraylist con l'interfaccia)?
  • Re: Ordinare Arraylist di oggetti di interfaccia

    NoCode ha scritto:


    L'interfaccia Operazione:
    Operazione tecnicamente è corretta. Il senso potrebbe essere dubbio/discutibile per due motivi:
    a) il esegui con 3 operandi è un po' strano/inconsueto. Per una divisione che vorrebbe dire??? (val1 ÷ val2) ÷ val3 ?? O che?
    b) l'uso di getRisultato() presuppone che prima sia stato invocato esegui. Detto in generale (volendo fare proprio i pignoli) chi garantirebbe che in una lista di operazioni tutte siano già state "eseguite" prima dell'ordinamento?

    NoCode ha scritto:


    L'interfaccia Utilita:
    Classe astratta, non interfaccia.

    Ma c'è una questione: quel val. Per COSA lo usi? Guarda BENE. Quel val NON è usato da nessuna parte!
    Quindi? Ripensa bene ...

    NoCode ha scritto:


    La classe Somma (le altre operazioni sono analoghe):
    La implementazione di Comparable<Somma> è di per sé corretta. Ma non ti è utile (probabilmente non era nemmeno richiesta dall'esercizio, vero?)

    Non è utile perché tu hai un List<Operazione> e il sort basilare si aspetta una lista di oggetti Comparable ma Operazione non è-un Comparable.

    L'unico modo per risolvere è implementare Comparator in una classe a sé stante. Oppure rendere Operazione una estensione di Comparable<Operazione> (cosa che però forse/probabilmente non è quanto voluto dall'esercizio).

    NoCode ha scritto:


    ho letto anche l'articolo che hai linkato
    Ti è stato utile? Avevo impiegato svariati giorni a scriverlo!
  • Re: Ordinare Arraylist di oggetti di interfaccia

    Grazie mille andbin, scusa ma nei due giorni scorsi non ho potuto connettermi.
    Per quanto riguarda l'articolo: mi è stato non utile ma utilissimo, mi ha chiarito molte cose. Ora lavoro un po' sul mio esercizio e poi rispondo puntualmente ai punti che hai scritto.
    Grazie ancora e saluti per ora
  • Re: Ordinare Arraylist di oggetti di interfaccia

    andbin ha scritto:


    NoCode ha scritto:


    L'interfaccia Operazione:
    Operazione tecnicamente è corretta. Il senso potrebbe essere dubbio/discutibile per due motivi:
    a) il esegui con 3 operandi è un po' strano/inconsueto. Per una divisione che vorrebbe dire??? (val1 ÷ val2) ÷ val3 ?? O che?

    La penso come te, ma così richiede l'esercizio... Evidentemente proprio val1 ÷ val2 ÷ val3...

    b) l'uso di getRisultato() presuppone che prima sia stato invocato esegui. Detto in generale (volendo fare proprio i pignoli) chi garantirebbe che in una lista di operazioni tutte siano già state "eseguite" prima dell'ordinamento?

    Giustissimo, ma diamo pr buono (anche se convengo che è un po' una forzatura...) che l'arraylist la costruisco con oggetti che sono stati istanziati proprio chiamando il metodo esegui (come nel main di test che ho postato)

    NoCode ha scritto:


    L'interfaccia Utilita:
    Classe astratta, non interfaccia.

    Sì, mia distrazione nello scrivere, sorry...

    Ma c'è una questione: quel val. Per COSA lo usi? Guarda BENE. Quel val NON è usato da nessuna parte!
    Quindi? Ripensa bene ...

    lo uso nei metodi "esegui" nelle operazioni, no?

    NoCode ha scritto:


    La classe Somma (le altre operazioni sono analoghe):
    La implementazione di Comparable<Somma> è di per sé corretta. Ma non ti è utile (probabilmente non era nemmeno richiesta dall'esercizio, vero?)

    Giustissimo, non era richiesta. L'esercizo chiedeva di ordinare l'arraylist "utilizzando il metodo Confronta". Ma io non ho idea di come si fa!

    Non è utile perché tu hai un List<Operazione> e il sort basilare si aspetta una lista di oggetti Comparable ma Operazione non è-un Comparable.

    L'unico modo per risolvere è implementare Comparator in una classe a sé stante. Oppure rendere Operazione una estensione di Comparable<Operazione> (cosa che però forse/probabilmente non è quanto voluto dall'esercizio).

    NoCode ha scritto:


    ho letto anche l'articolo che hai linkato
    Ti è stato utile? Avevo impiegato svariati giorni a scriverlo!
    Come già detto, utilissimo, grazie!


    Dunque, secondo te (ed altri che evebtualmente leggono), chiedendo di ordinare "utilizzando il metodo Confronta", cosa si vuole che si faccia? Se ho capito bene per ordinare un arraylist bisogna usare o comparable o comparator, giusto?

    Grazie mille ancora a tutti per l'attenzione e per l'aiuto!
  • Re: Ordinare Arraylist di oggetti di interfaccia

    Ho usato per la prima volta la risposta al post con citazione...evidentemente ho sbagliato qualcosa... Le risposte alle singole questioni sono dentro il box giallo.
  • Re: Ordinare Arraylist di oggetti di interfaccia

    Ciao di nuovo!
    Per andbin (e per chi è interessato):
    1) Ho provato a fare public interface Operazione extends Comparable<Operazione> come dicevi tu: avevo già provato ma avevo sempre un errore... Ora ho capito perché: avevo "dimenticato" di implementare compareTo nelle 4 classi figlie... (no comment). Adesso funziona! E sono già contento per questo grazie infinite!

    2) Probabilmente, come tu stesso hai detto, non era ciò che l'esercizio voleva... Rimane questo benedetto "utilizzando il metodo Confronta"...Qualche idea su come ordinare l'array usando un metodo "custom" (invece di compareTo).?

    Grazie!
  • Re: Ordinare Arraylist di oggetti di interfaccia

    NoCode ha scritto:


    lo uso nei metodi "esegui" nelle operazioni, no?
    No quel val di Utilita NON lo stai usando!!
    public abstract class Utilita {
        private double val;       // <-------- a COSA ti serve???
        Utilita()
        {
            this.val=0;
        }
        Utilita(double val)
        {
            this.val=val;
        }
        public abstract void stampa();
        public abstract int confronta(Operazione o);
    }
    Il campo è private, non è accessibile né alle sottoclassi né, in generale, all'esterno. Viene solo inizializzato (tra l'altro Somma non ha un costruttore esplicito, quindi ha quello di "default" che invoca super(); quindi esegue quel this.val=0; ) ma poi in Utilita quel val non viene usato.

    Quindi? Ripeto la domanda: a cosa ti servirebbe questo val?

    NoCode ha scritto:


    avevo "dimenticato" di implementare compareTo nelle 4 classi figlie...
    ovvio .....
  • Re: Ordinare Arraylist di oggetti di interfaccia

    Ciao di nuovo andbin,
    OK, ho capito, quel val non lo uso, in effetti... E ho capito anche perché: quella classe Utilita in realtà dovrebbe avere anche un metodo Potenza, che calcola appunto la potenza a^b, dove a (la base) è appunto val, e b, l'esponente, è dato come parametro di input. Con questo metodo allora sì che userei anche val. Siccome la consideravo una cosa meno importante nell'immediato, me l'ero dimenticato. Ma già il fatto di aver capito che, così com'era scritto, era un atributo inutile, mi ha chiarito un po' le cose.
    Ti ringrazio ancora molto, scusa se lo faccio dopo qualche giorno ma ho avuto dei problemi. Grazie anche a chi ha letto i post
Devi accedere o registrarti per scrivere nel forum
11 risposte