Jump to content

Problema com construtor


Baderous
 Share

Recommended Posts

Cá estou eu com mais uma dúvida. Desta vez tenho uma classe que tem um TreeSet<Passageiro> como variável de instância, sendo Passageiro uma classe que tem 3 Strings como variáveis de instância. Estou a tentar definir um construtor na sua forma mais básica receberia um TreeSet<Passageiro> e um Comparator de Passageiros, o qual já defini numa classe à parte. Disse forma mais básica pois estou a tentar obter o máximo de abstracção, fazendo por isso com que o tal TreeSet que é argumento seja na verdade uma Collection<? extends Passageiro>. O método compila e acho que está bem definido, mas quando, numa classe de teste tento criar um conjunto de passageiros através deste construtor dá-me erro.

Classe que implementa o Comparator de Passageiros:

import java.util.*;
import java.io.*;

public class PassageiroComparator implements Serializable, Comparator<Passageiro> {
    /**Método que compara 2 Passageiros pelos seus códigos*/
    public int compare(Passageiro p1,Passageiro p2) {
        return (p1.getCodigo()).compareTo(p2.getCodigo());
    }
}

Classe que implementa o TreeSet<Passageiro>:

import java.util.*;
import java.io.*;

public class ListaPassageiros implements Serializable {
    //Variáveis de instância
    /**Conjunto de passageiros de um voo*/
    private TreeSet<Passageiro> listaP;

/**Construtor que recebe um Comparator*/
    public ListaPassageiros(Comparator<Passageiro> c) {
        listaP = new TreeSet<Passageiro>(c);
    }
    
    /**Construtor completo*/
    public ListaPassageiros(Collection<? extends Passageiro> lst, Comparator<Passageiro> c) {
        this(c);
        for (Passageiro p : lst)
            listaP.add(p.clone());
        }

Classe de teste:

public class Teste {
    public static void main(String[] args) {
        ListaPassageiros lista = new ListaPassageiros();
        Passageiro p1 = new Passageiro("q123","joao","pt");
        Passageiro p2 = new Passageiro("a423","maria","esp");
        Passageiro p3 = new Passageiro("23sdf","jose","nam");
        lista.inserePassageiro(p1);
        lista.inserePassageiro(p2);
        lista.inserePassageiro(p3);
ListaPassageiros lesp = new ListaPassageiros(lista,new PassageiroComparator());

O erro ocorre nesta última linha. Consultando a ajuda do BlueJ, ele indica:

http://img183.imageshack.us/img183/949/72177366gf4.jpg

Também tenho um erro de compilação quando uso um método semelhante que adiciona uma colecção de passageiros ao conjunto já existente.

/**Método que adiciona uma colecção de passageiros ao conjunto já existente*/
    public void insereColeccao(Collection<? extends Passageiro> c) {
        for (Passageiro p : c)
            listaP.add(p.clone());
        }

Alguma coisa devo estar a fazer mal...

Não creio que o erro esteja no Collection<? extends Passageiro> porque já tentei fazer com TreeSet<Passageiro> e dá erro na mesma. Deve ser problema na classe de teste...

Somebody help me!

Link to comment
Share on other sites

Guest id194

Não te posso ajudar com o teu problema mas visto isto ser relacionado com o trabalho que também estou a fazer, porquê que estas a usar um TreeSet para a lista de passageiros? Será que vais tirar partido da ordenação do TreeSet? Em que circunstâncias?

Mas o mais importante é, porque não um Map onde ao código do passageiro associas-lhe a ficha de passageiro? Pelo menos é como eu estou a fazer e parece ser uma hipotese melhor do que simplesmente guardar as fichas sem lhe associares nada. Claro que isto depende um pouco de como irás fazer o resto do trabalho e das operações que vais efectuar à lista de passageiros, mas assim há primeira vista, parece-me melhor um Map (seja Hash ou Tree, isso já é + especifico).

Link to comment
Share on other sites

Porque tendo em conta as operações que vão ser efectuadas sobre os passageiros, não será necessário consultar a informação pessoal de cada um. Eu por acaso também pus essa ideia no início mas depois fiz com Set, só para evitar repetidos.

Quanto ao meu problema, acho que já resolvi. O problema era que estava a passar uma instância de ListaPassageiros no lugar de uma Collection, logo dava erro.

Link to comment
Share on other sites

Vou aproveitar esta thread para perguntar sobre uma coisa parecida. Quero criar uma classe que tem como variável de instância um Map<CodigoDeVoo,Voo>. Voo possui um tempo de partida como variável. Eu gostava que esse Map fosse um TreeMap<CodigoDeVoo,Voo> em que os códigos estivessem ordenados por tempo de partida dos voos. Mas isto não é possível pois não uma vez que a ordenação é referente às chaves do Map, certo?

Se não for, como devo fazer? Criar um HashMap<CodigoDeVoo,Voo>, e depois num método auxiliar, criar um TreeMap que seja cópia deste HashMap, mas que esteja ordenado por TempoPartida??

Link to comment
Share on other sites

A ordenaçã é sempre feita pela chave, usando apenas uma estrutura não consegues ordenar os elementos sem ser por chave.

Outro problema a que tens de ter atenção é que é perigoso usar, como chave, elementos que não são imutáveis, isto é, uma chave não deve sofrer alterações que afectem o método equals, enquanto está dentro de um Map. Se isso acontecer, o comportamento do Map é indeterminado.

Quanto ao teu problema, a solução que apresentaste é uma possível, mas precisas que os elementos estejam sempre ordenados por tempo ou a ordenação acontece em alturas muito especificas?

Se não precisas sempre poderás usar os métodos de ordenação da classe Collections, desta forma ordenas apenas quando precisas dos dados por ordem e não tens uma segunda estrutura. Tens a desvantagem de perder alguma performance, mas pode ser mais simples de implementar.

Por outro lado, se usares o TreeMap e tiveres dois tempos iguais? Repara que ao adicionares dois objectos diferentes com a mesma chave, o valor antigo é substituído.

Link to comment
Share on other sites

A ordenaçã é sempre feita pela chave, usando apenas uma estrutura não consegues ordenar os elementos sem ser por chave.

Tal como suspeitava.

Outro problema a que tens de ter atenção é que é perigoso usar, como chave, elementos que não são imutáveis, isto é, uma chave não deve sofrer alterações que afectem o método equals, enquanto está dentro de um Map. Se isso acontecer, o comportamento do Map é indeterminado.

Por outro lado, se usares o TreeMap e tiveres dois tempos iguais? Repara que ao adicionares dois objectos diferentes com a mesma chave, o valor antigo é substituído.

Ainda bem que disseste isso, pois a variável Tempo de Partida pode sofrer alterações (atrasos no voo), e podem existir 2 voos à mesma hora!

Quanto ao teu problema, a solução que apresentaste é uma possível, mas precisas que os elementos estejam sempre ordenados por tempo ou a ordenação acontece em alturas muito especificas?

Se não precisas sempre poderás usar os métodos de ordenação da classe Collections, desta forma ordenas apenas quando precisas dos dados por ordem e não tens uma segunda estrutura. Tens a desvantagem de perder alguma performance, mas pode ser mais simples de implementar.

O objectivo da classe é guardar o mapa de voos do aeroporto. Não creio que seja necessário ter os voos por ordem. No entanto, um dos requisitos é que deverá existir um Placard electrónico no aeroporto que apresente informação relativa a alguns voos e têm de estar por ordem de tempo de partida.

Mas agora estou aqui a pensar...se eu criar uma classe VooComparator que implemente a interface Comparator<Voo>, onde, se o tempo de partida do voo v1 for menor do que o v2, então ele é menor, caso contrário (se for igual ou maior), então é maior. Algo como isto (tempo de partida é instância de GregorianCalendar):

public class VooComparator implements Serializable, Comparator<Voo> {
    /**Método que compara 2 Tempos de Partida pelas suas horas*/
    public int compare(Voo v1,Voo v2) {
        if (v1.getTempoPartida().before(v2.getTempoPartida()))
            return -1;
        else return 1;
    }
}

Assim já poderei fazer o tal método com o TreeMap, passando-lhe o Comparator como parâmetro (desde que, quando ocorra um atraso, remova a chave e o Voo do Map, altere o tempo de partida, e volte a inserir)?

Link to comment
Share on other sites

Sim, podes usar esses, ou esse, método de ordenação.

Se usares o sort que recebe um comparador podes usar o que já tens feito ou fazer outro que se adapte melhor, se não quiseres usar um comparador podes colocar os teus objectos a implementarem a classe Comparable, que é o mesmo que o comparador, e podes usar o método sort que recebe apenas uma Collection.

Link to comment
Share on other sites

Guest id194

Não querem dar um exemplo mais concreto de como se faria isso? Também vou precisar disto 👍 mas não estou a ver bem como faria, ainda não domino bem o comparator...

Link to comment
Share on other sites

Um pequeno exemplo de como usar a interface Comparable e o método sort da classe Collections para ordernar uma lista.

Se usarem um comparador terão de usar o método que receba o comparador e adaptar em conformidade. Em principio será apenas retirar a interface e o método de comparação.

Reparem que usando a interface Comparable apenas podemos comparar de uma forma, não sendo possível ter dois métodos de comparação.

package allaroundtesting;

import java.util.Collections;
import java.util.LinkedList;

/**
*
* @author knitter
*/
public class Pessoa implements Comparable {

    private String nome;
    private int idade;
    private LinkedList<Pessoa> familiares;
    
    public Pessoa() {
        familiares = new LinkedList<Pessoa>();
        familiares.add(new Pessoa("Tiago", 50));
        familiares.add(new Pessoa("Joao", 15));
        familiares.add(new Pessoa("Andre", 35));
        familiares.add(new Pessoa("Maria", 20));
        familiares.add(new Pessoa("Ana", 35));
        familiares.add(new Pessoa("Marta", 40));
        familiares.add(new Pessoa("Jose", 10));
        familiares.add(new Pessoa("Paula", 5));
    }
    
    public Pessoa(String nome, int idade) {
        this.nome = nome;
        this.idade = idade;
    }
    
    public void mostrar() {
        System.out.println("Antes de ordenar:");
        for(Pessoa p : familiares) {
            System.out.println(p);
        }
        
        Collections.sort(familiares);
        
        System.out.println("\nDepois dede ordenar:");
        for(Pessoa p : familiares) {
            System.out.println(p);
        }        
    }
    
    //Comparar por nome para que as pessoas possam ser ordenadas por nome.
    public int compareTo(Object o) {
        return nome.compareTo(((Pessoa) o).nome);
    }
    
    //Comparar por idade, apenas um metodo de comparacao pode existir
    /*
    public int compareTo(Object o) {
        idade - ((Pessoa)o).idade;
    }*/
    
    @Override
    public String toString() {
        return nome + ", " + idade + " anos.";
    }
    
    public static void main(String[] args) {
        new Pessoa().mostrar();
    }
}
Link to comment
Share on other sites

Acho que já consegui. Criei um método onde tenho 1 ArrayList<GregorianCalendar> e um HashSet<Voo> e um ArrayList<Voo>. Depois percorro o mapa de voos e coloco os tempos de partida de cada voo no ArrayList<GregorianCalendar> e os voos no HashSet<Voo>. Depois faço Collections.sort do ArrayList<GregorianCalendar>, ficando os tempos ordenados por ordem crescente. Depois, percorro esse ArrayList e, para cada tempo, vou ao HashSet<Voo> buscar o voo cujo tempo de partida lhe corresponde, coloco-o no ArrayList<Voo> e retiro-o do HashSet<Voo> (assim quando ele vai procurar por um tempo de partida repetido, vai-me devolver outro voo, não interessa a ordem, o que interessa é que não sai o mesmo, porque já lá não está). Por fim devolvo o ArrayList<Voo>.

/**Método que ordena os voos por Tempo de Partida*/
    public List<Voo> ordenaPorTempo() {
       ArrayList<GregorianCalendar> tp = new ArrayList<GregorianCalendar>();
       HashSet<Voo> voos = new HashSet<Voo>();
       ArrayList<Voo> res = new ArrayList<Voo>();
       for (Voo v : this.mapa.values()) {
            tp.add(v.getTempoPartida());
            voos.add(v.clone());
        }
       Collections.sort(tp);
       for (GregorianCalendar c : tp) {
            boolean encontrado = false;
            Iterator<Voo> it = voos.iterator();
            Voo v = null;
            while (!encontrado && it.hasNext()) {
                v = it.next();
                if (v.getTempoPartida().equals(c)) {
                    encontrado = true;
                    res.add(v.clone());
                    it.remove();
                }
            }
        }
        return res;
    }
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.