UFPR · DELT · Contact
Exercicio / Aula Prática

Exercícios sobre fundamentos de programação
Utilize a linguagem Java em todos os casos. Estes exercícios foram planejados para treinar questões de fundamentos de programação.
  1. Escreva um programa para verificar se um número é par ou impar. O usuário deve entrar com o número pelo teclado.
  2. Escreva um programa para verificar se um número digitado pelo usuário é primo ou não. Um número primo é aquele que é divisível apenas por ele mesmo ou por 1.
  3. Escreva um program que pede o valor de um depósito inicial, o valor do investimento mensal, o número de meses que o dinheiro vai ficar rendendo na poupança e a taxa de juros mensal. Após isso, calcule o valor do capital no final do período e o lucro obtido.
  4. Escreva um programa que indica se um número digitado pelo usuário é uma potência de dois ou não. 1,2 e 4 são potências de dois. 3 não é potência de dois.
  5. Escreva um programa para ordenar um vetor de números inteiros digitados pelo usuário. Não utilize ferramentas da API.
  6. Escreva um programa para imprimir uma String digitada pelo usuário ao contrário. Não use a API. Por exemplo, se o usuário digitou "teste" o programa imprime "etset".
  7. Escreva um programa para imprimir os n primeiros números da série de Fibonacci. O usuário deve entrar com o valor de n. A série de Fibonacci pode ser calculada por F(n)=F(n–1)+F(n–2), com F(1)=F(2)=1 .
  8. Escreva um programa para calcular o valor do fatorial de um número digitado pelo usuário. Escreva duas versões: recursiva e não recursiva.
  9. Escreva um programa para calcular a média e o desvio padrão de uma série de valores digitados pelo usuário.
  10. Dado uma base n, n>1, calcule recursivamente o valor de n^x. O usuário deve entrar com o valor de n e x. Exemplo: potencia(3,2) deve retornar 9. Não é permitido o uso de loops.

Classes e Objetos
Este exercício tem como objetivo fixar o conceito de classes e objetos.
Suponha uma biblioteca que possui um acervo de livros.
  1. Crie uma classe para representar um livro e um programa para testar esta classe (classe Livro). Solução: Livro.java - TesteLivro.java
  2. Crie uma classe para representar o acervo de livros da biblioteca (classe Acervo) e um programa para testar esta classe. Em uma primeira implementação o acervo deve ser capaz de representar uma lista de livros utilizando um vetor de tamanho fixo. O programa de teste deve permitir a inserção e remoção de livros. O programa de teste deve realizar uma interface básica com o usuário. Solução: Acervo.java - TesteAcervo.java
  3. Crie uma classe para manipular uma lista de livros (ListaLivros). Esta classe deve permitir a inserção, remoção, pesquisa por título e listagem dos livros da lista. A classe Acervo deve ser modificada para utilizar uma lista de livros ao invés de utilizar o vetor de tamanho fixo implementado no item anterior. ListaLivro.java - TesteListaLivro.java

Herança e Polimorfismo
  1. Considere o seguinte código:
    public class Pai {
    
        public int a, b;    
    
        public void teste1() {
           System.out.println("\n1");
        }
        public void teste2() {
           System.out.println("\n2");
        }
        Pai() //Construtor
        {
           System.out.println("\nConstrutorPai");
           a=1;
           b=1;
        }
    }
    
    public class Filho extends Pai {
        
        public int b,c;
    
        public void teste2() {
           System.out.println("\n3");
        }
        public void teste3() {
           System.out.println("\n4");
        }
        Filho() //Construtor 
        {
           System.out.println("\nConstrutorFilho");
           b=2;
           c=2;
        }
    }
    
    Com relação ao código acima, responda as seguintes perguntas:
    • Suponha que seja criado um objeto do tipo Filho. Verifique qual a ordem de chamada dos construtores.
    • Suponha que seja criado um objeto do tipo Filho. As chamadas aos métodos teste1(), teste2(), e teste3() correspondem a qual código?
    • Suponha que o programador da classe Filho deseja re-escrever o método teste2() fazendo uma chamada ao método teste2() da classe Pai. Mostre como isso pode ser feito.
    • Suponha que seja criado um um objeto do tipo Filho. Qual o valor do atributo a, b e c? Em qual classe cada atribudo foi definido? Em qual classe cada atributo foi inicializado?
    • Suponha que seja criada uma classe Avô. A classe pai foi extendida da classe avô. A classe filho foi extendida da classe pai. Quando foi criada um objeto do tipo filho, qual a ordem de chamada dos construtores?
    • Suponha que a classe Avô defina o atributo a do tipo inteiro, e em seu construtor seja atribuído o valor inicial 0. Um objeto do tipo Filho possuirá um atributo a com qual valor inicial?
  2. Suponha um programa para calcular salários de funcionários de uma empresa. Nesta empresa, todos os funcionários possuem um salário base. O salário é calculado através do salário base, somado ao número de horas extras trabalhadas. Por simplificação, considere uma carga de 40 horas semanais e considere o valor da hora extra igual à hora regular. Escreva um método para calcular o salário. Suponha que um vendedor possui o salário calculado da mesma forma, mas somando um valor de comissões recebidas. Escreva as classes Funcionário e Corretor, com um método para o cálculo do salário. Utilize o conceito de herança e polimorfismo. Escreva um programa para testar o uso das classes implementadas.

Fundamentos de Análise - UML
Considere o problema o sistema de acervo de livros apresentado anteriormente. Suponha que se deseja um sistema para gerenciar os livros de uma biblioteca, incluindo empréstimos para usuários.
  1. Desenvolva o diagrama de casos de uso para este problema.
  2. Projete o diagrama de classes.
Considere o problema tratado no Trabalho 1:
  1. Desenvolva o diagrama de casos de uso para este problema.
  2. Projete o diagrama de classes.

Concorrência e sincronização
A abordagem a seguir considera que todos os alunos tem bom conhecimento sobre Threads e Processos, bem como os problemas de condições de corrida.
Considere o seguinte código:
public class TesteThread implements Runnable {

    private static int cont=1; 
    private int id;    

    TesteThread() //construtor
    {
       id=cont;
       cont++;
    }

    public void run() {
       int i;
       
       for (i=0;i<10;i++) { 
            System.out.printf("\nThread %d - %d",id, i);
            try {
               Thread.sleep(1000); // thread dorme por 1000 milisegundos
            } 
            catch (InterruptedException e) {
               e.printStackTrace(); 
            }
        }
    } 
}

public class Teste {
 public static void main(String args[]) {
       Thread t;
       TesteThread th1;
       th1= new TesteThread();
       t = new Thread(th1);
       t.start();

       try {
           t.join(); 
        } 
        catch( Exception e) {
           System.out.println("Interrupted");
        }

    }
}
Com relação ao código acima, responda as seguintes perguntas:
  1. Compile e execute o código.
  2. Modifique o código para que o método main da classe teste crie 3 threads. Execute e observe o resultado.
  3. Procure na documentação da API Java porque foi possível chamar diretamente o método sleep da classe Thread.
  4. Procure na documentação da API Java porque é obrigatório o uso do try {...} catch {...} na chamada do método sleep da classe Thread. Romova o try {...} catch {...}, tente compilar e observe o resultado.
  5. Procure na documentação da API Java qual a função do método join utilizado na classe Teste.
  6. Re-escreva a classe TesteThread utilizando herança ao invés de usar a interface. Modifique a classe Teste para testar a sua implementação.
Considere o seguinte código:
class ContadorEstatico {
    private static int c = 0;

    public static void increment() {
        c++;
    }

    public static void decrement() {
        c--;
    }

    public static int getValue() {
        return c;
    }
}


public class TesteThread1 implements Runnable {

    private static int cont=1; 
    private int id;    

    TesteThread1() //construtor
    {
       id=cont;
       cont++;
    }

    public void run() {
       int i;
       
       for (i=0;i<100000;i++) { 
            ContadorEstatico.increment();
        }
    } 
}

public class Teste1 {
 public static void main(String args[]) {
       Thread t;
       TesteThread1 th1;
       th1= new TesteThread1();
       t = new Thread(th1);
       t.start();

       for (int i=0;i<100000;i++) { 
            ContadorEstatico.decrement();
        }

       try {
           t.join(); // espera pelo fim da thread t
        } 
        catch( Exception e) {
           System.out.println("Interrupted");
        }

        System.out.printf("\nO valor final do contador é: %d\n\n",ContadorEstatico.getValue());

    }
}
Com relação ao código acima, responda as seguintes perguntas:
  1. Analise o código. Qual deveria ser o valor impresso?
  2. Explique porque o valor impresso foi diferente do previsto.
  3. Modifique os métodos da classe ContadorEstatico para que eles sejam sincronizados (synchronized).
  4. Explique o funcionamento da diretiva synchronized do Java.

Programação Sockets
Considere os programas cliente-servidor disponíveis em http://www.eletrica.ufpr.br/TE253/Programas/Sockets/. Modifique a versão Multithread do programa servidor para responder à requisição de um cliente HTTP (browser), da seguinte forma:
  1. Não processe a requisição e sempre responda com uma mesma mensagem, formatada em da seguinte forma:

    ---------------
    HTTP/1.1 200 OK
    Date: Fri, 31 Dec 1999 23:59:59 GMT
    Content-Type: text/plain
    Content-Length: 8
    some-footer: some-value
    another-footer: another-value

    mensagem
    ------------------

    troque o Content-Type por text/html e envie uma mensagem HTML.

  2. Não processe a requisição e responda com uma mesma mensagem, formatada em HTML, informando o horário atual (dica. http://www.tutorialspoint.com/java/java_date_time.htm).

Voltar para página da TE253