partir do estudo desta unidade, você deverá ser capaz de:
conhecer algumas peculiaridades e usos importantes sobre interfaces;
criar e usar adequadamente métodos e generalizações usando a linguagem Java;
conhecer os tipos de referências e objetos de cópia em POO;
aplicar os registros de maneira adequada usando a linguagem Java.
PLANO DE ESTUDOS
A cada tópico desta unidade, você encontrará autoatividades com o objetivo de reforçar o conteúdo apresentado.
Unidade 3
Bem-vindo à Unidade 3 da disciplina de Programação Orientada a Objetos. Nesta etapa, vamos conhecer algumas estruturas mais complexas relacionadas à programação orientada a objetos.
Nesta Unidade abordaremos sobre tópicos relacionados aos conteúdos de interfaces como interfaces no mecanismo de retorno de chamada bem como métodos de enumeração.
Quais os objetivos de aprendizagem da Unidade 3 Confira:
Conhecer algumas peculiaridades e usos importantes sobre interfaces;
Criar e usar adequadamente métodos e generalizações usando a linguagem Java;
Conhecer os tipos de referências e objetos de cópia em POO;
Aplicar os registros de maneira adequada usando a linguagem Java.
A programação orientada a objetos (OOP) é um paradigma de programação baseado em objetos (tendo dados e métodos) que visa incorporar as vantagens da modularidade e da reutilização. Os objetos, que geralmente são instâncias de classes, são usados para interagir uns com os outros para projetar aplicativos e programas de computador.
As características importantes da programação orientada a objetos são:
Abordagem de baixo para cima no design do programa.
Programas organizados em torno de objetos, agrupados em aulas.
Concentre-se em dados com métodos para operar sobre os dados do objeto.
Interação entre objetos através de funções.
Reutilização do design através da criação de novas classes adicionando recursos às classes existentes.
Que tal relacionar-se com os colegas por meio de um Fórum? Esse recurso favorece o diálogo, a troca de opiniões e de saberes, estimulando o debate e a reflexão em torno de temas, situações, problemas ou ideias encontradas em nossa vida acadêmica e pessoal.
Que tal realizar um Objeto de Aprendizagem? Sugerimos o artigo "Os 4 pilares da Programação Orientada a Objetos", que serve para contextualizar brevemente sobre a Linguagem Java.
Nada melhor do que ver codificação e prática para entender os conceitos complexos por trás da Programação Orientada a objetos com Java. Deste modo, veja a live do programador Nélio do canal DevSuperior onde ele explica passos importantes desse paradigma usando a linguagem Java.
Orientação a Objetos : Introdução prática : Programação Orientada a Objetos
Por fim, lembre-se de reservar uma hora do seu dia para os estudos (por meio da leitura Do Livro Didático), para o desenvolvimento das Autoatividades e para buscar conhecimento por meio de outras referências bibliográficas. Restando dúvidas, entre em contato com a tutoria interna e os professores disponíveis nos diversos canais de comunicação disponibilizados.
Bons estudos!
SIGA EM FRENTE!
1 INTRODUÇÃO
O mecanismo da herança é muito conveniente, mas tem suas limitações. Em particular, podemos herdar apenas uma classe, ao contrário, por exemplo, da língua C++, onde há herança múltipla.
Na linguagem Java, as interfaces resolvem parcialmente esse problema. Interfaces definem algumas funcionalidades que não possuem uma implementação específica, que é então implementada por classes que usam essas interfaces. E uma única classe pode aplicar muitas interfaces.
Aluno, no Tópico 1, abordaremos sobre tópicos relacionados aos conteúdos de interfaces como interfaces no mecanismo de retorno de chamada, bem como métodos de enumeração.
2 INTERFACES NO MECANISMO DE RETORNO DE CHAMADA
Para definir uma interface, use a palavra-chave da interface. Por exemplo:
Esta interface se chama Printable. Uma interface pode definir constantes e métodos que podem ou não ter uma implementação. Métodos sem implementação são semelhantes aos métodos abstratos das classes abstratas. Então, neste caso, um método que não tem implementação é declarado.
Todos os métodos de interface não possuem modificadores de acesso, mas, na verdade, o acesso padrão é público, já que o objetivo da interface é definir a funcionalidade para a classe implementar. Portanto, todas as funcionalidades devem estar abertas para implementação.
Para uma classe usar uma interface, você deve usar a palavra-chave implements:
Neste caso, a classe Book implementa a interface “Printable”. Deve-se ter em mente que, se uma classe usa uma interface, ela deve implementar todos os métodos da interface, como no caso do método implementado acima. Então, no método principal, podemos criar um objeto da classe Book e chamar seu método de impressão. Se uma classe não implementar alguns métodos de interface, então essa classe deve ser definida como abstrata, e suas classes descendentes não abstratas devem então implementar esses métodos.print
Ao mesmo tempo, não podemos criar diretamente objetos de interface. Sendo assim, o seguinte código não funcionará:
Uma das vantagens do uso de interfaces é que elas permitem que você adicione flexibilidade ao seu aplicativo. Por exemplo, além da classe de Livro, vamos definir outra classe que implementa a interface Imprimível:
A classe Book e a classe Journal estão relacionadas em implementar a interface Printable. Portanto, podemos criar objetos imprimíveis dinamicamente no programa como instâncias de ambas as classes:
O código acima apresenta a classe principal, com instâncias das classes logo abaixo. Tem-se uma interface “Printable” cuja o retorno é um “print”. A classe “Ebook” implementa a interface “Printable”. Por fim, abaixo tem-se a classe “Journal” que também implementa a classe “Printable”.
2.1 INTERFACES EM CONVERSÕES DE TIPOS
Tudo o que foi dito sobre conversão de tipo também é verdade para interfaces. Por exemplo, como a classe Journal implementa a interface Printable, uma variável do tipo Printable pode armazenar uma referência a um objeto do tipo Journal:
E se quisermos nos referir aos métodos da classe Journal, definidos não na interface Printable, mas na própria classe Journal, então precisamos realizar explicitamente uma conversão de tipo:
2.2 MÉTODOS PADRÃO
Anteriormente, antes do JDK 8, ao implementar uma interface, tínhamos que implementar todos os seus métodos em uma classe. E a interface em si só poderia conter definições de métodos sem uma implementação específica. JDK 8 adicionou funcionalidade, como métodos “default”. E agora as interfaces, além de definir métodos, podem ter uma implementação padrão deles, usada se a classe que implementa essa interface não implementar o método. Por exemplo, criaremos um método padrão na interface Imprimível:
O método padrão é um método regular sem modificadores marcados com a palavra-chave padrão. Então, na classe Journal, não temos que implementar este método, embora possamos substituí-lo:
2.3 MÉTODO ESTÁTICOS
Começando pelo JDK 8, métodos estáticos estão disponíveis nas interfaces e são semelhantes aos métodos da classe:
Para acessar o método estático da interface da mesma forma que no caso das classes, escreva o nome e o método da interface:
Neste caso, tem-se o resultado “Read printable”. O código acima simplesmente aciona o método “Printable” que retorna o resultado apresentado mencionado.
2.4 MÉTODOS PRIVADOS
Por padrão, todos os métodos na interface realmente têm um modificador público. No entanto, a partir do Java 9, também podemos definir métodos com o modificador privado na interface. Eles podem ser estáticos ou não estáticos, mas não podem ter uma implementação padrão.
Tais métodos só podem ser usados na interface em que são definidos. Ou seja, por exemplo, precisamos realizar algumas ações repetitivas na interface, e neste caso tais ações podem ser distinguidas em métodos privados:
O código acima, inicia com o método principal onde é criado um objeto “c” “Calculatable” e realizado somas desse objeto. As classes que são usadas para criar este objeto são declaradas logo abaixo, são elas “Calculatable” e “Calculation” que implementa a classe anterior.
2.5 CONSTANTES EM INTERFACES
Além dos métodos, as constantes estáticas podem ser definidas em interfaces:
Embora essas constantes também não tenham modificadores, mas por padrão eles têm um modificador de acesso, e, portanto, seu valor está disponível de qualquer lugar do programa.public static final.
Aplicação de constantes:
2.6 VÁRIAS IMPLEMENTAÇÕES DE INTERFACE
Se precisarmos aplicar várias interfaces a uma classe, todas elas serão listadas separadas por círios após a palavra implements:
2.7 MÉTODO ESTÁTICOS
Interfaces, como classes, podem ser herdadas:
Quando você usar esta interface, a classe Book precisará implementar tanto os métodos da interface BookPrintable quanto os métodos da interface base Printable.
2.8 INTERFACES ANINHADAS
Como as classes, as interfaces podem ser aninhadas, ou seja, podem ser definidas em classes ou outras interfaces. Por exemplo:
Ao usar tal interface, precisamos especificar seu nome totalmente qualificado junto com o nome da classe:
Como podemos ver logo acima, a classe “Journal” implementa a classe Printer. Logo abaixo, tem-se o método “print”, que retorna o “name” do tipo String declarado logo acima desta.
O uso da interface será semelhante aos casos anteriores:
2.9 INTERFACES COMO PARÂMETROS E RESULTADOS DE MÉTODOS
E como nas classes, as interfaces podem ser usadas como um tipo de parâmetro de método ou como um tipo de retorno:
O Código acima possui a classe principal onde é criado um objeto chamado “printable” e chamado duas vezes o método “read”. Logo abaixo, tem-se todos esses métodos, além da interface “Printable”, a classe “Book” e a classe “Journal”, ambas implementam a classe “Printable”.
O método read() toma um objeto de interface imprimível como um parâmetro, para que possamos passar tanto um objeto Book quanto um objeto Journal para este método.
O método createPrintable() retorna um objeto imprimível, para que possamos também retornar um objeto Book e um objeto Journal.
Saída do console:
2.10 RETORNOS DE CHAMADA
Uma maneira comum de usar interfaces em Java é criar um retorno de chamada. A essência do retorno é que criamos ações, invocadas por outras ações. Ou seja, algumas ações são causadas por outras ações. Um exemplo padrão é pressionar um botão. Quando apertamos um botão, realizamos uma ação, mas em resposta a esse clique, outras ações são desencadeadas. Por exemplo, clicar no ícone da impressora começa a imprimir um documento na impressora, e assim por diante.
Considere o seguinte exemplo:
Então aqui temos uma classe Button que pega um objeto de interface EventHandler no construtor e chama o método de execução desse objeto no método de clique.
Em seguida, você define a implementação do EventHandler como ButtonClickHandlerbutton.click(). E no programa principal, um objeto desta classe é passado para o construtor button. Assim, através do construtor, instalamos o manipulador de cliques no botão. E cada vez que o método é chamado, este manipulador será chamado.
Como resultado, o programa exibirá o seguinte resultado no console:
Mas parece que por que precisamos colocar todas as ações na interface e implementá-la, por que não escrevê-la imediatamente na classe Button?
O fato é que, no momento da definição da classe, nem sempre sabemos exatamente as ações que devem ser realizadas. Especialmente se a classe Button e a classe principal do programa estiverem em diferentes pacotes, bibliotecas e podem ser projetadas por diferentes desenvolvedores. Além disso, podemos ter vários botões — Botões de objetos e para cada objeto precisamos definir sua própria ação. Por exemplo, mudaremos a classe principal do programa:
Aqui temos dois botões - um para ligar/desligar a TV e o outro para imprimir na impressora (print). Em vez de criar classes separadas que implementam a interface EventHandler, aqui os manipuladores são especificados como objetos anônimos que implementam a interface EventHandler. Além disso, o manipulador de botões de TV armazena o estado adicional na forma de uma variável booleana.
Como resultado, o console exibirá o seguinte resultado:
E em suma, devo dizer que interfaces nesta capacidade são especialmente amplamente utilizadas em várias APIs gráficas - AWT, Swing, JavaFX, onde o processamento de eventos de objetos - elementos da interface gráfica é especialmente relevante.
3 MÉTODOS DE ENUMERAÇÃO
Além de alguns tipos e classes de dados primitivos, Java tem um tipo como “Enum” ou enumeração. As enumerações representam um conjunto de constantes logicamente relacionadas. A enumeração é declarada utilizando-se o operador de enum, seguido pelo nome da enumeração. Isso é seguido por uma lista separada de elementos de enumeração:
A enumeração representa, na verdade, um novo tipo, para podermos definir uma variável desse tipo e usá-la:
Enumerações podem ser usadas em classes para armazenar dados:
A enumeração em si é declarada fora da classe, contém quatro gêneros de livros. Além das variáveis usuais, a classe Book também contém uma variável do nosso tipo de enumeração. No construtor, também podemos atribuí-lo, como os campos habituais da classe.
Usando o interruptor “case” pode verificar que o valor bookType pertence a uma constante de enumeração específica.
3.1 MÉTODOS DE ENUMERAÇÃO
Cada enumeração tem um método de valores estáticos(). Ele retorna uma série de todas as constantes de enumeração:
O método ordinal() retorna o número de sequência de uma constante específica (a numeração começa com 0):
3.2 DESIGNERS, CAMPOS E MÉTODOS DE ENUMERAÇÃO
Enumerações, como classes regulares, podem definir construtores, campos e métodos. Por exemplo:
A enumeração Color define um campo de código privado para armazenar o código de cor, e ele é devolvido usando o método getCode. Um valor é passado através do construtor. Deve-se notar que o construtor padrão é privado, ou seja, tem um modificador privado. Qualquer outro modificador será considerado um erro. Portanto, só podemos criar constantes de enumeração usando o construtor dentro da enumeração.
Você também pode definir métodos para constantes individuais:
Como podemos ver, o código acima possui a classe principal onde é criado o objeto “op”, e impresso com a ajuda do “println” o método “action”. Logo abaixo, temos os métodos ENUM e SUM.
RESUMO DO TÓPICO 1
Neste tópico, você aprendeu:
Conhecimento acerca da usabilidade adequada de interfaces utilizando a Linguagem Java.
Utilização de retornos de chamadas em Programação Orientada a Objetos usando a Linguagem Java.
Entendimento sobre o uso de interfaces no mecanismo de retorno de chamada.
Utilização de métodos de enumeração em Programação Orientada a Objetos usando a linguagem Java.
AUTOATIVIDADE
1 Uma interface é uma construção, dentro da qual é costume descrever métodos públicos abstratos e constantes estáticas. Você pode usar a interface para especificar o que a classe que a implementa deve fazer, mas não como fazê-la. O método de implementação é escolhido pela própria classe. Interfaces não conseguem armazenar dados do estado. As interfaces são um dos mecanismos para implementar o princípio do polimorfismo. Sobre interfaces, assinale a alternativa CORRETA:
a) ( ) Para definir uma interface devemos usar a palavra reservada “new interface”.
b) ( ) Uma interface pode definir constantes e métodos que podem ou não ter uma implementação.
c) ( ) Métodos com implementação são semelhantes aos métodos abstratos das classes abstratas.
d) ( ) Todos os métodos de interface possuem modificadores de acesso.
2 Interfaces como classes podem ser declaradas com o nível de acesso public ou padrão. As variáveis de interface são padrão e esses modificadores são opcionais ao declará-los. Todos os métodos de interface são opcionais e esses modificadores também. Os métodos declarados não contêm corpos, e suas declarações terminam com ponto e vírgula. Ainda com base nas interfaces, analise as sentenças a seguir:
I- Todas as funcionalidades de classes devem estar abertas para implementação.
II- Somente a linguagem Java possui a ideia de uso de interfaces.
III- Deve-se ter em mente, que se uma classe usa uma interface, ela deve implementar todos os métodos da interface.
Assinale a alternativa CORRETA:
a) ( ) As sentenças I e II estão corretas.
b) ( ) Somente a sentença II está correta.
c) ( ) As sentenças I e III estão corretas.
d) ( ) Somente a sentença III está correta.
3 O mecanismo de retorno de chamadas é generalizado na programação. Em um retorno de chamada, o programador especifica as ações que devem ser realizadas sempre que um evento ocorrer. E não importa se você desenvolverá apenas softwares em java ou aplicativos android — os retornos de chamadas serão encontrados em todos os lugares. Conforme os princípios de retornos de chamadas, classifique V para as sentenças verdadeiras e F para as falsas:
( ) A essência do retorno é que criamos ações, invocadas por outras ações.
( ) O fato é que, no momento da definição da classe, devemos saber exatamente as ações que devem ser realizadas.
( ) No conceito de retorno de chamadas, algumas ações são causadas por outras ações.
Assinale a alternativa que apresenta a sequência CORRETA:
a) ( ) V – F – F.
b) ( ) V – F – V.
c) ( ) F – V – F.
d) ( ) F – F – V.
4 O conceito de uma função de retorno de chamada não existe em Java porque Java não tem conceito de ponteiro. No entanto, há situações em que se pode falar de um objeto de retorno de chamada ou de uma interface de retorno de chamada. Em vez de passar o endereço de memória de uma função, é passada uma interface que se refere à localização de uma função. Disserte sobre uma maneira comum de usar retorno de chamadas e interfaces em Java, citando um exemplo.
5 A partir do Java 1.5 tarefas onde são necessárias a criação de classes enumeradas foram solucionadas com a classe Enum. Essa classe traz modelos prontos para que o programador faça uso delas em situações de repetição. Disserte sobre o que é e os usos da classe enum na linguagem Java.
1 INTRODUÇÃO
As classes Java consistem em variáveis e métodos (também conhecidos como membros de instância). As variáveis Java, são dois tipos: tipos primitivos ou tipos de referência, como visto na unidade 1 deste ebook.
Um método em Java é um bloco de código que, quando chamado, executa ações específicas mencionadas nele. Por exemplo, se você tiver instruções escritas para desenhar um círculo no método, ele realizará essa tarefa. Você pode inserir valores ou parâmetros em métodos, e eles só serão executados quando chamados.
Acadêmico, no Tópico 2, abordaremos tópicos relacionados aos conteúdos de classes e seus métodos tais quais podemos listar as generalizações e limitações dos processos genéricos na programação orientada a objetos.
2 GENÉRICOS
Embora possamos criar uma classe comum que não herda outra classe, na verdade, todas as classes herdam da classe Object. Todas as outras classes, mesmo aquelas que adicionamos ao nosso projeto, são derivadas implicitamente da classe Object. Portanto, todos os tipos e classes podem implementar os métodos definidos na classe Object.
2.1 TO STRING
Use este método para obter uma representação de sequência deste objeto. Quando você tenta produzir uma representação de sequência de um objeto, você normalmente observará o nome totalmente qualificado da classe. Por exemplo:
O valor que se obtém (nesse caso) dificilmente pode servir como uma boa descrição de sequência do objeto. Portanto, o método é muitas vezes substituído. Por exemplo:
2.2 MÉTODO HASGCODE
O método hashCode permite especificar um valor numérico que corresponderá a este objeto ou ao seu código hash. Por este número, por exemplo, você pode comparar objetos.
Por exemplo, vamos derivar uma representação do objeto acima:
Mas podemos especificar nosso próprio algoritmo para determinar o código hash do objeto:
2.3 MÉTODO EQUALS
O método Equals compara dois objetos à igualdade:
O método “equals” toma como parâmetro um objeto de qualquer tipo, que lançamos então para o atual se eles são objetos da mesma classe.
A instância da instrução permite determinar se o objeto passado como parâmetro é um objeto de uma determinada classe, neste caso a classe Pessoa. Se os objetos pertencem a classes diferentes, então sua comparação não tem sentido, e falso é devolvido.
Então comparamos pelo nome. Se eles corresponderem, retornem verdadeiros, o que dirá que os objetos são iguais.
2.4 GENERALIZAÇÃO
Generalizações ou genéricos (tipos e métodos generalizados) permitem-nos fugir da definição rígida dos tipos utilizados. Considere o problema em que podemos precisar deles.
Digamos que definimos uma classe para representar uma Account bancária. Por exemplo, poderia ser assim:
A classe Account tem dois campos: id - um identificador de Account único e soma - o valor na Account.
Neste caso, o identificador é especificado como um valor inteiro, por exemplo, 1, 2, 3, 4 e assim por diante. No entanto, também não é incomum que valores de string sejam usados para o identificador. Ambos os valores numéricos e de cordas têm seus prós e contras. E no momento da redação da classe, podemos não saber exatamente o que é melhor escolher para armazenar o identificador — uma corda ou um número. Ou talvez esta classe seja usada por outros desenvolvedores que podem ter uma opinião sobre o assunto. Por exemplo, eles vão querer usar sua própria classe como o tipo de id.
E à primeira vista, podemos resolver esse problema da seguinte forma: definir o id como um campo do tipo Objeto, sendo uma superclasse universal e básica para todos os outros tipos:
Neste caso, tudo funciona bem. No entanto, então nos deparamos com o problema da segurança do tipo de dado. Por exemplo, no seguinte caso, teremos um erro:
O problema pode parecer artificial, pois neste caso vemos que uma string é passada para o construtor, sendo improvável que tentemos convertê-lo para o tipo int. No entanto, durante o processo de desenvolvimento, podemos não saber qual tipo representa o valor no id, e ao tentar obter um número neste caso, encontraremos a exceção de java.lang.ClassCastException.
Escrever sua própria versão da classe Account para cada tipo individual também não é uma boa solução, pois neste caso temos que nos repetir. Entretanto, esses problemas visavam eliminar generalizações genéricas. As generalizações permitem evitar especificar um tipo específico que será usado. Portanto, definimos a classe Account como generalizada:
Usando a letra T na definição de classe, especificamos que este tipo T será usado por esta classe. O parâmetro T em suportes angulares é chamado de parâmetro genérico porque você pode substituir qualquer tipo em vez disso. Ao mesmo tempo, ainda não sabemos que tipo será: String, int ou algum outro. Além disso, a carta é escolhida condicionalmente, pode ser qualquer outra letra ou conjunto de caracteres.class Account<T>T
Sendo assim, após declarar a classe, podemos aplicar o parâmetro genérico T: assim por diante, uma variável desse tipo é declarada na classe, sendo então atribuída um valor na construtora. O método retorna o valor da variável id, mas como essa variável é do tipo T, este método também retorna um objeto do tipo T: .getId()public T getId()
Nós usamos esta classe:
Quando você define uma variável de uma determinada classe e cria um objeto após o nome da classe, você deve especificar em suportes de ângulo qual tipo usar em vez do parâmetro genérico. Deve-se ter em mente que eles trabalham apenas com objetos, mas não trabalham com tipos primitivos. Ou seja, podemos escrever, mas não podemos usar o tipo int ou double, por exemplo, . Em vez de tipos primitivos, você deve usar classes de invólucro: Inteiro em vez de int, Duplo em vez de duplo, etc.Account<Integer>Account<int>
Por exemplo, o primeiro objeto usará o tipo String, ou seja, String será substituído em vez de T:
Neste caso, uma sequência é passada para o construtor como o primeiro parâmetro.
E o segundo objeto usa o tipo int (Inteiro):
2.5 INTERFACES GENERALIZADAS
Interfaces, como classes, também podem ser generalizadas. Vamos criar uma interface responsável generalizada e usá-la no programa:
Contudo, ao implementar tal interface, existem duas estratégias: a primeira estratégia é implementada, ao implementar um parâmetro de interface genérico, especifica um tipo específico, como neste caso o tipo String. Em seguida, a classe que implementa a interface é codificada para esse tipo.
A segunda estratégia apresenta uma definição de classe genérica que também usa o mesmo parâmetro genérico:
No código acima, podemos ver o método principal são criados dois objetos: "acc1", e “acc2”. Logo abaixo é impresso com o "println" os objetos chamando o método “getid”. Estes métodos e classes estão definidos logo abaixo.
2.6 MÉTODOS GENERALIZADOS
Além de tipos genéricos, você também pode criar métodos genéricos que usam parâmetros genéricos da mesma forma. Por exemplo:
Uma característica do método generalizado é o uso de um parâmetro genérico na declaração do método, afinal, modificadores e antes do tipo de retorno.
Então, dentro do método, todos os valores do tipo T representarão este parâmetro genérico.
Quando você chama tal método, o nome é precedido em suportes de ângulo para indicar qual tipo será passado no lugar do parâmetro genérico:
2.7 USO DE VÁRIOS PARÂMETROS GENÉRICOS
Também podemos definir vários parâmetros universais ao mesmo tempo:
Neste caso, o tipo de corda será passado para o local do parâmetro T, e o tipo Duplo será passado para o local do parâmetro S.
2.8 CONSTRUTORES GENERALIZADOS
Construtores, como métodos, também podem ser generalizados. Neste caso, os parâmetros genéricos também são indicados em suportes angulares antes do construtor:
Neste caso, o construtor toma um parâmetro de id que representa o tipo T. No construtor, seu valor é convertido em uma corda e armazenado em uma variável local.
3 LIMITAÇÕES DAS GENERALIZAÇÕES
Quando especificamos um parâmetro genérico para generalizações, por padrão pode representar qualquer tipo. No entanto, às vezes você quer um parâmetro para combinar apenas com alguns tipos limitados. Neste caso, aplicam-se restrições que permitem especificar a classe base que o parâmetro deve corresponder.
Para definir uma restrição, a palavra extends é usada após o parâmetro genérico, seguido pela classe base da restrição:
Por exemplo, neste caso, o limite para o parâmetro T em Transação é a classe Account. Ou seja, no lugar do parâmetro T, podemos passar na classe Account ou em uma de suas classes descendentes.
Observe o seguinte exemplo: considere o seguinte programa:
Neste caso, a classe “transação”, que representa uma operação de transferência de dinheiro entre duas “Accounts”, é digitada pelo parâmetro T, que tem a classe “Account” definida como uma restrição. Quando você cria um objeto de “transação”, dois objetos de Account são passados para seu construtor — duas Accounts entre as quais você deseja efetuar uma transferência e o valor da transferência.
É importante entender que, uma vez que estabelecemos tal limite, o compilador reconhecerá objetos do tipo T como objetos do tipo Account. Novamente, podemos chamar os métodos da classe Account em objetos do tipo T. E não seríamos capazes de fazer isso se não tivéssemos esse limite:
3.1 TIPOS GENERALIZADOS COM RESTRIÇÕES
Outras generalizações também podem atuar como restrições, que podem ter limitações:
Nesse caso, o limite para transação é o tipo Account, que é digitado pelo tipo String.
3.2 INTERFACES COMO ORGANIZAÇÕES
Interfaces também podem atuar como restrições. Nesse caso, o tipo passado para o local do parâmetro genérico deve implementar esta interface:
3.3 MÚLTIPLAS RESTRIÇÕES
Você também pode definir várias restrições ao mesmo tempo. Por exemplo, suponha que a classe transaction só pode funcionar com objetos que simultaneamente implementam a interface “responsável” e herdam da classe “pessoa”.
RESUMO DO TÓPICO 2
Neste tópico, você aprendeu:
Entendimento sobre o conceito de classes e sua importância na programação orientada a objetos em Java.
Entendimento sobre o conceito de métodos e sua importância na programação orientada a objetos em Java.
Conhecimento sobre o processo de generalização na programação orientada a objetos com Java.
Utilização adequada do processo de generalização em Java, incluindo as limitações de seu uso.
AUTOATIVIDADE
1 O JDK 5.0 introduziu os Genéricos Java visando reduzir os bugs e adicionar uma camada extra de abstração sobre os tipos. Escrevemos métodos genéricos com uma única declaração de método, e podemos chamá-los com argumentos de diferentes tipos. O compilador garantirá a correção de qualquer tipo que usarmos. Sobre métodos genéricos em Java, assinale a alternativa CORRETA:
a) ( ) Embora possamos criar uma classe comum que não herda, na verdade, todas as classes herdam da classe Object.
b) ( ) Todas as outras classes, mesmo aquelas que adicionamos ao projeto, são derivadas implicitamente da classe Main.
c) ( ) Nem todos os tipos e classes podem implementar os métodos definidos na classe Object.
d) ( ) Somente a linguagem Java possui o conceito de métodos genéricos.
2 Se você quiser representar qualquer objeto como uma sequência, o método toString() entrará em vigor. O método toString() retorna a representação string do objeto. Se você imprimir qualquer objeto, o compilador Java invoca internamente o método toString() no objeto. Assim, substituindo o método toString(), retorna a saída desejada, pode ser o estado de um objeto, etc. dependendo da sua implementação. Com base nas definições referentes ao método toString, analise as sentenças a seguir:
I- Use este método para obter uma representação de sequência deste objeto.
II- Somente a linguagem Java possui métodos toString.
III- Quando você tenta produzir uma representação de sequência de um objeto, normalmente observará o nome totalmente qualificado da classe.
Assinale a alternativa CORRETA:
a) ( ) As sentenças I e II estão corretas.
b) ( ) Somente a sentença II está correta.
c) ( ) As sentenças I e III estão corretas.
d) ( ) Somente a sentença III está correta.
3 O método “Java string class equals()” compara as duas strings dadas com base no conteúdo da string. Se qualquer personagem não for correspondido, ele retorna falso. Se todos os personagens forem combinados, ele retornará verdadeiro. O método String equals() substitui o método igual () da classe Objeto. Conforme os princípios do método “equals”, classifique V para as sentenças verdadeiras e F para as falsas:
( ) O método “equals” toma como parâmetro um objeto de qualquer tipo, que lançamos para o atual se eles são objetos da mesma classe.
( ) Se os objetos pertencem a classes diferentes, então sua comparação tem sentido, e a sentença verdadeira é devolvida.
( ) A instância da instrução permite determinar se o objeto passado como parâmetro é um objeto de uma determinada classe, neste caso a classe “pessoa”.
Assinale a alternativa que apresenta a sequência CORRETA:
a) ( ) V – F – F.
b) ( ) V – F – V.
c) ( ) F – V – F.
d) ( ) F – F – V.
4 Converter um tipo de subclasse em um tipo de superclasse é chamado de “generalização” porque estamos fazendo a subclasse se tornar mais geral e seu escopo está aumentando. Isso também é chamado de alargamento ou até o elenco. A ampliação é segura porque as aulas se tornarão mais gerais. Disserte sobre o processo de restrições aplicadas nas generalizações em Java.
5 Generalização é o processo de tirar propriedades e funcionalidades comuns de duas ou mais classes e combiná-las em outra classe que atua como a classe dos pais dessas classes ou o que podemos dizer da classe generalizada dessas classes especializadas. Quando este processo é desenvolvido usando alguns tipos de variáveis primitivas, ações devem ser tomadas. Neste contexto, disserte sobre os procedimentos realizados ao usar, por exemplo, variáveis inteiras e flutuantes (double, por exemplo).
1 INTRODUÇÃO
A generalização é um mecanismo para combinar classes semelhantes de objetos em uma única classe mais geral é um processo ascendente. Generalização e herança são abstrações poderosas para compartilhar semelhanças entre classes enquanto preservam suas diferenças.
Portanto, a generalização identifica semelhanças entre um conjunto de entidades. A semelhança pode ser de atributos, comportamento ou ambos. Generalização/especialização representa o conjunto de relacionamentos, um elemento essencial do paradigma orientado a objetos. A ideia principal em generalização/especialização é que uma classe de objeto (a especialização) é um subconjunto de outra (a generalização).
Aluno, no Tópico 3, abordaremos tópicos relacionados à discussão acima, os quais podemos listar o conceito de generalização, tipos de referências e objetos de cópias e por fim, o uso de registros em programação orientada a objetos.
2 TIPOS DE REFERÊNCIA E OBJETOS DE CÓPIAS
As classes generalizadas podem participar da hierarquia da herança: podem ser herdadas de outras “pessoas”, ou podem atuar como classes-base. Veremos diversas situações diferentes.
2.1 CLASSE GENERALIZADA BÁSICA
Ao herdar de uma classe generalizada, a classe descendente deve passar dados de tipo específicos na construção da classe base:
No construtor “DepositAccount”, você acessa o construtor da classe base, para o qual os dados do tipo são passados.
Use casos para classes:
Neste caso, a classe herdada pode adicionar e usar alguns parâmetros de seu próprio tipo:
Variantes de uso:
E mais uma situação — a classe de herdeiros pode não ser generalizada em tudo:
Aqui, ao herdar, você especifica explicitamente o tipo que será usado pelos construtores de classe base. Ao construtor da classe base é passado um valor desse tipo — neste caso, o número 5.
Caso de uso:
2.2 CLASSE HERDADA GENERALIZADA
Também pode haver uma situação onde a classe base é uma classe não genérica regular. Por exemplo:
Neste caso, o uso das construções da classe base no herdeiro ocorre como de costume.
2.3 CONVERTENDO TIPOS GENÉRICOS
Um objeto de um tipo generalizado pode ser lançado para outro tipo se eles usarem o mesmo tipo. Observemos a conversão de tipos usando as duas classes generalizadas a seguir:
Podemos lançar o objeto DepositAccount<Integer> para Account<Integer> ou DepositAccount<String> para Account<String>:
2.4 TIPOS DE REFERÊNCIA E OBJETOS DE CÓPIA
Ao trabalhar com objetos de classe, deve-se ter em mente que todos eles representam tipos de referência, ou seja, apontam para algum objeto localizado na memória. Para entender as possíveis dificuldades que podemos encontrar, olharemos um exemplo:
Aqui criamos dois objetos “pessoa” e atribuímos um ao outro. Mas, mesmo que estejamos apenas modificando o objeto bob, o objeto tom também é modificado. Porque uma vez atribuídos, eles apontam para a mesma área na memória onde os dados reais sobre o objeto “pessoa” e seus campos são armazenados.
EXEMPLO DO DIAGRAMA DA CLASSE PESSOA E SEUS OBJETOS
FONTE: o autor.
Para evitar esse problema, você deve criar um objeto separado para a variável bob, por exemplo, usando o “clone”.
Para implementar a clonagem, a classe “pessoa” deve usar a interface cloneable, que define o clone. Implementar esse método simplesmente retorna uma chamada de método para a classe pai — ou seja, a classe objeto, com uma conversão para o tipo “pessoa”.
Além disso, caso a classe não suporte a clonagem, o método deve lançar um CloneNotSupportedException, determinado usando a instrução de lançamentos.
Então, usando uma chamada para este método, podemos executar uma cópia:
No entanto, este método executa a cópia incompleta, adequado se o objeto clonado não contiver objetos complexos. Por exemplo, deixe a classe “livro” ter a seguinte definição:
Se tentarmos mudar o autor do livro, falharemos:
Neste caso, embora as variáveis book e book2 apontem para diferentes objetos na memória, esses objetos apontarão para o mesmo objeto.
EXEMPLO DO DIAGRAMA DA CLASSE BOOK
FONTE: o autor.
E neste caso, precisamos fazer uma cópia completa. Para isso, defina o método de clonagem da classe “author”:
E, em seguida, corrigir o método clone na classe “livro” da seguinte forma:
3 REGISTROS
Começando com Java 16, uma nova funcionalidade foi adicionada ao idioma — Registros. Os registros representam classes projetadas para criar contêineres de dados imutáveis. Além disso, os registros permitem simplificar o desenvolvimento reduzindo a quantidade de código.
JDK 16 é a implementação de referência do Java 16, a versão do Java padrão que segue o JDK 15, que chegou em 15 de setembro. JDK 16 é uma versão de recurso apoiada por apenas seis meses de suporte da Oracle. JDK 17, com vencimento em setembro, será um lançamento de suporte de longo prazo (LTS). Oracle enquadra JDK 16 como ponto de partida para migração para JDK 17, com usuários capazes de testar no JDK 16 antes de implantar no JDK 17. Os lançamentos do LTS são publicados a cada três anos.
Para definir as classes de registro, a palavra-chave “record” é usada, seguida pelo título e, em seguida, entre parênteses, a lista de campos de registro:
Consideremos o exemplo a seguir:
A classe “pessoa” define duas constantes, name e age:
Registros: este é um recurso de pré-visualização, um recurso cujo design, especificação e implementação estão completos, mas não é permanente, o que significa que o recurso pode existir de uma forma diferente ou não em futuros lançamentos JDK. Para compilar e executar código que contenha recursos de visualização, você deve especificar opções adicionais de linha de comando.
Seus valores são definidos no construtor. Não há como instalá-los novamente. Portanto, depois que o objeto “pessoa” for criado, eles armazenarão dados imutáveis.
Para obter os valores de nome e idade, são fornecidos os seguintes métodos:
Também substitui os métodos derivados de objetos: .equals()hashCode()toString()
No método, crie um objeto da classe “pessoa” e exala sua representação de texto para o console:main.
Como resultado, o console nos exibirá:
Agora vejamos o que a records nos oferece — definiremos um registro que será completamente semelhante à classe acima:
Os registros são definidos usando a palavra-chave “record”, seguido pelo título do registro. A seguir, uma lista de campos de registro. Ou seja, neste caso, dois campos são definidos — nome e idade. E por padrão, todos eles serão privados e terão um modificador final.
Você também criará um construtor com dois parâmetros, nome e idade. Em cada campo será criado automaticamente um método público de mesmo nome para obter o valor deste campo. Por exemplo, um método namename() é criado para um campo que retorna o valor do campo de name.
Desta forma, os métodos serão criados automaticamente. Em geral, este registro será completamente semelhante à classe acima, mas contém muito menos código.equals, hashCode e toString.
Se necessário, podemos chamar todos os métodos disponíveis:
3.1 CONSTRUTOR DE REGISTROS
No exemplo acima, utilizou-se o registro de formulário:
Que realmente criou o construtor:
Este construtor é chamado de canônico. Ele pega parâmetros, que também são chamados de campos de registro, e passa os valores dos parâmetros correspondentes para os campos.
No entanto, se necessário, podemos mudar a lógica do construtor. Então, podemos anular a lógica do designer. Por exemplo, e se uma idade inválida for transmitida ao criar um objeto? Consideramos esta situação sobrepondo a lógica do construtor:
Neste caso, se um valor inválido for aprovado, aplicamos algum valor padrão (o número 18). Como resultado, na verdade, teremos um construtor com a seguinte ação:
Como resultado, o programa exibirá o seguinte no console:
Podemos substituir completamente o construtor canônico:
Também podemos definir alguns outros construtores, mas todos eles têm que chamar o construtor canônico:
Aqui, é definido um construtor que aceita convencionalmente o primeiro nome, sobrenome e idade do usuário. Esse construtor chama o construtor canônico, passando-o valores para o nome e a idade: campos.this(firstName + " " + lastName, age)
Saída do console do programa:
3.2 MÉTODOS PREDOMINANTES
Também podemos substituir os métodos que o registro tem por padrão. E estes são métodos equals(), hashCode(), toString(), e métodos chamados como campos de registro, e que retornam os valores dos campos correspondentes.
Por exemplo, vamos substituir os métodos pessoa e:toString()name():
Saída de programas do console:
3.3 LIMITAÇÕES DOS REGISTROS
Tenha em mente que não podemos herdar a entrada recorde de outras classes e classes de registros. No entanto, as classes de registro podem implementar interfaces. Além disso, as classes de registro não podem ser abstratas.
Contudo, não pode definir explicitamente campos não estáticos e inicializadores registrados. No entanto, pode definir variáveis estáticas e inicializadores, bem como métodos estáticos e não estáticos:
LEITURA COMPLEMENTAR
PROGRAMAÇÃO ORIENTADA A OBJETOS
Renato Mattos
1 INTRODUÇÃO
O objetivo deste artigo é para desenvolvedores que desconhecem programação orientada a objeto, apresento as características básicas de programação orientada a objeto e espero dar o pontapé inicial para o leito no aprofundamento desse assunto. Programação orientada a objeto implementa o conceito de: abstração, classe, objeto, encapsulamento, herança e polimorfismo.
A orientação a objetos, apesar de estar fortemente presente hoje nas linguagens de programação, é um conceito antigo na computação, onde surgiu na área acadêmica.
A POO (Programação Orientada a Objetos) e a POE (Programação Orientada a Eventos) são facilmente confundidas, mas lembre-se a POO contém a POE, mas a POE não contém a POO, um objeto pode existir mesmo que não exista nenhum evento associado a ele, mas um evento não pode existir se não houver um objeto a ele associado.
2 ABSTRAÇÃO
Quando surgiram os primeiros computadores, a preocupação dos programadores era em busca da maior eficiência com o pouco uso de memória devido às limitações do hardware da época. Os programas consistiam em um único bloco, pois a divisão em vários blocos consumia mais recursos. Com a evolução do hardware a preocupação é na eficiência do desenvolvimento, isto é o tempo de trabalho dos programadores.
Para otimizar o tempo de desenvolvimento foi elaborado várias técnicas e metodologias, onde, em geral, é muito usada a estratégia de “dividir para conquistar”, ou seja, implica em resolver um grande problema dividindo-o em vários problemas menores. Esse método aumenta a potencialidade do reuso de código. Essa técnica é realizada por meio de modularização, o que além de resolver problemas complexos facilita o entendimento dos programas e viabilizar o reuso de códigos.
Assim entra a abstração, o que é um conceito fundamental para conseguir uma boa modularização. A abstração é fundamental para o raciocínio e resolução de problemas, devemos nos importar com os aspectos relevantes do problema em questão. Em programas bem modularizados, cada módulo representa uma abstração existente no contexto do problema. Essa técnica é empregada em sua forma mais simples por funções e procedimentos parametrizados, criando funções genéricas onde resolvem um subproblema.
Poderíamos falar só sobre abstração de dados, o que considero o mais importante para se construir programas bem modularizados e consequentemente orientados a objetos. O aspecto mais importante é como dado um problema criar sua abstração, ou seja, quais aspectos são relevantes e como representá-los. Conhecer as técnicas para implementar uma abstração é menos relevante, pois não garante a construção de um bom aplicativo.
O.O claro que o leitor já deve ter escutado esse termo e para muito pode ser assustador e complexo, no entanto, não é, a aplicação da técnica não é complexo e atualmente traz muitas vantagens para o desenvolvimento e esse conceito é o utilizado nas novas linguagens de programação. Onde temos o JAVA e .NET totalmente, orientados a objetos. E já temos bancos de dados também O.O, onde considero ser a nova arquitetura usada num futuro próximo.
Então, para os desenvolvedores manterem-se atualizados devem trabalhar com afinco, respirar fundo e cair de cabeça neste assunto. Espero que este artigo seja o pontapé inicial para muitos em programação orientada a objetos.
3 OBJETO
Um objeto é tudo aquilo que existe. Poderia ser um cliente, um carro, um relógio. Em termo computacional, um objeto é a representação de algo que existe. Você deve abstrair um "objeto" real para representá-lo computacionalmente, como, por exemplo, construir o objeto carro.
Os objetos são incrivelmente úteis, pois transformam a engenharia de software em algo como blocos de concretos para construção. Assim quem utiliza não precisa entender como o bloco foi construído e isso se chama encapsulamento.
Para entender melhor o que seria um objeto vamos usar como exemplo um rádio. Existem várias coisas que você pode fazer com esse objeto, como: ligar ou desligar, escutar o som, aumentar o volume, escolher uma estação. E você não precisa entender como tudo funciona para poder executar essas atividades.
Na engenharia de software os objetos funcionam basicamente da mesma maneira. Uma vez que tenha um objeto, você pode usar, pedir que ele faça coisas sem ter que entender como seus detalhes internos estão implementados.
Em geral, os objetos possuem as seguintes características:
identidade;
estado;
comportamento.
4 ENCAPSULAMENTO
O conceito básico por trás da orientação a objeto é o encapsulamento. O que é muito simples de entender. A todo o momento estamos trabalhando com "algo" encapsulado. Como, por exemplo, o uso do componente common dialog, usamos as propriedades e métodos desse componente, mas não vemos como está implementado. O uso de dll, ocx, api sempre utilizamos e não sabemos como está implementado, ou seja, o código está encapsulado.
5 MÉTODOS E PROPRIEDADES
Você utiliza os objetos através dos seus métodos e propriedades. Os métodos são algo que você pede para o objeto fazer como: aumentar o som do Rádio ou criar um cliente. As propriedades descrevem as características do objeto. Como, por exemplo: para um objeto pessoa o nome, endereço, telefone seriam as propriedades. E o que você pode fazer com essa pessoa seria um método.
6 VISIBILIDADE
Algumas partes do seu objeto serão privadas, enquanto outras serão públicas. Os métodos e propriedades públicas serão a interface do seu objeto com o usuário. É o que você espera que o desenvolvedor utilize do seu objeto.
7 CLASSE
Na construção de software é empregado o termo “classe”, o que, na verdade, seria o objeto abstrato construído computacionalmente. Quando o aplicativo é executado você utilizará essa classe dando assim "vida" ao objeto. Você constrói a classe onde fica seu código e fará uso dessa classe declarando uma variável dessa classe que quando executado o programa a variável será uma instância dessa classe onde chamamos de objeto. Em geral "criamos classes" e "instanciamos objetos". A criação de uma classe é feita em tempo de projeto, quando você está codificando o seu software, envolvendo a escrita do código-fonte. O objeto é criado em tempo de execução, quando é feita uma instância da classe é criado um objeto. A classe é como se fosse um molde, você constrói o molde e depois utiliza para elaborar diversos objetos.
8 HERANÇA
A herança é usada para criar objetos que têm "tudo que outro objeto tinha, mas também possui alguns detalhes próprios". A herança nos permite pegar uma classe e utilizar ou alterar suas propriedades e métodos, incluindo nossas propriedades, métodos.
Um exemplo seria, pegamos uma classe “pessoa”, onde possui como propriedades: nome, endereço, telefone, cpf, etc. Incluímos essa classe pessoa na nossa classe “funcionário”, dessa forma aproveitamos todas as propriedades de pessoa e incluímos as propriedades específicas de funcionário, como: data de admissão, cargo, salário, etc.
9 POLIMORFISMO
Conceito mais difícil de ser compreendido, no entanto, não é nada complicado entendê-lo. Significa que um objeto pode ser tratado como se fosse um tipo diferente de objeto, desde que seja com bom senso. Isso está muito relacionado com o conceito de herança. Podemos, por exemplo, tratar o objeto “funcionário” como sendo o objeto “pessoa”, pois o objeto "funcionário'' herda todas as propriedades e métodos do objeto “pessoa”. O contrário não pode ser feito, pois o objeto "funcionário'' possui características que o objeto “pessoa” não tem.
Dessa forma, quando se ouve falar de polimorfismo se trata de que um objeto pode se comportar como se fosse outro objeto.
Fonte:: MATTOS, R. Programação orientada a objetos. Disponível em: http://www.linhadecodigo.com.br/artigo/506/programacao-orientada-a-objetos.aspx. Acesso em: 30 ago. 2022.
RESUMO DO TÓPICO 3
Neste tópico, você aprendeu:
Entendimento sobre o conceito de herança e sua relevância na programação orientada a objetos.
Conhecimentos sobre o processo de generalização nas classes usando a linguagem Java.
Conhecimento sobre os tipos de referências e objetos de cópias usando a linguagem Java e programação orientada a objetos.
Uso de registros e tipos de registros usando programação orientada a objetos com linguagem Java.
AUTOATIVIDADE
1 Especialização e generalização são os mecanismos de hierarquia de subclasse e superclasse em um banco de dados relacional semelhante ao conceito de herança em Java. A ideia é simples, mas provoca confusão às vezes devido à sua organização incomparável entre o esquema relacional e a tecnologia orientada a objetos. Sobre generalização e classes genéricas, assinale a alternativa CORRETA:
a) ( ) Generalização e herança são abstrações poderosas para compartilhar semelhanças entre classes enquanto preservam suas diferenças.
b) ( ) A generalização é um processo descendente.
c) ( ) A generalização identifica diferenças entre um conjunto de entidades.
d) ( ) A semelhança pode ser de atributos, somente.
2 Generalização é o processo de abstração de baixo para cima, onde as diferenças entre as entidades conforme a característica comum, sendo possível generalizá-las em uma única superclasse. As entidades originais são, portanto, subclasses deste. Em termos mais simples, é apenas o inverso da especialização, sendo um processo de cima para baixo, enquanto a generalização é de baixo para cima. Com base nas definições de classes genéricas, analise as sentenças a seguir:
I- Ao herdar de uma classe generalizada, a classe descendente deve passar dados de tipo na construção da classe base.
II- Um objeto de um tipo generalizado pode ser lançado para outro tipo se eles usarem tipos diferentes.
III- Também pode haver uma situação onde a classe base é uma classe não genérica regular.
Assinale a alternativa CORRETA:
a) ( ) As sentenças I e II estão corretas.
b) ( ) Somente a sentença II está correta.
c) ( ) As sentenças I e III estão corretas.
d) ( ) Somente a sentença III está correta.
3 A clonagem de objetos refere-se à criação de uma cópia exata de um objeto. Ele cria uma instância da classe do objeto atual e inicializa todos os seus campos com exatamente o conteúdo dos campos correspondentes deste objeto. Conforme os princípios de clonagem em Java, classifique V para as sentenças verdadeiras e F para as falsas:
( ) Ao trabalhar com objetos de classe, deve-se ter em mente que todos eles representam tipos de referência, ou seja, apontam para algum objeto localizado na memória.
( ) Caso a classe não suporte a clonagem, o método deve lançar um NoPermission(), determinado usando a instrução de lançamentos.
( ) Para implementar a clonagem, a classe criada deve usar a interface cloneable, que define o clone.
Assinale a alternativa que apresenta a sequência CORRETA:
a) ( ) V – F – F.
b) ( ) V – F – V.
c) ( ) F – V – F.
d) ( ) F – F – V.
4 Em Java, um registro é um tipo especial de declaração de classe destinada a reduzir o código da caldeira. Os registros java foram introduzidos com a intenção de serem usados como uma maneira rápida de criar classes portadoras de dados, ou seja, as classes cujo objetivo é conter simplesmente dados e transportá-los entre módulos, também conhecidos como POJOs (Plain Old Java Objects) e DTOs (Data Transfer Objects). Disserte de forma introdutória sobre os registros e definição dessas classes em Java.
5 O registro foi introduzido no Java como um recurso de pré-visualização, sendo um recurso cujo design, implementação e especificação estão completos, mas não é uma adição permanente ao idioma, o que significa que o recurso pode ou não existir nas versões futuras da linguagem. Neste contexto, disserte sobre as definições de registros relacionando ainda com o uso de construtores.