Soluções — O Paradigma Orientado a Objetos e a Máquina Java
Aula 1 — Programação Orientada a Objetos
Dica(Resposta) Teste 1 — TRUE e o custo de mudança
- ✔ Verdadeiro — TRUE não é um critério de corretude funcional — é um critério de facilidade de mudança. Um código pode fazer exatamente o que deveria (passar em todos os testes) e ainda ser rígido, frágil e imóvel: qualquer mudança pequena pode forçar uma cascata de alterações em módulos dependentes, quebrar partes sem conexão lógica com o que foi alterado, ou não poder ser reaproveitado fora do contexto original. Um aluno que confunde “funciona hoje” com “é bem projetado” cairia nessa pegadinha.
- ✗ Falso — Exemplary não é sobre o código funcionar — é sobre o código encorajar quem o modifica a manter as mesmas qualidades de design, não degradá-las. Uma correção que funciona mas ensina um mau padrão (por exemplo, duplicar uma regra de negócio em vez de centralizá-la, ou ignorar validação) viola exatamente essa propriedade, mesmo passando todos os testes. O erro conceitual seria achar que “funcionar” e “ser Exemplary” são a mesma coisa.
- ✗ Falso — Reasonable exige proporcionalidade entre o custo de uma mudança e o benefício que ela traz — não um custo fixo e constante. Uma mudança pequena e de baixo benefício deve ser barata; uma mudança grande e de alto benefício pode custar mais, desde que a relação continue proporcional. Um código Reasonable que impusesse sempre o mesmo custo, batizando qualquer alteração (trivial ou não) com a mesma “epopeia”, estaria descrevendo justamente o sintoma de rigidez que o TRUE quer evitar.
- ✗ Falso — Os três sintomas são distintos e independentes. Rigidez é uma mudança forçando cascata em módulos dependentes; fragilidade é o sistema quebrar em lugares sem conexão lógica com a alteração; imobilidade é a impossibilidade de reaproveitar o código fora do contexto original por causa de dependências. Um sistema pode, por exemplo, deixar de ser rígido (uma mudança local não propaga mais) e continuar frágil (efeitos colaterais inesperados em partes distantes) ou imóvel (ainda amarrado a dependências que impedem reuso). Tratá-los como sinônimos é a falsa equivalência: resolver um sintoma não resolve os outros dois automaticamente.
Dica(Resposta) Teste 2 — Espaço do Problema vs. Paradigma Procedural
- ✗ Falso — O risco do paradigma procedural não vem de como os arquivos estão organizados — vem de dados serem estruturas passivas manipuladas livremente por funções externas, sem que nenhuma delas seja a “guardiã” da regra de negócio. Dividir o código em módulos ou arquivos diferentes não muda essa relação: qualquer uma dessas funções, em qualquer arquivo, ainda pode alterar os dados de forma inadvertida. O erro seria confundir organização de arquivos (um problema de estrutura de projeto) com unificação de dados e comportamento (o problema arquitetural real que a OO resolve).
- ✗ Falso — Colocar dados e métodos dentro do mesmo arquivo/classe é só união sintática. Se os atributos são
public, qualquer código externo pode alterá-los diretamente, ignorando os métodos que supostamente encapsulariam as regras — exatamente o mesmo risco do paradigma procedural (dados manipulados livremente de fora). A proposta real da OO exige que o objeto seja o único guardião do seu estado, o que depende de os atributos serem protegidos (private), não apenas de estarem “ao lado” dos métodos. - ✗ Falso — Essa é exatamente a descrição da visão procedural do exemplo (uma função externa calcula e sobrescreve o preço). Na visão orientada a objetos, quem calcula e decide se o desconto é aceitável é o próprio
Produto— você diz “aplique 10% de desconto em si mesmo” e o objeto pode até recusar. Atribuir esse comportamento de calcular-por-fora à OO troca exatamente a relação de causa e efeito que distingue os dois paradigmas. - ✗ Falso — O risco de dados manipulados livremente por código externo não desaparece só porque o sistema usa a sintaxe de classes — ele desaparece quando os atributos são protegidos (
private) e só podem ser alterados através de métodos que aplicam regras de negócio. Um sistema orientado a objetos com atributospublicreproduz, na prática, o mesmo risco do paradigma procedural: qualquer parte do código pode alterar o estado sem checar nenhuma regra. Usarclassnão é, por si só, encapsulamento.
Dica(Resposta) Teste 3 — Estado, Comportamento e Identidade
- ✗ Falso — Identidade e Estado são propriedades independentes. A Identidade é a garantia da JVM de que aquela instância é fisicamente única na memória (seu endereço na Heap), e essa garantia vale independentemente de como o Estado mude ao longo do tempo. O mesmo objeto
Produtocontinua sendo o mesmo objeto (mesma identidade) antes e depois deaplicarDescontoalterar seupreco— é precisamente por isso que um objeto pode evoluir seu estado sem nunca deixar de ser “ele mesmo”. Confundir mudança de estado com perda de identidade é o erro central deste item. - ✗ Falso — É a própria analogia usada na aula: dois pacotes idênticos de arroz, com o mesmo preço, são bens distintos no estoque real. Dois objetos
Produtocom exatamente o mesmonomeeprecocontinuam sendo duas instâncias fisicamente distintas na Heap, cada uma com seu próprio endereço de memória. Igualdade de estado (valores dos atributos) não implica identidade (unicidade física) — são propriedades ortogonais. - ✗ Falso — Comportamento é definido pelas ações que o objeto pode realizar — seus métodos, aquilo que ele faz diante de um estímulo. Um objeto sem nenhum método (só atributos) não tem como reagir a nada: ele é, na prática, uma estrutura de dados passiva, do tipo que o paradigma procedural manipula de fora. Nenhuma quantidade de Estado, por mais rico que seja, substitui a ausência de Comportamento — são propriedades diferentes, não intercambiáveis. No limite (zero métodos), o Comportamento é zero, independentemente do Estado.
- ✗ Falso — A aula distingue explicitamente identidade física de integridade lógica: um objeto assim é um “zumbi” no domínio (seu Estado é logicamente inválido), mas sua Identidade física — a unicidade do endereço na Heap garantida pela JVM — continua absolutamente intacta. O objeto não desaparece nem se funde com outro; ele apenas representa um estado inconsistente com as regras de negócio. Confundir “estado corrompido” com “identidade perdida” é exatamente o erro que este item testa.
Dica(Resposta) Teste 4 — Encapsulamento e Ocultamento de Informação
- ✗ Falso — Declarar o atributo
privateé só a metade sintática do encapsulamento; a proteção real vem de os métodos que o acessam aplicarem regras (invariantes). Um getter/setter trivial (setPreco(double p) { this.preco = p; }, sem oif (p >= 0)) permite que qualquer código externo grave um valor inválido através do setter — na prática, é equivalente a ter o atributopublic, porque não existe barreira lógica alguma, só uma barreira de sintaxe. A classeProdutoda aula é precisamente o contraexemplo:setPrecosó aceitap >= 0, e é essa validação (não oprivateisolado) que sustenta o invariante e reduz fragilidade. - ✗ Falso — A própria aula é explícita: Ocultamento de Informação não é uma medida de segurança contra invasores, é uma medida de engenharia contra a fragilidade do próprio código. Mesmo numa equipe inteiramente confiável, sem qualquer intenção maliciosa, o benefício do Information Hiding permanece: impedir que outras partes do sistema criem uma dependência física com a estrutura interna de um objeto, para que esse objeto possa mudar por dentro sem quebrar código externo. O risco que o IH mitiga é o do acoplamento acidental, não o de ataques — por isso ele continua útil mesmo sem nenhuma ameaça de segurança no horizonte.
- ✗ Falso — Esse é exatamente o antipadrão Ask, Don’t Tell — extrair dados do objeto (
getSaldo()) para que o código externo tome a decisão e depois grave o resultado de volta (setSaldo(...)). O princípio Tell, Don’t Ask propõe o oposto: delegar a decisão para dentro do objeto (por exemplo, um métododebitar(valorCompra)que ele mesmo executa e cujas invariantes ele mesmo protege). Usar o jargão correto (“está aplicando Tell, Don’t Ask”) para descrever exatamente o padrão contrário é a armadilha deste item. - ✗ Falso — A autonomia do objeto depende de ele ser o único caminho para alterar seu próprio estado — e isso só é garantido quando os atributos são protegidos (
private). Seprecofossepublic, qualquer código externo poderia executarproduto.preco = -50diretamente, ignorando completamenteaplicarDesconto()e qualquer regra que ele implemente. A mera presença de métodos ao lado de atributos públicos não impede o bypass; a classe volta a se comportar como uma estrutura procedural, mesmo compilando como umaclassJava.
Dica(Resposta) Teste 5 — Classe vs. Objeto/Instância
- ✗ Falso —
new Produto(...)cria uma instância — um bloco físico na Heap com identidade própria e valores concretos — não uma nova cópia da classe. A classe (seu bytecode, seus métodos) é carregada uma única vez no Method Area/Metaspace peloClassLoader, independentemente de quantas equipes, ou quantas vezes, o códigonew Produto(...)seja executado. Todas as instâncias, de qualquer equipe, compartilham exatamente o mesmo código executável já carregado. - ✗ Falso — O bytecode dos métodos é carregado uma única vez no Method Area/Metaspace, independentemente de quantas instâncias existam — seja 1, seja 10.000. O que cresce proporcionalmente ao número de instâncias é a memória da Heap, onde cada objeto guarda seus próprios dados isolados (nome, saldo, etc. de cada
Cliente). Confundir a área que cresce com o número de instâncias (Heap) com a área do código compartilhado (Method Area) é o erro estrutural que este item testa. - ✗ Falso — O Metaspace é memória RAM associada a um processo da JVM em execução, não um armazenamento persistente. Quando a JVM é encerrada, todo o conteúdo do Metaspace daquela execução — incluindo o bytecode carregado — desaparece junto com o processo. Ao iniciar uma nova execução (mesmo do mesmíssimo programa), o
ClassLoaderprecisa ler novamente o arquivo.classdo disco e recarregar as classes na memória da nova JVM. Isso reforça o ponto da aula de que a classe “existe na memória para fornecer as instruções” apenas enquanto a JVM daquela execução estiver viva — não é um cache permanente entre execuções. - ✗ Falso — A aula é explícita: no Method Area (Metaspace) ficam “o bytecode dos métodos e os membros
static”. Um contadorstaticpertence à classe como um todo, não a nenhuma instância específica — por isso ele é armazenado junto com o restante dos dados estáticos da classe, na mesma área de memória do bytecode, e não dentro de nenhum objeto individual na Heap. Se o contador vivesse dentro de uma instância, cadaClienteteria sua própria cópia do contador, o que contradiz a própria natureza de um campostatic(compartilhado por todas as instâncias).
Dica(Resposta) Teste 6 — JVM, Bytecode e Portabilidade (WORA)
- ✗ Falso — A compilação em Java ocorre em duas etapas distintas: primeiro o
javactransforma o.javaem Bytecode (.class), independente de plataforma; só depois, em tempo de execução, a JVM mapeia esse bytecode para instruções nativas do ambiente hospedeiro (com ajuda do JIT). Se ojavaccompilasse direto para código nativo de uma CPU específica, o.classgerado deixaria de ser portável, e o lema Write Once, Run Anywhere simplesmente não existiria — é justamente a existência dessa camada intermediária de bytecode que sustenta a portabilidade. - ✗ Falso — A garantia de WORA depende de que exista “uma JVM compatível” — ou seja, uma implementação que respeite corretamente a especificação do bytecode. O Bytecode em si é só uma sequência de instruções independente de plataforma; ele não executa sozinho, e sua interpretação correta depende inteiramente da JVM que o lê. Uma JVM com bug que interpreta um opcode de forma diferente do especificado produzirá um resultado diferente naquele ambiente, quebrando a portabilidade — a garantia de WORA é condicional à conformidade da JVM, não uma propriedade absoluta e automática do arquivo
.class. - ✗ Falso — O Bytecode não é código de máquina de nenhuma arquitetura específica — mesmo que o processador seja idêntico nas duas máquinas, o sistema operacional não sabe interpretar instruções de bytecode Java diretamente. É a JVM, não o hardware, que faz a ponte entre o
.classe as instruções nativas do ambiente. Sem uma JVM compatível instalada no servidor Linux, o arquivo.classsimplesmente não executa, independentemente de a CPU ser igual à da máquina onde foi compilado — confundir compatibilidade de hardware com a necessidade de runtime é o erro central deste item. - ✗ Falso — O
javacproduz Bytecode, não código de máquina — o sistema operacional não sabe executar Bytecode diretamente, ele só executa instruções nativas do processador. A JVM é o intermediário obrigatório que lê o Bytecode e o traduz (com ajuda do JIT) para instruções que o hardware realmente entende. No caso limite de não haver nenhuma JVM disponível, o.classnão tem como ser executado, ponto — não existe um caminho alternativo direto entre bytecode e sistema operacional.
Dica(Resposta) Teste 7 — O Compilador JIT
- ✗ Falso — O JIT não compila tudo de antemão — ele faz profiling ativo do programa em execução, identifica os hotspots (métodos e laços chamados com altíssima frequência) e só então os traduz para código nativo, com base no comportamento real observado. Compilar o programa inteiro no início seria, na prática, uma compilação AOT (ahead-of-time) tradicional, perdendo justamente a vantagem do JIT: otimizar com informação que só existe depois que a aplicação já está rodando e mostrando seu comportamento real.
- ✗ Falso — Hotspots são definidos exatamente pelo oposto: métodos e laços chamados com altíssima frequência. Um método executado uma única vez está no extremo contrário do espectro — ele não gera dados suficientes de profiling para justificar o custo de compilá-lo para código nativo, e continua sendo simplesmente interpretado. Priorizar métodos raramente executados desperdiçaria o próprio propósito do JIT, que é investir esforço de compilação onde o retorno (tempo de execução economizado) é maior.
- ✗ Falso — O JIT precisa de tempo de execução para fazer profiling, identificar os hotspots e só então compilá-los — esse processo tem um custo inicial (“aquecimento”) que só se paga ao longo de uma execução suficientemente longa para os hotspots serem executados muitas vezes após a compilação. Numa aplicação que termina em poucos milissegundos, não há tempo para esse ciclo de profiling e compilação compensar; a aplicação já teria terminado antes de qualquer hotspot ser otimizado. É justamente por isso que a aula associa a vantagem do JIT a “aplicações servidoras de longa duração” — o cenário contrário (vida muito curta) favorece a compilação estática (AOT), que já entrega código nativo desde o primeiro instante.
- ✗ Falso — O JIT compila seletivamente apenas os hotspots — os trechos identificados como muito frequentes. O restante do código (caminhos raros, tratamento de casos excepcionais, métodos pouco usados) continua sendo executado por interpretação do Bytecode. A execução de um programa Java é, a qualquer momento, um modelo híbrido — parte interpretada, parte nativa —, nunca um binário inteiramente compilado como sugere a afirmação. Usar corretamente o jargão (“compila os hotspots”) para concluir algo estruturalmente errado (“tudo passa a ser nativo”) é a armadilha deste item.
Dica(Resposta) Teste 8 — Stack, Heap e Alcançabilidade
- ✗ Falso — Todo objeto criado com
new, em qualquer método, é alocado fisicamente na Heap — essa regra não depende de qual método faz a criação, nem de onde ele foi chamado. O que iria para a Stack, dentro deenviarEmailConfirmacao, seria apenas a variável de referência local que aponta para esse novo objetoEmail(semelhante a comop1guarda o endereço doPedido) — o objetoEmailem si, com seus próprios dados, ficaria na Heap, exatamente como oPedidodo exemplo original. - ✗ Falso —
newsempre aloca o objeto na Heap, independentemente de a variável que o referencia ser local oustatic. O que muda quando a referência éstaticé apenas onde a referência em si fica armazenada — junto aos membros estáticos da classe, no Method Area/Metaspace — e por quanto tempo ela permanece uma raiz de alcançabilidade (uma GC Root praticamente eterna), não onde o objeto referenciado é fisicamente guardado. Confundir a localização da referência com a localização do objeto é exatamente o erro que este item testa (e é a mesma confusão que está por trás da retenção obsoleta comcacheInfinito, discutida mais adiante na aula). - ✗ Falso — É o efeito exatamente oposto. Uma variável local desaparece (junto com seu frame na Stack) ao fim do método, deixando o objeto que ela referenciava potencialmente órfão e, se nenhuma outra referência existir, elegível para coleta. Já uma variável
staticé ela mesma uma GC Root, que persiste enquanto a classe estiver carregada — bem além do término de qualquer método. Sep1fossestatic, oPedidocontinuaria alcançável (e, portanto, NÃO elegível para coleta) mesmo depois deprocessarPedido()terminar, exatamente o mecanismo de retenção obsoleta discutido com ocacheInfinitomais adiante na aula. - ✗ Falso — Alcançabilidade não é sobre “existir alguma referência apontando para o objeto” — é sobre existir um caminho a partir de uma GC Root até o objeto. Se B não é alcançável a partir de nenhuma raiz, então o caminho de qualquer GC Root até A (que passaria necessariamente por B) também está quebrado, e A é igualmente inalcançável, mesmo tendo uma referência (a de B) apontando para ele. Esse é o cenário clássico de uma “ilha” de objetos que se referenciam mutuamente mas estão desconectados de qualquer raiz — todos nessa ilha são elegíveis para coleta.
Dica(Resposta) Teste 9 — Retenção Obsoleta e Recursos do Sistema
- ✗ Falso — O Java evita o memory leak clássico (ponteiro perdido, memória inacessível e irrecuperável), mas não é imune a acúmulo indevido de objetos — ele sofre de retenção obsoleta: uma coleção
static, por exemplo, mantém referências alcançáveis para objetos que a lógica de negócio já descartou, e a JVM não tem como saber que eles não servem mais para nada. O GC só coleta o que está inalcançável; objetos ainda referenciados, mesmo que inúteis, nunca são coletados. “Qualquer forma” é o exagero que torna a afirmação falsa — o Garbage Collector resolve um tipo específico de problema, não todo acúmulo possível de memória. - ✔ Verdadeiro — A causa raiz da retenção obsoleta não é a mera existência de uma coleção
static(que é sempre uma GC Root, viva enquanto a classe estiver carregada) — é o fato de ela reter referências para objetos que a lógica de negócio já não precisa mais. Se cadaPedidofosse removido do mapa logo depois de ser usado, ocacheInfinitocontinuaria sendo uma GC Root eterna, mas apontando para um mapa vazio (ou só com pedidos ainda em uso) — nenhum objeto obsoleto ficaria retido. Isso mostra que o problema está na política de limpeza (ou na ausência dela), não na naturezastaticda estrutura em si. - ✗ Falso — Tornar-se elegível para coleta (ficar inalcançável) e ser efetivamente coletado pelo GC são dois momentos diferentes, e o GC age em tempo não-determinístico — pode levar um tempo arbitrário até de fato coletar o objeto, e mesmo a coleta em si não garante que qualquer recurso do sistema operacional associado seja liberado no mesmo instante. É exatamente por essa imprevisibilidade que o GC não é a ferramenta adequada para liberar arquivos, sockets ou conexões de banco: recursos escassos do sistema operacional exigem liberação determinística, via
try-with-resources, e não podem depender do momento (incerto) em que o coletor decidir agir. - ✗ Falso — O
try-with-resourceschamaclose()sempre, ao final do bloco — com sucesso ou com exceção. A linguagem injeta um “finally” invisível que garante o fechamento determinístico do recurso independentemente de como o bloco terminou. Achar queclose()só entra em ação diante de falhas inverte o próprio motivo de existir do try-with-resources: ele existe para garantir que o recurso seja sempre devolvido ao sistema operacional, não apenas quando algo dá errado.
Dica(Resposta) Teste 10 — Modificadores de Acesso
- ✗ Falso — A aula é explícita: tentar acessar um membro
privatede fora da classe “não gera um aviso, gera um erro de compilação”. Sedepositarpassasse a serprivate, qualquer código externo que o chamasse deixaria de compilar imediatamente — o build falharia antes mesmo do programa rodar. Não existe uma fase intermediária em que o código compila mas “falha silenciosamente” em tempo de execução; o compilador Java fiscaliza o acesso a membrosprivateestaticamente, no momento da compilação. - ✗ Falso — Se
saldoépublic, código externo pode atribuir qualquer valor diretamente ao atributo, sem passar por nenhum método da classe — nem pordepositar(), nem porvalidarSaldo(), nem por nenhuma outra “alfândega” interna. A existência de um método privado de validação não tem efeito nenhum sobre esse caminho de acesso direto, porqueconta.saldo = -5000nunca chama método algum. A proteção contra essa escrita inválida depende exclusivamente desaldoserprivate— é isso, e só isso, que força toda alteração a passar pelos métodos públicos da classe. - ✔ Verdadeiro — O modificador
privaterestringe o acesso ao escopo da própria classe declarante, e essa restrição não é afetada por organização em pacotes: mesmo duas classes no mesmíssimo pacote não conseguem acessar diretamente o atributoprivateuma da outra (diferentemente do modificador default/package-private, que não foi discutido na aula, mas que teria esse comportamento mais permissivo). A “pista falsa” deste item é sugerir que estar no mesmo pacote poderia abrir uma exceção paraprivate— não abre. - ✗ Falso —
privateé uma restrição aplicada pelo compilador ao código-fonte comum — é ojavacque rejeitaobjeto.atributoPrivadofora da classe, gerando erro de compilação. A API de reflection, porém, contorna essa barreira: comField.setAccessible(true), é possível ler e até alterar atributosprivatede outra classe em tempo de execução, sem erro de compilação nem, por padrão, bloqueio da JVM. Isso conecta com o ponto já feito na aula sobre Ocultamento de Informação:privateé uma ferramenta de engenharia contra o acoplamento acidental do código-fonte comum, não uma barreira de segurança absoluta e impenetrável em qualquer circunstância.
Dica(Resposta) Teste 11 — Escopo, Sombreamento e
this
- ✔ Verdadeiro — O sombreamento é uma regra geral de resolução de escopo — ocorre sempre que um identificador declarado num escopo mais interno tem o mesmo nome de um identificador do escopo mais externo, e não é exclusivo ao caso parâmetro-versus-atributo discutido na aula. Uma variável local declarada dentro do corpo do construtor (por exemplo,
String preco = "temp";, seprecotambém fosse o nome de um atributo da classe) sombreia esse atributo exatamente pela mesma regra: o compilador prioriza sempre o escopo mais interno. O caso do parâmetro é só o exemplo mais comum, não o único gatilho possível. - ✗ Falso — É exatamente o erro lógico descrito na aula:
nome = nome;, semthis, resolve as duas ocorrências para o parâmetro local (o escopo mais interno) — a linha atribui a variável local a ela mesma e “morre” inteiramente na Stack. O atributo da classe (na Heap) nunca é tocado e permanece com seu valor padrão (null, para umaString). Achar que a atribuição “de algum jeito” alcança o atributo, só porque os nomes coincidem, é precisamente a armadilha que motiva a existência dethis.nome = nome;. - ✗ Falso —
thisexiste para desambiguar um conflito de nomes entre escopos — ele resolve o problema do sombreamento, não é uma exigência sintática universal. Quando não há nenhum parâmetro ou variável local com o mesmo nome do atributo naquele escopo, referenciar o atributo pelo nome simples compila e funciona perfeitamente, porque não existe ambiguidade nenhuma para o compilador resolver. Tratarthis.como obrigatório em toda e qualquer referência a atributo é generalizar demais o papel específico quethisdesempenha. - ✗ Falso —
thisnão é uma referência global compartilhada pelo método — é vinculado individualmente a cada chamada, de acordo com a instância sobre a qual o método foi invocado. Quandop1.aplicarDesconto(10)ep2.aplicarDesconto(10)executam (mesmo simultaneamente, em threads diferentes), cada execução tem seu própriothisapontando para a respectiva instância — a chamada em uma thread alterap1, a chamada na outra alterap2, cada um isoladamente. É exatamente esse mecanismo (já discutido na aula) que garante que rodar o mesmo bytecode não faça uma instância “vazar” alterações para a outra; achar quethisé compartilhado inverteria essa garantia.
Dica(Resposta) Teste 12 — Passagem de Parâmetros: Primitivos vs. Referências
- ✗ Falso — Um array é um tipo de referência, não um primitivo — o “valor” copiado ao passá-lo como parâmetro é apenas o endereço de memória (a referência), exatamente como acontece com
Produto p. Os 10 milhões de elementos continuam armazenados numa única cópia física, na Heap; o parâmetro do método recebe só uma cópia do “controle remoto” que aponta para esse bloco de memória. É exatamente essa distinção fina — cópia da referência, não do conteúdo — que permite passar objetos e coleções pesadas para métodos sem duplicar memória a cada chamada. - ✗ Falso — Para tipos primitivos, o “valor” copiado é o próprio dado — a JVM cria uma cópia isolada do número na Stack do método chamado. Multiplicar essa cópia por 2 altera só a variável local dentro do método; a variável original do chamador, sendo uma cópia física separada e independente, permanece com seu valor original depois que a chamada retorna. Esse é exatamente o “isolamento total” dos tipos primitivos descrito na aula, em contraste com o comportamento dos tipos de referência.
- ✔ Verdadeiro — Isso combina duas ideias da aula: a Identidade de um objeto é física e independente do seu Estado (dois objetos com valores idênticos ainda são instâncias distintas, cada uma com seu próprio endereço na Heap), e passar um objeto para um método sempre copia o valor da referência — o endereço guardado na variável. Como TV e Geladeira são objetos distintos, seus endereços na Heap são necessariamente diferentes, então cada parâmetro do método recebe uma cópia de um endereço diferente, independentemente de os valores de
nomeeprecocoincidirem ou não. - ✗ Falso — A ordem das operações importa porque
prodé uma variável que pode ser reapontada. No exemplo original da aula,prod.setPreco(999.0)executa primeiro, enquantoprodainda guarda o endereço da TV — por isso a TV é alterada e a mudança é vista por quem chamou. Se a reatribuiçãoprod = new Produto("Geladeira", ...)ocorresse antes,prodpassaria a apontar para o novo objeto Geladeira, e a chamada seguinteprod.setPreco(999.0)alteraria a Geladeira, não a TV — a TV original do chamador permaneceria com seu preço original, intocada. Isso mostra que o resultado depende de qual objetoprodestá apontando no momento exato de cada chamada, não apenas de quais linhas de código existem no método.