JavaRush /Java Blog /Random-KO /Java 개발자 인터뷰의 질문과 답변을 분석합니다. 12부

Java 개발자 인터뷰의 질문과 답변을 분석합니다. 12부

Random-KO 그룹에 게시되었습니다
안녕하세요! 아는 것이 힘이다. 첫 번째 인터뷰 전에 더 많은 지식을 갖고 있을수록 면접에 대한 자신감이 더 커질 것입니다. Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 1충분한 지식이 있으면 혼동하기 어려울 것이며 동시에 면접관을 즐겁게 놀라게 할 수 있을 것입니다. 따라서 오늘은 더 이상 고민하지 않고 Java 개발자를 위한 250개 이상의 질문을 검토하여 이론적 기반을 계속 강화할 것입니다 . Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 2

103. 상속에서 예외를 확인하는 규칙은 무엇입니까?

질문을 올바르게 이해하면 상속 중 예외 작업에 대한 규칙에 대해 질문하고 있으며 그 내용은 다음과 같습니다.
  • 하위 항목/구현에서 재정의되거나 구현된 메서드는 상위 클래스/인터페이스 메서드의 예외보다 계층 구조에서 더 높은 확인된 예외를 발생시킬 수 없습니다.
즉, IOException을 발생시키는 메소드가 있는 특정 Animal 인터페이스가 있는 경우입니다 .
public  interface Animal {
   void voice() throws IOException;
}
이 인터페이스 구현에서는 보다 일반적인 예외(예: Exception , Throwable )를 발생시킬 수 없지만 FileNotFoundException 과 같은 하위 예외로 대체할 수 있습니다 .
public class Cat implements Animal {
   @Override
   public void voice() throws FileNotFoundException {
// некоторая реализация
   }
}
  • 서브클래스 생성자는 해당 throws 블록 에 객체가 생성될 때 호출되는 슈퍼클래스 생성자에서 발생하는 모든 예외 클래스를 포함해야 합니다.
Animal 클래스의 생성자가 많은 예외를 발생시킨다고 가정해 보겠습니다 .
public class Animal {
  public Animal() throws ArithmeticException, NullPointerException, IOException {
  }
그런 다음 클래스 상속자는 생성자에도 이를 표시해야 합니다.
public class Cat extends Animal {
   public Cat() throws ArithmeticException, NullPointerException, IOException {
       super();
   }
또는 메서드의 경우와 마찬가지로 동일한 예외가 아닌 보다 일반적인 예외를 지정할 수 있습니다. 우리의 경우에는 보다 일반적인 예외인 Exception 을 지정하는 것으로 충분합니다 . 이는 고려된 세 가지 예외 모두의 공통 조상이기 때문입니다.
public class Cat extends Animal {
   public Cat() throws Exception {
       super();
   }

104. finally 블록이 실행되지 않을 때를 위한 코드를 작성해 주실 수 있나요?

먼저 finally 가 무엇인지 기억해 봅시다 . 이전에는 예외를 포착하는 메커니즘을 살펴보았습니다. try 블록은 포착 영역의 개요를 설명하고, catch 블록 은 특정 예외가 발생했을 때 작동하는 코드입니다. 마지막으로 finally 다음의 세 번째 코드 블록은 catch 와 상호 교환 가능 하지만 상호 배타적이지는 않습니다. 이 블록의 핵심은 try 또는 catch 의 결과에 관계없이 (예외 발생 여부에 관계없이) 그 안에 있는 코드가 항상 작동한다는 것입니다. 실패 사례는 매우 드물며 비정상적입니다. 가장 간단한 실패 사례는 위 코드에서 System.exit(0) 메서드가 호출되어 프로그램을 종료하는 경우입니다.
try {
   throw new IOException();
} catch (IOException e) {
   System.exit(0);
} finally {
   System.out.println("Данное сообщение не будет выведенно в консоль");
}
최종적으로 작동하지 않는 다른 상황도 있습니다 .
  • 심각한 시스템 문제로 인해 발생한 프로그램의 비정상 종료 또는 응용 프로그램을 "충돌"시키는 일부 오류의 발생(오류의 예로는 스택 메모리가 오버플로될 때 발생하는 StackOwerflowError 와 동일할 수 있음)
  • 데몬 스레드 가 ry...finally 블록을 통과 하고 이와 동시에 프로그램이 종료됩니다. 결국 데몬 스레드는 백그라운드 작업을 위한 스레드입니다. 즉, 우선 순위나 필수 사항이 아니며 애플리케이션은 작업이 완료될 때까지 기다리지 않습니다.
  • try 또는 catch 에서 가장 일반적인 무한 루프는 한 번 흐름이 영원히 유지됩니다.

    try {
       while (true) {
       }
    } finally {
       System.out.println("Данное сообщение не будет выведенно в консоль");
    }

이 질문은 신입사원 면접에서 꽤 인기가 있기 때문에 몇 가지 예외적인 상황은 기억해 둘 가치가 있습니다. Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 3

105. 하나의 catch 블록에서 여러 예외를 처리하는 예제를 작성하세요.

1) 질문이 잘못되었을 수 있습니다. 내가 이해하는 한, 이 질문은하나의 try 블록에 대한 여러 캐치를 나타냅니다 .
try {
  throw new FileNotFoundException();
} catch (FileNotFoundException e) {
   System.out.print("Упс, у вас упало исключение - " + e);
} catch (IOException e) {
   System.out.print("Упс, у вас упало исключение - " + e);
} catch (Exception e) {
   System.out.print("Упс, у вас упало исключение - " + e);
}
try 블록 에서 예외가 발생하면 catch 블록 은 위에서 아래로 번갈아가며 이를 잡으려고 시도합니다. 특정 catch 블록이 성공하면 예외를 처리할 수 있는 권한을 갖게 되지만 아래의 나머지 블록은 더 이상 예외를 처리할 수 없습니다. 그것을 포착하고 자신의 방식으로 처리하려고 노력할 수 있습니다. 따라서 더 좁은 예외는 캐치 블록체인 에서 더 높은 곳에 배치되고 , 더 넓은 예외는 더 낮은 곳에 배치됩니다. 예를 들어, 첫 번째 catch 블록에서 Exception 클래스 의 예외가 catch 되면 확인된 예외는 나머지 블록에 들어갈 수 없습니다( Exception 하위 항목이 있는 나머지 블록은 전혀 쓸모가 없습니다). 2) 질문이 올바르게 요청된 경우, 처리 과정은 다음과 같습니다.
try {
  throw new NullPointerException();
} catch (Exception e) {
   if (e instanceof FileNotFoundException) {
       // некоторая обработка с сужением типа (FileNotFoundException)e
   } else if (e instanceof ArithmeticException) {
       // некоторая обработка с сужением типа (ArithmeticException)e
   } else if(e instanceof NullPointerException) {
       // некоторая обработка с сужением типа (NullPointerException)e
   }
catch를 통해 예외를 포착한 후 , 객체가 특정 유형에 속하는지 확인하는 데 사용되는 인스턴스of 메소드 를 통해 특정 유형을 찾으려고 시도하므로 나중에 부정적인 결과 없이 이 유형으로 범위를 좁힐 수 있습니다. 고려된 두 가지 접근 방식 모두 동일한 상황에서 사용할 수 있지만 두 번째 옵션을 좋다고 부르지 않고 실제로 본 적이 없으며 동시에 멀티 캐치를 사용하는 첫 번째 방법이 널리 보급되었기 때문에 질문이 틀렸다고 말했습니다. 주목. 확산. Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 4

106. 예외를 강제로 발생시킬 수 있는 연산자는 무엇입니까? 예시 작성

위에서 이미 여러 번 사용했지만 그럼에도 불구하고 이 키워드를 반복 하겠습니다 . 사용 예(예외 강제 적용):
throw new NullPointerException();

107. 메인 메소드가 예외를 던질 수 있나요? 그렇다면 어디로 이전되나요?

우선, main은 일반적인 메서드일 뿐이며 프로그램 실행을 시작하기 위해 가상 머신에 의해 호출되지만 이 외에도 다른 코드에서도 호출될 수 있다는 점에 주목하고 싶습니다. 즉, throw 후 확인된 예외를 지정하는 일반적인 규칙도 적용됩니다 .
public static void main(String[] args) throws IOException {
따라서 예외가 발생할 수도 있습니다. main이 일부 메서드에서 호출되지 않았지만 프로그램 시작 지점으로 시작된 경우 , 발생한 예외는 .UncaughtExceptionHandler 인터셉터 에 의해 처리됩니다 . 이 핸들러는 스레드당 하나입니다(즉, 각 스레드에 하나의 핸들러). 필요한 경우 자체 핸들러를 생성하고 Thread 객체 에서 호출되는 setDefaultUncaughtExceptionHandler 메소드를 사용하여 이를 설정할 수 있습니다 .

멀티스레딩

Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 5

108. 멀티스레딩 작업을 위해 어떤 도구를 알고 있습니까?

Java에서 멀티스레딩을 사용하기 위한 기본/기본 도구:
  • 동기화는 스레드가 다른 스레드에서 메서드/블록에 들어갈 때 메서드/블록을 닫는(차단하는) 메커니즘입니다.
  • Volatile은 다양한 스레드에서 변수에 대한 일관된 액세스를 보장하는 메커니즘입니다. 즉, 변수에 이 수정자가 있으면 모든 할당 및 읽기 작업이 원자성이어야 합니다. 즉, 스레드는 이 변수를 로컬 메모리에 복사하여 변경하지 않고 원래 값을 변경합니다.
여기에서 휘발성에 대해 자세히 알아보세요 .
  • Runnable 은 특정 클래스에서 구현될 수 있는 인터페이스(특히 run 메서드)입니다.
public class CustomRunnable implements Runnable {
   @Override
   public void run() {
       // некоторая логика
   }
}
이 클래스의 객체를 생성한 후에는 새 Thread 객체의 생성자에서 이 객체를 설정하고 해당 start() 메서드를 호출하여 새 스레드를 시작할 수 있습니다 .
Runnable runnable = new CustomRunnable();
new Thread(runnable).start();
start 메소드는 구현된 run() 메소드를 별도의 스레드에서 실행합니다.
  • Thread 는 다음을 상속하는 클래스입니다( run 메소드를 재정의하는 동안 ).
public class CustomThread extends Thread {
   @Override
   public void run() {
       // некоторая логика
   }
}
그리고 이 클래스의 객체를 생성하고 start() 메서드를 사용하여 이를 실행 하면 새 스레드가 시작됩니다.
new CustomThread().start();
  • 동시성은 다중 스레드 환경에서 작업하기 위한 도구가 포함된 패키지입니다.
그것은 다음으로 구성됩니다:
  • 동시 컬렉션 - 다중 스레드 환경에서 작업하는 데 특화된 컬렉션 집합입니다.
  • 대기열 - 다중 스레드 환경(차단 및 비차단)을 위한 특수 대기열입니다.
  • 동기화 장치는 다중 스레드 환경에서 작업하기 위한 특수 유틸리티입니다.
  • 실행자는 스레드 풀을 생성하는 메커니즘입니다.
  • 잠금 - 스레드 동기화 메커니즘(표준 메커니즘보다 유연함 - 동기화, 대기, 알림, 통지All).
  • Atomics는 멀티스레드 실행에 최적화된 클래스입니다. 각 작업은 원자적입니다.
여기에서 동시 패키지에 대해 자세히 알아보세요 .

109. 스레드 간 동기화에 대해 이야기해 보세요. wait(), inform() - informAll() Join() 메소드는 무엇에 사용됩니까?

내가 질문을 이해하는 한, 스레드 간 동기화는 키 수정자에 관한 것 입니다 . 이 수정자는 블록 바로 옆에 배치할 수 있습니다.
synchronized (Main.class) {
   // некоторая логика
}
또는 메소드 서명에서 직접:
public synchronized void move() {
   // некоторая логика}
앞서 말했듯 이 동기화는 한 스레드가 이미 입력한 경우 다른 스레드에서 블록/메서드를 닫을 수 있게 해주는 메커니즘입니다. 블록/메서드를 방으로 생각하세요. 어떤 개울은 그곳에 오면 그 방으로 들어가서 잠글 것이고, 다른 개울은 방에 와서 그것이 닫혀 있는 것을 보고 그 방이 풀릴 때까지 그 근처에서 기다릴 것입니다. 해당 작업을 완료한 후 첫 번째 스레드는 룸을 떠나 키를 해제합니다. 그리고 제가 열쇠에 대해 끊임없이 이야기한 것은 아무것도 아닙니다. 왜냐하면 그것이 실제로 존재하기 때문입니다. 이는 통화 중/한가함 상태를 갖는 특수 개체입니다. 이 객체는 모든 Java 객체에 연결되므로 동기화된 블록을 사용할 때 문을 닫으려는 뮤텍스가 있는 객체를 괄호 안에 표시해야 합니다.
Cat cat = new Cat();
synchronized (cat) {
   // некоторая логика
}
첫 번째 예제( Main.class ) 에서 했던 것처럼 클래스 뮤텍스를 사용할 수도 있습니다 . 메소드에 동기화를 사용할 때 닫으려는 객체를 지정하지 않습니다. 그렇죠? 이 경우 비정적 메서드의 경우 this 개체 , 즉 이 클래스의 현재 개체 의 뮤텍스에서 닫힙니다 . 정적 클래스는 현재 클래스( this.getClass(); ) 의 뮤텍스에서 닫힙니다 . 뮤텍스에 대한 자세한 내용은 여기에서 확인할 수 있습니다 . 여기에서 동기화 에 대해 읽어 보세요 . Wait() 는 마치 현재 모니터(앵커와 같은 것)에 연결된 것처럼 뮤텍스를 해제하고 현재 스레드를 대기 모드로 전환하는 메서드입니다. 이 때문에 이 메서드는 동기화된 블록이나 메서드에서만 호출할 수 있습니다(그렇지 않으면 무엇을 해제해야 하고 무엇을 기대해야 할까요). 또한 이는 Object 클래스 의 메서드라는 점에 유의하세요 . 보다 정확하게는 하나가 아니라 세 개도 가능합니다.
  • Wait() - 다른 스레드가 이 개체에 대한 inform() 또는 informAll() 메서드를 호출할 때까지 현재 스레드를 대기 모드로 전환합니다 (이러한 메서드에 대해서는 나중에 설명하겠습니다).

  • 대기(긴 시간 초과) - 다른 스레드가 이 개체에 대해 inform() 또는 informAll() 메서드를 호출하거나 지정된 시간 초과가 만료될 때까지 현재 스레드를 대기 모드로 전환합니다 .

  • 대기(긴 시간 제한, int nanos) - 이전 항목과 유사하지만 nanos 만 나노초(보다 ​​정확한 시간 설정)를 지정할 수 있습니다.

  • Notify()는 현재 동기화 블록의 임의 스레드 하나를 깨울 수 있는 메서드입니다. 다시 말하지만, 이는 동기화된 블록이나 메서드 에서만 호출할 수 있습니다 (결국 다른 곳에서는 고정을 해제할 사람이 없습니다).

  • NotifyAll() 은 현재 모니터에서 대기 중인 모든 스레드를 깨우는 메서드입니다( 동기화 블록이나 메서드에서만 사용됨).

110. 흐름을 멈추는 방법은 무엇입니까?

가장 먼저 말해야 할 것은 run() 메소드가 완전히 실행되면 스레드가 자동으로 소멸된다는 것입니다. 하지만 때로는 이 방법이 완료되기 전에 예정보다 일찍 그를 죽여야 할 때도 있습니다. 그렇다면 우리는 어떻게 해야 할까요? 아마도 Thread 객체에는 stop() 메소드가 있어야 할까요 ? 아무리 그렇더라도! 이 방법은 오래된 것으로 간주되며 시스템 충돌이 발생할 수 있습니다. Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 6그럼 어쩌지? 이를 수행하는 방법에는 두 가지가 있습니다. 첫 번째 는 내부 부울 플래그를 사용하는 것입니다. 예를 살펴보겠습니다. 완전히 멈출 때까지 화면에 특정 문구를 표시하는 스레드를 자체적으로 구현했습니다.
public class CustomThread extends Thread {
private boolean isActive;

   public CustomThread() {
       this.isActive = true;
   }

   @Override
   public void run() {
       {
           while (isActive) {
               System.out.println("Поток выполняет некую логику...");
           }
           System.out.println("Поток остановлен!");
       }
   }

   public void stopRunningThread() {
       isActive = false;
   }
}
stopRunning() 메서드를 사용하면 내부 플래그가 false가 되고 run 메서드의 실행이 중지됩니다. main 에서 실행해보자 :
System.out.println("Начало выполнения программы");
CustomThread thread = new CustomThread();
thread.start();
Thread.sleep(3);
// пока наш основной поток спит, вспомогательный  CustomThread работает и выводит в коноль своё сообщение
thread.stopRunningThread();
System.out.println("Конец выполнения программы");
결과적으로 콘솔에 다음과 같은 내용이 표시됩니다.
프로그램 실행 시작 스레드가 일부 로직을 실행 중입니다... 스레드가 일부 로직을 실행 중입니다... 스레드가 일부 로직을 실행 중입니다... 스레드가 일부 로직을 실행 중입니다... 스레드가 일부 로직을 실행 중입니다... 스레드가 일부 논리를 실행 중입니다... 프로그램 실행 종료 스레드가 중지되었습니다!
이는 스레드가 작동하여 특정 수의 메시지를 콘솔에 출력하고 성공적으로 중지되었음을 의미합니다. 출력되는 메시지 수는 실행마다 다르며 때로는 추가 스레드가 아무 것도 출력하지 않는 경우도 있습니다. 내가 알아차렸듯이 이는 메인 스레드의 휴면 시간에 따라 달라지며, 시간이 길수록 추가 스레드가 아무 것도 출력하지 않을 가능성이 줄어듭니다. Sleep Time을 1ms로 설정하면 메시지가 거의 출력되지 않지만, 20ms로 설정하면 거의 항상 작동합니다. 아마도 시간이 짧을 때 스레드는 작업을 시작하고 시작할 시간이 없으며 즉시 중지됩니다. 두 번째 방법은 내부 인터럽트 플래그(이 플래그는 기본적으로 false임 )의 값을 반환하는 Thread 객체의 Interrupted() 메서드 와 이 플래그를 true로 설정하는 다른 Interrupt() 메서드를 사용하는 것입니다. 플래그가 true 이면 스레드가 작업을 중지해야 합니다.) 예를 살펴보겠습니다:
public class CustomThread extends Thread {

   @Override
   public void run() {
       {
           while (!Thread.interrupted()) {
               System.out.println("Поток выполняет некую логику...");
           }
           System.out.println("Поток остановлен!");
       }
   }
}
메인 에서 실행 :
System.out.println("Начало выполнения программы");
Thread thread = new CustomThread();
thread.start();
Thread.sleep(3);
thread.interrupt();
System.out.println("Конец выполнения программы");
실행 결과는 첫 번째 경우와 동일하지만 저는 이 접근 방식이 더 마음에 듭니다. 코드를 덜 작성하고 기성 표준 기능을 더 많이 사용합니다. Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 7오늘은 여기서 멈추겠습니다.Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 12 - 8
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION