Esboço 1. “Um método aparentemente simples”
Escreva como você implementaria um método que retorna o resultado da divisão do número a pelo número b. O entrevistador escreve em um pedaço de papelint divide(int a, int b) {
}
*Olhei incrédula para o pedaço de papel com a assinatura do método. Qual é o truque?* Eu escrevo:
int divide(int a, int b) {
return a/b;
}
Há algum problema com este método? *Estou pegando um idiota muito idiota* Aparentemente não.. Em seguida vem uma pergunta legítima: E se b=0? *Uau, estou prestes a ser expulso deste escritório se continuar assim!* Ah, sim, claro. Aqui temos argumentos do tipo int, então uma Exceção Aritmética será lançada. Se os argumentos fossem do tipo float ou double, o resultado seria Infinity. O que vamos fazer sobre isso? Estou começando a escrever try/catch
int divide(int a, int b) {
try {
return a/b;
} catch (Exception e) {
e.printStackTrace();
return ... // ??? what the hack?
}
}
*Posso retornar e congelar: algo precisa ser retornado em caso de erro. Mas como distinguir este “algo” do resultado do cálculo?* O que retornaremos? Hm... eu mudaria o tipo da variável de retorno para Inteiro e em caso de exceção retornaria nulo. Vamos imaginar que não podemos mudar o tipo. Podemos de alguma forma sair? Talvez possamos fazer outra coisa com exceção? *Aí vem* Também podemos encaminhá-lo para o método de chamada! Certo. Como será?
int divide(int a, int b) throws ArithmeticException{
return a/b;
}
void callDivide(int a, int b) {
try {
divide(a, b);
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
É necessário tratar a exceção? Sim, porque o encaminhamos explicitamente a partir do método divide. (*Eu estava errado aqui! O que se segue são perguntas importantes do entrevistador para chegar à resposta correta*) E Exceção Aritmética - que tipo de exceção é essa - marcada ou desmarcada? Esta é uma exceção de tempo de execução, o que significa desmarcada. *Aí vem a pergunta matadora* Então acontece que, em suas palavras, se especificássemos lançamentos de exceção aritmética na assinatura do método, então ele se tornaria uma exceção verificada? *Ugh!* Provavelmente... não. Sim, desapareceu. Se indicarmos throws /exceção não verificada/ na assinatura, apenas avisaremos que o método pode lançar uma exceção, mas não é necessário tratá-la no método de chamada. Isso está resolvido. Há mais alguma coisa que possamos fazer para evitar erros? *Depois de pensar um pouco* Sim, também podemos verificar se (b==0). E execute alguma lógica. Certo. Então podemos seguir 3 caminhos:
- tentar/pegar
- throws – encaminhando para o método de chamada
- verificação de argumentos
divide
qual método você acha preferível? Eu escolheria encaminhar a exceção para o método de chamada, porque... no método divide não está claro como processar essa exceção e que tipo de resultado int
retornar em caso de erro. E no método de chamada, eu usaria o argumento b para verificar se é igual a zero. Parece que esta resposta satisfez o entrevistado, mas para ser sincero, não tenho certeza se esta resposta é inequívoca))
Esboço 2. “Quem é mais rápido?”
Após a pergunta padrão, como um ArrayList difere de um LinkedList, veio o seguinte: O que acontecerá mais rápido - inserir um elemento no meioArrayList
ou no meio LinkedList
? *Aqui eu pulei, lembrei que em todos os lugares eu lia algo como “use LinkedList
para inserir ou remover elementos do meio da lista”. Em casa até verifiquei novamente as palestras do JavaRush, tem uma frase: “se você vai inserir (ou deletar) muitos elementos no meio de uma coleção, então é melhor usar LinkedList
. Em todos os outros casos.... ArrayList
” Respondido automaticamente* Será mais rápido com LinkedList
. Esclareça por favor
- Para inserir um elemento no meio
ArrayList
, encontramos o elemento da lista em tempo constante, e a seguir recalculamos os índices dos elementos à direita do inserido, em tempo linear. - Para
LinkedList
.. Primeiro chegamos ao meio em tempo linear e depois inserimos um elemento em tempo constante, trocando links para elementos vizinhos.
LinkedList
mais rápido? Acontece que quando o inserimos na primeira metade da lista. Por exemplo, se você inseri-lo logo no início, ArrayList
terá que recalcular todos os índices até o final, mas LinkedList
só terá que alterar a referência do primeiro elemento. Moral: não acredite literalmente em tudo o que está escrito, mesmo em JavaRush!)
Esboço 3. “Onde estaríamos sem iguais e código hash!”
A conversa sobre equals e hashcode foi muito longa - como substituí-lo, qual implementação está emObject
, o que acontece nos bastidores, quando um elemento é inserido em HashMap
, etc. Vou apenas dar alguns pontos que são interessantes na minha opinião* Imagine que criamos uma classe
public class A {
int id;
public A(int id) {
this.id = id;
}
}
E eles não substituíram equals
e hashcode
. Descreva o que acontecerá quando o código for executado
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*É bom que antes da entrevista eu tenha passado alguns dias especificamente entendendo os algoritmos básicos, sua complexidade e estruturas de dados - ajudou muito, obrigado CS50!*
-
Crie duas instâncias da classe A
-
Criamos um mapa vazio, que por padrão possui 16 cestas. A chave é um objeto da classe A, no qual os métodos
equals
e não são substituídoshashcode
. -
Coloque
a1
no mapa. Para fazer isso, primeiro calculamos o hasha1
.A que será igual o hash?
O endereço de uma célula na memória é uma implementação de um método de uma classe
Object
-
Com base no hash, calculamos o índice da cesta.
Como podemos calculá-lo?
*Infelizmente, não dei uma resposta clara aqui. Você tem um número longo - um hash e há 16 buckets - como definir um índice para que objetos com hashes diferentes sejam distribuídos uniformemente pelos buckets? Eu poderia imaginar que o índice seja calculado assim:
int index = hash % buckets.length
Já em casa vi que a implementação original no código fonte é um pouco diferente:
static int indexFor(int h, int length) { return h & (length - 1); }
-
Verificamos se não há colisões e inserimos a1.
-
Vamos passar para o método
get
. É garantido que as instâncias a1 e a2 tenham um endereço diferentehash
(endereço diferente na memória), portanto não encontraremos nada para esta chaveE se o redefinirmos apenas
hashcode
na classe A e tentarmos inserir no hashmap primeiro um par com a chave a1 e depois com a2?Então primeiro encontraremos a cesta desejada
hashcode
- esta operação será realizada corretamente. A seguir, vamos começar a examinar os objetosEntry
do LinkedList anexado ao carrinho e comparar as chaves porequals
. Porqueequals
não é substituído, então a implementação base é retirada da classeObject
- comparação por referência. É garantido que a1 e a2 tenham links diferentes, então “perderemos” o elemento inserido a1 e a2 será colocado no LinkedList como um novo nó.Qual é a conclusão? É possível usar como chave em
HashMap
um objeto não substituídoequalshashcode
?Não, você não pode.
Esboço 4. “Vamos quebrar de propósito!”
Após as perguntas sobre Erro e Exceção, seguiu-se a seguinte pergunta: Escreva um exemplo simples onde uma função lançará StackOverflow. *Então me lembrei de como esse erro me atormentava quando eu estava tentando escrever alguma função recursiva* Isso provavelmente acontecerá no caso de uma chamada recursiva, se a condição para sair da recursão for especificada incorretamente. *Aí comecei a tentar algo inteligente, no final o entrevistador ajudou, acabou ficando tudo simples*void sof() {
sof();
}
Como esse erro é diferente de OutOfMemory
? *Não respondi aqui, só depois percebi que se tratava de uma pergunta sobre conhecimento Stack
de Heap
memória Java (chamadas e referências a objetos são armazenadas na pilha, e os próprios objetos são armazenados na memória Heap). Conseqüentemente, StackOverflow é descartado quando não há mais espaço na Stack
memória para a próxima chamada de método e OutOfMemory
o espaço para objetos acaba na Heap
memória*
Esses são os momentos da entrevista que me lembro. No final fui aceite para um estágio, pelo que tenho pela frente 2,5 meses de formação e, se tudo correr bem, um emprego na empresa) Se houver interesse, posso escrever outro artigo, desta vez mais pequeno, com uma análise de um problema simples, mas ilustrativo que me foi concedido em uma entrevista em outra empresa. Isso é tudo para mim, espero que este artigo ajude alguém a aprofundar ou organizar seus conhecimentos. Feliz aprendizado a todos!
GO TO FULL VERSION