JavaRush /Java Blog /Random-KO /한 인터뷰의 이야기: 흥미로운 질문들
GuitarFactor
레벨 30
Санкт-Петербург

한 인터뷰의 이야기: 흥미로운 질문들

Random-KO 그룹에 게시되었습니다
최근 한 대형 IT 기업의 인턴 자리 면접에 참석할 기회가 있었습니다. 한 인터뷰의 이야기: 흥미로운 질문들 - 1이번이 첫 번째 IT 인터뷰였는데 제 생각에는 흥미로웠습니다. 전체적으로 나는 3 시간 이상 "심문"을 받았습니다 (이전에 숙제와 사무실 컴퓨터 테스트가 이어졌습니다). 제가 질문에 틀린 대답을 해도 포기하지 않고, 유도 질문의 도움으로 제가 그것에 대해 생각하고 정답을 찾을 수 있게 해주신 면접관님께 경의를 표하고 싶습니다. 아래에서는 몇 가지 "스케치"를 제시하겠습니다. 제 생각에는 매우 흥미로운 질문이며, 그 중 일부는 Java의 특정 측면에 대한 더 깊은 이해를 제공했습니다. 아마도 이러한 것들이 어떤 사람들에게는 당연해 보일 수도 있지만, 이것이 유용할 사람들이 있을 것이라고 생각합니다. 아래 문구는 다음 글꼴로 강조 표시됩니다. 면접관 - 굵은 글씨 음성 해설 설명 및 내 생각 - 이탤릭체 내 답변 - 일반 글꼴 배경은 끝났으니 본론으로 들어가겠습니다.

스케치 1. “간단해 보이는 방법”

숫자 a를 숫자 b로 나눈 결과를 반환하는 메서드를 구현하는 방법을 적습니다. 면접관은 종이에 씁니다.
int divide(int a, int b) {
}
*나는 메소드 서명이 적힌 종이를 믿을 수 없다는 듯이 쳐다보았습니다. 문제는 무엇입니까?* 나는 다음과 같이 씁니다:
int divide(int a, int b) {
    return a/b;
}
이 방법에 문제가 있나요? *정말 멍청한 멍청이를 잡았습니다* 분명히 그렇지 않습니다. 다음은 타당한 질문입니다. b=0이면 어떨까요? *아, 이대로 계속하다간 이 사무실에서 쫓겨날 뻔!* 아, 물론이죠. 여기에는 int 유형의 인수가 있으므로 산술 예외가 발생합니다. 인수가 float 또는 double 유형인 경우 결과는 Infinity입니다. 이에 대해 우리는 무엇을 할 것인가? try/catch를 쓰기 시작했습니다.
int divide(int a, int b) {
    try {
        return a/b;
    } catch (Exception e) {
        e.printStackTrace();
        return ... // ??? what the hack?
    }
}
*반품하고 멈춥니다. 오류가 발생하면 뭔가를 반납해야 합니다. 하지만 이 “무엇”이 계산 결과와 어떻게 구별될 수 있습니까?* 우리는 무엇을 반환할 것입니까? 흠... 반환 변수의 유형을 Integer로 변경하고 예외가 발생하면 null을 반환합니다. 유형을 변경할 수 없다고 상상해 봅시다. 우리 어떻게든 나갈 수 있을까? 어쩌면 예외를 제외하고 다른 일을 할 수 있을까요? *여기에 있습니다* 호출 메소드로 전달할 수도 있습니다! 오른쪽. 어떤 모습일까요?
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();
    }
}
예외를 처리해야 합니까? 예, Divide 메서드에서 명시적으로 전달하기 때문입니다. (*제가 틀렸습니다! 정답에 도달하기 위한 면접관의 주요 질문은 다음과 같습니다*) 그리고 산술 예외(Arithmetic Exception) - 어떤 종류의 예외가 선택되었는지 또는 선택되지 않았습니까? 이는 런타임 예외이며 선택 취소됨을 의미합니다. *여기에 킬러 질문이 있습니다* 그래서 우리가 메소드 시그니처에 산술 예외 throw를 지정하면 확인된 예외가 된다는 것이 밝혀졌습니다. *으윽!* 아마도... 아뇨. 예, 사라졌습니다. 서명에 /unchecked 예외 발생/을 표시하면 메서드가 예외를 throw할 수 있다는 경고만 하지만 호출 메서드에서 이를 처리할 필요는 없습니다. 정리되었습니다. 실수를 피하기 위해 우리가 할 수 있는 다른 일이 있습니까? *생각해 본 후에* 예, (b==0)인지 확인할 수도 있습니다. 그리고 몇 가지 논리를 수행하십시오. 오른쪽. 따라서 우리는 3가지 방법으로 갈 수 있습니다:
  • 시도/잡기
  • throws - 호출 메서드로 전달
  • 인수 검사
이런 경우에는 divide어떤 방식이 더 바람직하다고 생각하시나요?
나는 예외를 호출 메서드에 전달하기로 선택합니다. 왜냐하면... int나누기 메서드에서는 이 예외를 처리하는 방법과 오류 발생 시 반환할 결과 유형이 명확하지 않습니다 . 그리고 호출 메서드에서는 b 인수를 사용하여 0과 같은지 확인합니다. 이 답변이 인터뷰 대상자를 만족시킨 것 같지만, 솔직히 이 답변이 명확한지 잘 모르겠습니다.))

스케치 2. “누가 더 빠르나요?”

ArrayList와 LinkedList의 차이점에 대한 표준 질문 후에 다음과 같은 결과가 나왔습니다. 요소를 중간에 삽입하는 것, ArrayList아니면 중간에 삽입하는 것 중 어떤 일이 더 빨리 일어날까요 LinkedList? *여기서 나는 뛰어내렸고, " 목록 중간에 요소를 삽입하거나 제거하는 데 사용합니다."와 같은 내용을 어디에서나 읽었던 것을 기억했습니다 . LinkedList집에서 JavaRush 강의를 다시 확인해도 다음과 같은 문구가 있습니다. “컬렉션 중간에 많은 요소를 삽입(또는 삭제)하려면 LinkedList. 그 밖의 모든 경우에는 - ArrayList.” 자동 응답* 을 사용하면 더 빨라집니다 LinkedList. 명확히 해주세요
  1. 중간에 요소를 삽입하려면 ArrayList일정한 시간에 목록에서 요소를 찾은 다음 삽입되는 요소의 오른쪽에 있는 요소의 인덱스를 선형 시간으로 다시 계산합니다.
  2. .. 먼저 LinkedList선형 시간의 중간에 도달한 다음 일정한 시간에 요소를 삽입하여 인접한 요소에 대한 링크를 변경합니다.
그래서 어느 것이 더 빠른지 밝혀졌습니다. 흠... 결과는 똑같네요. 그런데 언제 LinkedList더 빨라지나요? 목록의 전반부에 삽입하면 결과가 나타납니다. 예를 들어 맨 처음에 삽입하면 ArrayList맨 끝 부분까지 모든 인덱스를 다시 계산해야 하지만 LinkedList첫 번째 요소의 참조만 변경하면 됩니다. 도덕적: JavaRush에서도 쓰여진 모든 것을 말 그대로 믿지 마십시오!)

스케치 3. "등호와 해시코드가 없다면 우리는 어디에 있을까요!"

같음과 해시코드에 대한 대화는 매우 길었습니다. 이를 재정의하는 방법, 에 구현이 무엇인지 Object, 내부적으로 어떤 일이 발생하는지, 요소가 에 삽입될 때 HashMap등이 있었습니다. 제 생각에는 흥미로운 점 몇 가지만 말씀드리겠습니다. * 우리가 클래스를 만들었다고 상상해 보세요.
public class A {
    int id;

    public A(int id) {
        this.id = id;
    }
}
그리고 그들은 equalshashcode. 코드가 실행되면 어떤 일이 일어날지 설명하세요.
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*인터뷰 전에 기본 알고리즘, 복잡성 및 데이터 구조를 이해하는 데 며칠을 투자한 것은 좋은 일입니다. 많은 도움이 되었습니다. CS50에게 감사드립니다!*
  1. 클래스 A의 두 인스턴스 만들기

  2. 기본적으로 16개의 바구니가 있는 빈 맵을 만듭니다. equals키는 및 메소드가 재정의되지 않은 클래스 A의 객체입니다 hashcode.

  3. a1지도에 넣으세요 . 이를 위해 먼저 해시를 계산합니다 a1.

    해시는 무엇과 동일합니까?

    메모리에 있는 셀의 주소는 클래스의 메소드 구현입니다.Object

  4. 해시를 기반으로 바구니 지수를 계산합니다.

    어떻게 계산할 수 있나요?

    *아쉽게도 여기서는 명확한 답변을 드리지 못했습니다. 해시가 있고 버킷이 16개 있는 긴 숫자가 있습니다. 서로 다른 해시를 가진 객체가 버킷에 고르게 분산되도록 인덱스를 정의하는 방법은 무엇입니까? 인덱스가 다음과 같이 계산된다고 상상할 수 있습니다.

    int index = hash % buckets.length

    이미 집에서 소스 코드의 원래 구현이 약간 다르다는 것을 확인했습니다.

    static int indexFor(int h, int length)
    {
        return h & (length - 1);
    }
  5. 충돌이 없는지 확인하고 a1을 삽입합니다.

  6. 방법으로 넘어 갑시다 get. 인스턴스 a1과 a2는 서로 다른(메모리의 다른 주소) 것을 보장하므로 hash이 키에 대해 아무것도 찾을 수 없습니다.

    클래스 A 에서만 재정의하고 hashcode먼저 키 a1과 키 a2를 사용하여 해시맵에 쌍을 삽입하려고 하면 어떻게 될까요?

    그런 다음 먼저 원하는 바구니를 찾습니다 hashcode. 이 작업은 올바르게 수행됩니다. Entry다음으로 카트에 연결된 LinkedList의 개체를 살펴보고 키를 비교해 보겠습니다 equals. 왜냐하면 equals재정의되지 않은 경우 기본 구현은 클래스에서 가져옵니다 Object(참조별 비교). a1과 a2는 서로 다른 링크를 가지도록 보장되므로 삽입된 요소 a1을 "누락"하고 a2는 LinkedList에 새 노드로 배치됩니다.

    결론은 무엇입니까? HashMap재정의되지 않은 객체 의 키로 사용할 수 있습니까 equalshashcode?

    아니 당신은 할 수 없습니다.

스케치 4. “일부러 부수자!”

오류 및 예외에 대한 질문 후에 다음 질문이 이어졌습니다. 함수가 StackOverflow를 발생시키는 간단한 예제를 작성하세요. *그런 다음 재귀 함수를 작성하려고 할 때 이 오류가 나를 얼마나 괴롭혔는지 기억했습니다.* 이는 재귀 호출의 경우 재귀 종료 조건이 잘못 지정되면 아마도 발생할 수 있습니다. *이후 나는 조금 영리해지기 시작했고 결국 면접관의 도움을 받아 모든 것이 간단하다는 것이 밝혀졌습니다*
void sof() {
    sof();
}
이 오류는 와 어떻게 다릅니까 OutOfMemory? *여기서는 대답하지 않았습니다. 나중에 이것이 Java 메모리 Stack에 대한 지식에 관한 질문이라는 것을 깨달았습니다 Heap(객체에 대한 호출 및 참조는 스택에 저장되고 객체 자체는 힙 메모리에 저장됩니다). Stack따라서 다음 메소드 호출을 위해 메모리 에 더 이상 공간이 없고 , 메모리 OutOfMemory에서 객체를 위한 공간이 부족해지면 StackOverflow가 던져집니다 Heap.*
제가 기억하는 인터뷰의 순간들입니다. 결국 인턴십에 합격했기 때문에 앞으로 2.5 개월의 교육을 받고 모든 것이 잘되면 회사에 취직하게됩니다.) 관심이 있으면 이번에는 더 작은 기사를 쓸 수 있습니다. 다른 회사에서 면접을 본 간단하지만 예시적인 문제에 대한 분석입니다. 저는 이것이 전부입니다. 이 기사가 누군가가 지식을 심화하거나 정리하는 데 도움이 되기를 바랍니다. 모두들 즐겁게 배우세요!
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION