Os exercícios incidem sobre as teóricas da semana anterior. Os enunciados são baseados nos exercício do livro "Objects First with JAVA" (Primeira Edição).
|
Semanas 1º Semestre |
|||||
| 26 Setembro | 3 Outubro | 10 Outubro | 17 Outubro | 24 Outubro | 31 Outubro |
| 7 Novembro | 14 Novembro | 21 Novembro | 28 Novembro | 5 Dezembro | 12 Dezembro |
Horário especial de abertura do segundo ano da LIG: não há aulas excepto apresentação da disciplina 3ª feira (EE 0.10, 10h às 12h) e marcação de turnos (EE0.10, 15h às 17h)
Ajustes de turnos, apresentação do laboratório. Primeiro contacto com ferramenta BlueJ: criar objectos, invocar métodos, inspeccionar estado de um objecto.
Projecto shapes (chapter 1)
Crie vários objectos círculo. Poderá fazê-lo seleccionando new Circle() do menu associado à classe Circle. Faça com que os círculos criados fiquem visíveis, depois mova-os pela janela de apresentação utilizando os métodos “move”. Transforme um dos círculos num círculo grande e amarelo ("yellow"), e outro num círculo pequeno e verde ("green"). Tente o mesmo com outro tipo de formas geométricas: crie alguns triângulos e quadrados. Altere as suas posições, tamanhos e cores.
Tendo em conta os objectos criados no Exercício 1.7, faça inspecção aos seus estados. Tente alterar o estado de um objecto (por exemplo, por invocação do método moveLeft) enquanto o “object inspector” estiver aberto. Deverá observar os valores no “object inspector” a serem alterados.
Exploração da ferramenta BlueJ (continuação): interacção entre objectos, criar novos métodos, ler e entender assinaturas dos métodos.
Projecto picture (chapter 1)
No código fonte da classe Picture, encontre a parte que realmente desenha a figura. Altere-a para que o Sol seja azul em vez de amarelo.
Implemente um método para simular o pôr-do-sol. De acordo com o exercício 1.15, esse método deverá fazer com que o Sol na figura se movimente lentamente para baixo. Nesse exercício é sugerida a utilização do método slowMoveVertical da classe Circle. Assim sendo, poderemos invocar o método draw para a apresentar a imagem original (com o Sol no céu) e depois invocar o novo método para simular o pôr-do-sol (sunset).
Projecto lab-classes (chapter 1)
Crie um objecto da classe LabClass. Observe a assinatura do construtor. Especifique o número máximo de alunos na aula criada (um inteiro).
Observe a assinatura do método enrollStudent e verifique que o parâmetro esperado é do tipo Student. Crie agora alguns objectos de estudantes (Student). Invoque o método enrollStudent do objecto instância de LabClass criado anteriormente (Exercício 1.19), seleccionado o valor a passar ao parâmetro com um click sobre um dos objectos instância de Student já criados. Faça o mesmo para outros estudantes.
No objecto da classe LabClass criado no Exercício 1.19, atribua-lhe um docente (instructor), uma sala (room) e uma hora (time). Invoque o método printList para imprimir a informação referente à aula, incluindo a lista de alunos inscritos.
Construção de métodos, métodos acessionais e mutantes, estruturas condicionais.
Projecto better-ticket-machine (chapter 2)
Implemente o método empty que simula o efeito de retirar todo o dinheiro da bilheteira. O método não retorna nada (void), limitando-se apenas a colocar a zero o valor do campo total. Será que o método necessita de algum parâmetro? Teste o método empty. Para tal crie uma bilheteira, insira dinheiro, emita bilhetes, teste o total de dinheiro inserido e depois retire todo o dinheiro da bilheteira. Considera o método empty um método mutante?
Implemente o método emptyMachine que simula o efeito de retirar todo o dinheiro da bilheteira. Este método deve retornar o total de dinheiro inserido até ao momento, para além de colocar a zero o valor do campo total.
Como classifica o método emptyMachine: acessional, mutante ou ambos?
Projecto lab-classes (chapter 1)
Qual será o valor retornado pelo método getLoginName de um estudante com nome (name) “José Silva” e número (id) “123456”?
Crie uma estudante chamada “Ana” com número “654321”. O que acontece quando é invocado o método getLoginName? Porque é que acontece?
Altere o método getLoginName da classe Student de forma a gerar sempre um nome de acesso (login name), mesmo quando os campos do nome (name) e do número (id) não sejam suficientemente grandes. Para strings menores do que o necessário, utilize toda a string.
Utilização do debugger do BlueJ. Interacção entre objectos. Apresentação do enunciado do trabalho prático da disciplina.
Projecto mail-system (chapter 3)
No projecto mail-system (chapter 3) crie uma instância de MailServer
(o servidor de mensagens). Crie depois duas instâncias de MailClient. Durante a
criação das instâncias de MailClient é necessário indicar a instância do
MailServer que lhe fica associado, ou seja o servidor de correio electrónico do
cliente que se está a criar. Para além do servidor, será ainda necessário
especificar o nome do utilizador do cliente de correio electrónico, ficado cada
cliente associado a um único utilizador.
Explore os objectos MailClient criados: experimente enviar mensagens de um
cliente para outro (método sendMessage) e receber mensagens (método
getNextMailItem ou printNextMailItem).
Desenhe um diagrama de objectos que descreva a situação após a criação de um servidor e de três clientes de correio electrónico. Nota: não se esqueça de observar o código fonte das diversas classes! (mas não muito...)
Esta sequência de exercícios permite explorar o debugger do BlueJ.
3.23 - Cenário de utilização: criar um servidor de correio electrónico;
criar dois clientes para os utilizadores "Ana" e "Paulo" (para facilitar a
utilização das instâncias, os seus próprios nomes deveriam ser "ana" e "paulo",
respectivamente). Agora envie uma mensagem do utilizador "Ana" (método
sendMessage na instância "ana") para o utilizador "Paulo".
ATENÇÃO: Não leia já
a mensagem na instância "paulo"! Isso vai ser feito nos exercícios
seguintes, mas com utilização do
debugger do BlueJ.
3.24 - Ponto de paragem (breakpoint): Edite a classe MailClient e
adicione um breakpoint na primeira linha efectiva do método
printNextMailItem.
3.25 - Passo-a-passo simples (step): Na instância "paulo" invoque
o método printNextMailItem. Observe o valor do estado de execução da janela do
debugger e avance apenas uma linha na execução do código (botão Step).
3.26 - Questão: Antes de voltar a avançar com o botão Step, preveja qual
será a próxima linha a ser executada. Avance agora mais uma linha com o botão
step. A sua previsão estava certa ou errada? O que é que aconteceu e porquê?
3.27 - Questão: Depois de terminar a execução do método printNextMailItem
do exercício anterior (3.26), volte a invocar este método. Avance com o debugger
sobre o método tal como anteriormente. O que é que observa? Explique a razão de
ter sucedido.
3.28 - Passo-a-passo para dentro de método (step into): Volte a
enviar uma mensagem de Ana para Paulo. Invoque o método printNextMailItem no
cliente "paulo". Desta vez, assim que atingir a linha
item.print()
utilize o botão Step Into em vez do botão Step. Assegure-se que
consegue ver a janela de terminal (onde as mensagens são apresentadas) enquanto
avança na execução. O que é que observa? Explique o que vê.
Coloque um ponto de paragem (breakpoint) na primeira linha efectiva do método sendMessage da classe MailClient. Invoque agora esse método para enviar uma mensagem e utilize o botão Step Into da janela do debugger para entrar dentro do construtor de itens de correio electrónico (MailItem). Observe agora na janela do debugger as variáveis locais bem como as variáveis de instância a serem inicializadas à medida que avança na execução passo-a-passo no construtor. Avance até ao final do método sendMessage podendo optar por entrar dentro do método post do servidor durante a execução.
Por observação do código fonte, execução integral de métodos, definição de
pontos de paragem e execução de métodos com o debugger, procure entender
as classes MailItem e MailClient. Procure igualmente entender a classe
MailServer, tendo em conta que utiliza conceitos apresentados em capítulos
posteriores ao Capítulo 3, mas já apresentados nas aulas teóricas.
Desenhe diagramas de objectos para explicitar o funcionamento dessas classes.
Colecções de objectos (ArrayList). Iterações em colecções.
Projecto auction (chapter 4)
Este projecto implementa um sistema de leilão. A classe Lot representa cada lote de artigos a serem leiloados. A classe Auction representa um leilão, tendo informação sobre os lotes a serem leiloados. A classe Person representa as pessoas que fazem uma licitação (oferta) para comprar um lote. A classe Bid representa as licitações (ofertas) feitas para um determinado lote.
Procure exemplos de casting nos métodos da classe Auction.
O que acontece se tentar compilar a classe Auction sem um dos casting? Por exemplo, altere o método showLots de forma a que a primeira instrução do bloco do ciclo while passe a ser:
Lot lot = it.next();
e teste o resultado da alteração.
Acrescente um novo método à classe Auction chamado close. Este método deverá percorrer a colecção de lotes (lots) e imprimir os seus detalhes. Os detalhes referentes aos lotes que já tenham sido vendidos devem incluir o nome da pessoa que o comprou, bem como o valor pelo qual foi comprado. Sempre que um lote não tenha sido vendido, deve imprimir-se uma mensagem que indique esse facto.
Suponha que a classe Auction contém um método que permite a remoção de lotes. Assumindo que o número de cada um dos restantes lotes (ver campo number na classe Lot) não é alterado sempre que ocorra uma remoção, qual será o impacto que esta nova operação teria no método getLot?
Reescreva o método getLot de forma a que este não associe o número de lote ao índice (número-de-lote -1) na colecção. Poderá assumir que os lotes são sempre por ordem crescente do seu número de lote.
Acrescente um novo método à classe Auction chamado removeLot, o qual deverá ter a seguinte assinatura:
/**
* Remove o lote identificado pelo
número de lote.
* @param number
O número do lote a ser removido.
* @return O lote
com o número indicado, ou null no caso de não existir.
*/
public Lot removeLot(int number)
Este método não deverá assumir que um lote com um determinado número está armazenado numa posição em particular dentro da colecção.
Classes da biblioteca Java. Exemplos de utilização de Maps (mapas): a classe java.util.HashMap. Documentação das classes em Java.
Nota: os exercícios desta semana são para ser feitos num novo projecto e não num projecto já existente, tal com tem vindo a acontecer nas aulas anteriores.
O que é um HashMap? Qual é a sua função e como utilizá-lo? A resposta a estas questões deve ser feita tendo por base a consulta da documentação da biblioteca Java (caso tenha a documentação localmente no seu computador, poderá consultá-la aqui).
Crie um novo projecto com uma classe chamada MapTester que utiliza um HashMap para implementar uma lista telefónica na qual apenas são armazenados os nomes e os números de telefone de diversas pessoas. Na classe criada implemente os seguintes métodos:
public void enterNumber(String name, String number) - que permite inserir na lista telefónica uma nova pessoa e respectivo número de telefone.
public String lookupNumber(String name) - que permite obter o número de telefone de uma determinada pessoa.
Estes dois métodos devem utilizar os métodos "put" e "get" da classe HashMap de forma a implementar a sua funcionalidade.
O que acontece quando se adiciona uma nova entrada (par chave/valor) num mapa (por exemplo, o HashMap) com uma chave já existente?
O que acontece quando se adiciona uma nova entrada (par chave/valor) num mapa (por exemplo, o HashMap) com um valor já existente?
Como é que se verifica que uma chave já existe no mapa? Apresente exemplos do código Java que constem do projecto desta aula.
O que acontece quando se tenta obter um valor cuja chave não existe no mapa?
Como se obtém o número de entradas (pares chave/valor) de um mapa?
Acrescente comentários de documentação (/** ... */) na classe MapTester,
utilizando os diversos símbolos especiais para formatação (por exemplo, @param).
Utilize a vista "interface" do editor de código fonte do BlueJ (no botão mais à
direita do editor, com opções "implementation" e "interface", escolher
"interface") e veja a documentação resultante. Utilize ainda a funcionalidade
"Project Documentation" do BlueJ (menu Tools) para gerar a documentação do
projecto em html.
Mais informação sobre documentação de código Java
aqui
Hierarquia de classes em Java. Superclasses e subclasses. Tipos e subtipos.
Projecto dome-v2 (chapter 8)
Abra o projecto dome-v2 (versão de DoME com hierarquia de classes). Observe o diagrama de classes, nomeadamente a hierarquia de classes dos itens (cd's e vídeos) a inserir na base de dados multimédia. Crie alguns cd's e alguns vídeos. Crie igualmente um objecto de base de dados (classe Database). Insira os cd's e os vídeos na base de dados e depois liste o conteúdo da mesma.
Ainda no projecto dome-v2, coloque um ponto de paragem (breakpoint) na primeira linha do construtor da classe CD. Depois crie um novo objecto da classe CD. Assim que aparecer a janela do debugger, use o botão Step Into para avançar ao longo do código fonte. Observe as variáveis de instância (campos) e sua inicialização. Descreva o que observa.
Adicione uma nova classe para jogos de vídeo ao projecto dome-v2. Para
além dos campos que todos os itens têm, essa classe ainda tem os campos
numberOfPlayers e platform, respectivamente para guardar o número de
jogadores e a plataforma de execução dos jogos de vídeo. Crie alguns objectos
dessa nova classe e teste se todos os seus métodos (incluindo os que são
herdados) funcionam tal como esperado.
Nota: aproveite este exercício para repensar a resposta dada ao exercício 8.10
apresentado na aula
teórico-prática da
semana de 31 de Outubro.
Considere as seguintes classes: Pessoa, Professor, Estudante, Doutorando.
Professor e Estudante são ambas subclasses de Pessoa. Doutorando é subclasse de
Estudante.
Quais das seguintes atribuições estão correctas e porquê?
Pessoa p1 = new Estudante();
Pessoa p2 = new Doutorando();
Doutorando d1 = new Estudante();
Professor prof1 = new Pessoa();
Estudante e1 = new Doutorando();
e1 = p1;
e1 = p2;
p1 = e1;
prof1 = e1;
e1 = d1;
d1 = e1;
Teste as suas respostas ao exercício anterior criando as classes referidas no mesmo e experimentando-as no BlueJ.
Hierarquia de classes em Java (continuação). Tipos estáticos e tipos
dinâmicos. Redefinição de métodos (overriding). Procura dinâmica de
métodos. Polimorfismo de métodos.
Trabalho Prático: ponto de situação dos vários grupos de trabalho após entrega
do relatório intermédio.
Projecto dome-v2 (chapter 8)
Abra a sua última versão do projecto DoME. (Pode utilizar a versão dome-v2 caso não tenha ainda a sua própria versão). Remova o método print da classe Item e coloque-o na classe Video e na classe CD. Proceda à compilação das várias classes. O que observa?
No seu projecto DoME, acrescente
novamente o método print na classe Item. Rescreva o corpo do método de
forma imprimir apenas o title. Depois altere os métodos print da
classe CD e da classe Video, de modo a imprimir apenas a informação relativa ao
artista, no caso do CD; e a imprimir apenas informação relativa ao director, no
caso do Video. Desta forma irá solucionar os erros que surgiram no exercício
anterior.
Antes de executar, preveja qual dos métodos print é que irá ser executado
após invocação do método list da classe Database.
Experimente agora, inserindo um objecto da classe CD e um objecto da classe
Video na base de dados Database e depois invoque o método list dessa
mesma classe. Qual foi o método print invocado? A sua previsão estava
correcta? Tente explicar o que observou.
Altere a última versão do projecto DoME de forma a incluir uma chamada super no método print de cada subclasse da classe Item, invocando assim o método print dessa classe. Efectue alguns testes. O resultado é o esperado? Detecta algum problema com esta solução?
A invocação do método print da superclasse torna a apresentação da informação sobre os itens algo restritiva, na medida em que esta fica dependente na forma como o valor da variáveis de instância são apresentados. Efectue as alterações necessárias à classe Item e ao método print da classe CD de modo a apresentar a informação da seguinte forma:
CD: Frank Sinatra:
A Swinging Affair *
16 tracks,
64 minutes
my
favorite Sinatra album
Note que o texto nas áreas a sombreado representam detalhes de informação da
superclasse.
Tenha em atenção que as alterações feitas à classe Item devem continuar a
preservar o encapsulamento, sendo apenas aceitável que o mesmo seja quebrado
quando se trate de uma subclasse. Assim , sempre que se justifique, sugere-se a
utilização do qualificador protected nas variáveis de instância da classe
Item.
Classes abstractas e interfaces em Java.
Trabalho prático: Esclarecimento de dúvidas referentes à implementação.
Projecto foxes-and-rabbits-v2 (chapter 10)
Este projecto simula o comportamento de uma população de animais numa determinada região (classe Field) modelada por uma matriz com várias posições (classe Location). Os animais considerados na simulação são as raposas (classe Fox) e os coelhos (classe Rabbit). A simulação propriamente dita é feita pela classe Simulator, que povoa o espaço com animais (raposas e coelhos) e os faz actuar (movimentar, caçar, etc) nesse espaço. Existem outras classes no projecto, nomeadamente as classes SimulatorView, FieldStats e Counter, responsáveis pela visualização gráfica da simulação e de alguns dados estatísticos sobre a mesma.
Abra o projecto foxes-and-rabbits-v2. Mova o método canBreed das classes Fox e Rabbit para a classe Animal e reescreva-o da seguinte forma:
/**
* An animal can breed if it has reached the breeding
age.
*/
public boolean canBreed()
{
return getAge() >= getBreedingAge();
}
Observe a invocação do método getBreedindAge. Acrescente agora o método getBreedindAge nas classes Fox e Rabbit de forma a comportar-se como o método acessional da constante BREEDING_AGE. Será que as alterações introduzidas são suficientes para se poder compilar o projecto? Se não forem, o que faltará na classe Animal?
Suponha agora que se pretende melhorar a simulação de forma a permitir outro
tipo de intervenientes para além dos animais, tais como plantas, tempo, etc.
Para tal necessitamos de generalizar a classe Animal, a qual passa agora a ser
uma especialização da classe do topo da hierarquia dos intervenientes, designada
Actor (ver figura10.3 da pág. 278 do livro). Considere ainda que a única
característica comum a todos os intervenientes é o facto de todos realizarem
algum tipo de acção, isto é, todos têm o método act (ver assinatura na
página 278 do livro), ainda que com
implementações diferentes.
Codifique agora a classe abstracta Actor e reescreva o método
simulateOneStep da classe Simulator de forma a utilizar o tipo
Actor em vez de Animal.
Reescreva a classe abstracta Actor do exercício anterior de forma a que esta passe a ser um interface (como é óbvio, altere também a ou as subclasses da classe Actor de forma a implementarem o interface em vez de estenderem a classe abstracta). Continuará a ser possível compilar e executar o projecto?
Tratamento de erros e excepções.
Trabalho prático: Esclarecimento de dúvidas referentes à implementação.
Projecto address-book-v3t (chapter 11)
Este projecto representa uma aplicação de gestão de contactos pessoais. As classes principais deste projecto são a classes AddressBook e ContactDetails. A classe AddressBookDemo permite testar a aplicação, criando para alguns contactos pessoais a serem introduzidos. Este projecto faz parte de um conjunto de projectos que, para além das versões texto, incluem ainda algumas versões gráficas.
No projecto address-book-v3t é feito o lançamento de algumas "unchecked exceptions", caso dos valores passados aos parâmetros dos vários métodos sejam null. O projecto inclui ainda uma "checked exception", representada na classe NoMatchingDetailsException, que actualmente não está a ser utilizada. Modifique o método removeDetails da classe AddressBook de forma a que este lance a referida excepção caso o parâmetro key não seja uma chave em utilização (chave não existente). Adicione agora o código necessário para apanhar e tratar a excepção (apresentando a respectiva ocorrência da mesma) no método remove da classe AddressBookTextInterface.
Ainda no projecto address-book.v3t, defina uma nova classe para a "checked exception" designada DuplicateKeyException. Esta excepção deverá ser lançada pelo método addDetails da classe AddressBook caso algum dos campos não null (campos name e phone) do seu parâmetro já esteja a ser utilizado. A classe de excepção a criar deverá armazenar os detalhes das chaves em situação de erro. Faça as alterações que julgue necessárias na classe de interface com o utilizador de modo a apanhar e reportar as situações de excepção.
Streams em Java.
Trabalho prático: Esclarecimento de dúvidas referentes à implementação.
Projecto address-book-v3t (chapter 11)
Acrescente ao projecto address-book-v3t a funcionalidade de gravar e
ler a lista de contactos e outra informação que julgue necessária em
ficheiro. Teste convenientemente, acrescentando os dois novos comandos ao
interface com o utilizador.
Tenha em atenção que o exercício poderá ser resolvido com recurso a streams de
texto ou streams de bytes. Pondere sobre a utilização dos dois tipos de streams
e opte por uma na implementação
Apresentação e defesa do trabalho prático.