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

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

Random-KO 그룹에 게시되었습니다
안녕 모두들! 프로그래밍에는 함정이 가득합니다. 그리고 당신이 넘어지거나 충돌하지 않을 주제는 거의 없습니다. 초보자에게는 특히 그렇습니다. 이를 줄이는 유일한 방법은 공부입니다. 특히 이는 가장 기본적인 주제에 대한 자세한 분석에 적용됩니다. 오늘 저는 기본적인 주제를 잘 다루는 Java 개발자 인터뷰에서 얻은 250개 이상의 질문을 계속 분석하고 있습니다 . 목록에는 일반적인 주제를 다른 각도에서 볼 수 있는 비표준 질문도 포함되어 있다는 점에 주목하고 싶습니다.Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 7 - 1

62. 스트링 풀이란 무엇이며 왜 필요한가요?

Java의 메모리(나중에 설명할 힙)에는 문자열 풀 또는 문자열 풀이라는 영역이 있습니다. 문자열 값을 저장하도록 설계되었습니다. 즉, 예를 들어 큰따옴표를 사용하여 특정 문자열을 생성하는 경우:
String str = "Hello world";
문자열 풀에 지정된 값이 있는지 확인하는 검사가 수행됩니다. 그렇다면 str 변수 에는 풀의 해당 값에 대한 참조가 할당됩니다. 그렇지 않은 경우 풀에 새 값이 생성되고 해당 값에 대한 참조가 str 변수에 할당됩니다 . 예를 살펴보겠습니다:
String firstStr = "Hello world";
String secondStr = "Hello world";
System.out.println(firstStr == secondStr);
true가 화면에 표시됩니다 . ==는 참조를 비교한다는 것을 기억합니다 . 즉, 이 두 참조는 문자열 풀에서 동일한 값을 참조한다는 의미입니다. 이는 메모리에 String 유형 의 동일한 객체를 많이 생성하지 않기 위해 수행됩니다 . 기억하는 것처럼 String 은 불변 클래스이고 동일한 값에 대한 참조가 많으면 아무런 문제가 없기 때문입니다. 한 곳의 값을 변경하면 여러 다른 링크가 동시에 변경되는 상황은 더 이상 불가능합니다. 그럼에도 불구하고 new를 사용하여 문자열을 생성하면 다음과 같습니다 .
String str = new String("Hello world");
이 문자열 값을 저장할 별도의 개체가 메모리에 생성됩니다(문자열 풀에 해당 값이 이미 있는지 여부는 중요하지 않습니다). 확인:
String firstStr = new String("Hello world");
String secondStr = "Hello world";
String thirdStr = new String("Hello world");
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
우리는 두 개의 거짓 값을 얻게 될 것 입니다. 이는 여기에 참조되는 세 가지 다른 값이 있음을 의미합니다. 실제로 이것이 바로 큰따옴표를 사용하여 문자열을 생성하는 것이 권장되는 이유입니다. 그러나 new 를 사용하여 객체를 생성할 때 문자열 풀에 값을 추가(또는 참조 가져오기)할 수 있습니다 . 이를 위해 문자열 클래스 메소드인 intern()을 사용합니다 . 이 메서드는 문자열 풀에 값을 강제로 생성하거나 값이 이미 거기에 저장되어 있는 경우 해당 값에 대한 링크를 가져옵니다. 예는 다음과 같습니다.
String firstStr = new String("Hello world").intern();
String secondStr = "Hello world";
String thirdStr = new String("Hello world").intern();
System.out.println(firstStr == secondStr);
System.out.println(firstStr == thirdStr);
System.out.println(secondStr == thirdStr);
결과적으로 우리는 콘솔에 3개의 참값을 받게 되는데 , 이는 3개의 변수가 모두 동일한 문자열을 참조한다는 것을 의미합니다.Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 7 - 2

63. 스트링 풀에는 어떤 GOF 패턴이 사용되나요?

GOF 패턴은 스트링 풀 ( 플라이웨이트 , 정착자라고도 함)에서 명확하게 볼 수 있습니다. 여기에 다른 템플릿이 있으면 댓글로 공유해 주세요. 이제 경량 템플릿에 대해 이야기해 보겠습니다. 경량은 프로그램의 여러 위치에서 고유한 인스턴스로 나타나는 개체가 실제로는 그렇지 않은 구조적 디자인 패턴입니다. 경량은 각 개체에 동일한 데이터를 저장하는 대신 개체 간의 공유 상태를 공유하여 메모리를 절약합니다. 본질을 이해하기 위해 가장 간단한 예를 살펴 보겠습니다. 직원 인터페이스가 있다고 가정해 보겠습니다.
public interface Employee {
   void work();
}
예를 들어 변호사와 같은 몇 가지 구현이 있습니다.
public class Lawyer implements Employee {

   public Lawyer() {
       System.out.println("Юрист взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Решение юридических вопросов...");
   }
}
그리고 회계사는:
public class Accountant implements Employee{

   public Accountant() {
       System.out.println("Бухгалтер взят в штат.");
   }

   @Override
   public void work() {
       System.out.println("Ведение бухгалтерского отчёта....");
   }
}
방법은 매우 조건적입니다. 우리는 단지 그 방법이 수행되는지 확인하면 됩니다. 동일한 상황이 생성자에도 적용됩니다. 콘솔 출력 덕분에 새 객체가 언제 생성되는지 확인할 수 있습니다. 또한 요청한 직원을 발급하는 임무를 맡은 직원 부서가 있으며, 직원이 없으면 그를 고용하고 요청에 응답하여 발급합니다.
public class StaffDepartment {
   private Map<String, Employee> currentEmployees = new HashMap<>();

   public Employee receiveEmployee(String type) throws Exception {
       Employee result;
       if (currentEmployees.containsKey(type)) {
           result = currentEmployees.get(type);
       } else {
           switch (type) {
               case "Бухгалтер":
                   result = new Accountant();
                   currentEmployees.put(type, result);
                   break;
               case "Юрист":
                   result = new Lawyer();
                   currentEmployees.put(type, result);
                   break;
               default:
                   throw new Exception("Данный сотрудник в штате не предусмотрен!");
           }
       }
       return result;
   }
}
즉, 논리는 간단합니다: 주어진 단위가 있으면 반환하고, 없으면 생성하여 저장소(캐시와 같은 것)에 저장한 후 반환합니다. 이제 모든 것이 어떻게 작동하는지 살펴보겠습니다.
public static void main(String[] args) throws Exception {
   StaffDepartment staffDepartment = new StaffDepartment();
   Employee empl1  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl2  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl3  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl4  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl5  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl6  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl7  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl8  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
   Employee empl9  = staffDepartment.receiveEmployee("Юрист");
   empl1.work();
   Employee empl10  = staffDepartment.receiveEmployee("Бухгалтер");
   empl2.work();
}
그리고 그에 따라 콘솔에 다음과 같은 출력이 표시됩니다.
변호사가 고용되었습니다. 법적 문제 해결... 회계사가 고용되었습니다. 회계 보고서 유지.... 법적 문제 해결... 회계 보고서 유지.... 법적 문제 해결... 회계 보고서 유지.... 법적 문제 해결... 회계 보고서 유지.... 법적 문제 해결 .. 회계 보고서 유지...
보시다시피 두 개의 객체만 생성되었으며 여러 번 재사용되었습니다. 이 예는 매우 간단하지만 이 템플릿을 사용하여 리소스를 절약할 수 있는 방법을 명확하게 보여줍니다. 글쎄요, 아시다시피 이 패턴의 논리는 보험 풀의 논리와 매우 유사합니다. 이 기사에서 GOF 패턴 유형에 대해 자세히 알아볼 수 있습니다 .Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 7 - 3

64. 문자열을 여러 부분으로 나누는 방법은 무엇입니까? 해당 코드의 예를 제공해 주세요.

분명히 이 질문은 분할 방법에 관한 것입니다 . String 클래스에는 이 메서드에 대한 두 가지 변형이 있습니다.
String split(String regex);
그리고
String split(String regex);
regex 는 줄 구분 기호입니다. 예를 들어 문자열을 문자열 배열로 나누는 일부 정규식입니다.
String str = "Hello, world it's Amigo!";
String[] arr = str.split("\\s");
for (String s : arr) {
  System.out.println(s);
}
콘솔에 다음이 출력됩니다.
안녕하세요, 세상 아미고입니다!
즉, 문자열 값은 문자열 배열로 분할되었으며 구분 기호는 공백이었습니다(분리를 위해 공백이 아닌 정규 표현식 "\\s" 및 문자열 표현식 " " 만 사용할 수 있음 ). 두 번째 오버로드된 메서드에는 추가 인수인 limit 가 있습니다 . 한계 — 결과 배열의 최대 허용 값입니다. 즉, 문자열이 이미 허용되는 최대 하위 문자열 수로 분할된 경우 더 이상 분할이 없으며 마지막 요소에는 분할되지 않은 문자열의 "나머지"가 포함됩니다. 예:
String str = "Hello, world it's Amigo!";
String[] arr = str.split(" ", 2);
for (String s : arr) {
  System.out.println(s);
}
콘솔 출력:
안녕하세요, 세상 아미고입니다!
보시다시피, 제한 = 2 제약 조건이 아닌 경우 배열의 마지막 요소는 세 개의 하위 문자열로 분할될 수 있습니다.Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 7 - 4

65. 비밀번호를 저장하는 데 문자열보다 문자 배열이 더 나은 이유는 무엇입니까?

비밀번호를 저장할 때 문자열보다 배열을 선호하는 데는 여러 가지 이유가 있습니다. 1. 문자열 풀 및 문자열 불변성. 배열( char[] )을 사용하면 작업이 완료된 후 데이터를 명시적으로 지울 수 있습니다. 또한 원하는 만큼 배열을 다시 작성할 수 있으며 가비지 수집 이전에도 유효한 암호는 시스템 어디에도 없습니다(몇 개의 셀을 잘못된 값으로 변경하는 것으로 충분합니다). 동시에 String은 불변 클래스입니다. 즉, 해당 값을 변경하려면 새 값을 얻고 이전 값은 문자열 풀에 유지됩니다. 비밀번호의 문자열 값을 제거하려는 경우 문자열 풀 에서 값을 제거하려면 가비지 수집기가 필요하고 이 문자열 값이 한동안 그대로 유지될 가능성이 높기 때문에 이는 매우 어려운 작업이 될 수 있습니다. 장기. 즉, 이 상황에서는 데이터 저장 보안 측면에서 String이 char 배열 보다 열등합니다. 2. 문자열 값이 실수로 콘솔(또는 로그)에 출력된 경우 값 자체가 표시됩니다.
String password = "password";
System.out.println("Пароль - " + password);
콘솔 출력:
비밀번호
동시에 실수로 콘솔에 배열을 출력한 경우:
char[] arr = new char[]{'p','a','s','s','w','o','r','d'};
System.out.println("Пароль - " + arr);
콘솔에는 이해할 수 없는 gobbledygook이 있을 것입니다:
비밀번호 - [C@7f31245a
실제로는 gobbledygook이 아니지만: [C 는 클래스 이름이 char 배열이고 , @ 가 구분 기호이고 그 뒤에 7f31245a 가 16진수 해시 코드입니다. 3. 공식 문서인 Java Cryptography Architecture Guide에서는 String 대신 char[] 에 비밀번호를 저장하는 것을 명시적으로 언급합니다 . “ java.lang.String 유형의 객체에 비밀번호를 수집하고 저장하는 것이 논리적인 것처럼 보입니다 . 그러나 여기에는 주의 사항이 있습니다. String 객체는 변경할 수 없습니다. 즉, String 객체 의 내용을 사용 후 수정(덮어쓰기)하거나 null로 만들 수 있도록 정의된 메서드가 없습니다 . 이 기능으로 인해 String 객체는 사용자 비밀번호와 같은 민감한 정보를 저장하는 데 적합하지 않습니다. 대신, 항상 민감한 보안 정보를 문자 배열로 수집하고 저장해야 합니다.”Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 7 - 5

열거형

66. Java의 Enum에 대해 간략하게 설명해주세요

Enum 은 공통 유형으로 통합된 문자열 상수 집합인 열거형입니다. 키워드 - enum 을 통해 선언됩니다 . 다음은 특정 학교에서 유효한 역할인 열거 형의 예입니다 .
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD
}
대문자로 작성된 단어는 new 연산자를 사용하지 않고 단순화된 방식으로 선언된 열거형 상수와 동일합니다 . 열거형을 사용하면 이름 지정 시 오류와 혼란을 방지하는 데 도움이 되므로(특정 값 목록만 있을 수 있으므로) 생활이 크게 단순화됩니다. 개인적으로 Switch의 로직 설계에 사용하면 매우 편리하다고 생각합니다 .

67. Enum으로 인터페이스를 구현할 수 있나요?

예. 결국 열거형은 단순한 수동 컬렉션(예: 역할) 이상을 나타내야 합니다. Java에서는 일부 기능을 포함하는 더 복잡한 개체를 나타낼 수 있으므로 추가 기능을 추가해야 할 수도 있습니다. 또한 구현된 인터페이스 유형이 필요한 위치에 열거형 값을 대체하여 다형성 기능을 사용할 수 있습니다 .

68. Enum이 클래스를 확장할 수 있나요?

아니요, 그럴 수 없습니다. 왜냐하면 열거형은 일반 클래스 Enum <T> 의 기본 하위 클래스이기 때문입니다 . 여기서 T는 일반 열거형 유형을 나타냅니다. 이는 Java 언어의 모든 열거형 유형에 대한 공통 기본 클래스일 뿐입니다. 열거형을 클래스로 변환하는 작업은 컴파일 타임에 Java 컴파일러에 의해 수행됩니다. 이 확장은 코드에 명시적으로 표시되지 않지만 항상 눈에 보이지 않게 존재합니다.

69. 객체 인스턴스 없이 Enum을 생성하는 것이 가능합니까?

저는 질문이 조금 이상하거나 완전히 이해하지 못했습니다. 두 가지 해석이 있습니다: 1. 값이 없는 열거형이 있을 수 있습니까 ? 물론 빈 클래스와 같을 것입니다. 의미가 없습니다.
public enum Role {
}
그리고 전화:
var s = Role.values();
System.out.println(s);
콘솔에서 다음을 받게 됩니다:
[Lflyweight.Role;@9f70c54
( 역할 값의 빈 배열) 2. new 연산자 없이 열거형을 만드는 것이 가능합니까 ? 물론 그렇습니다. 위에서 말했듯이 열거형 값(enumerations) 에는 new 연산자를 사용할 필요가 없습니다 . 이는 정적 값이기 때문입니다.

70. Enum에 대한 toString() 메서드를 재정의할 수 있나요?

예, 물론 toString() 메서드를 재정의하여 toString 메서드를 호출할 때 열거 형을 표시하는 특정 방법을 정의 할 수 있습니다 ( 예를 들어 콘솔이나 로그에 출력하기 위해 열거형을 일반 문자열로 변환하는 경우).
public enum Role {
   STUDENT,
   TEACHER,
   DIRECTOR,
   SECURITY_GUARD;

   @Override
   public String toString() {
       return "Выбрана роль - " + super.toString();
   }
}
오늘은 여기까지입니다. 다음 부분까지!Java 개발자 인터뷰의 질문과 답변을 분석합니다.  파트 7 - 6
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION