본문 바로가기

개발중/Java

Java 개발자라면 알아야하는 질문들이라길래 나는 잘 알고 있는가 ?

728x90
반응형

📌 JDK 와 JRE 의 차이점

JDK (Java Development Kit)
JDK는 Java 애플리케이션을 개발하기 위한 도구 집합입니다. 

JDK에는 JRE가 포함되어 있으며, 추가적으로 컴파일러(javac), 디버거, 아카이버(jar), 문서 생성기(javadoc) 등의 도구도 포함되어 있습니다. 즉, JDK는 소프트웨어를 개발하기 위한 도구를 제공합니다.

JRE (Java Runtime Environment)
JRE는 Java 애플리케이션을 실행하기 위한 환경입니다. JRE에는 JVM (Java Virtual Machine)과 Java 클래스 라이브러리(Java API)가 포함되어 있습니다. 이는 애플리케이션을 실행하는데 필요한 최소한의 도구 및 라이브러리를 제공합니다. 그러나 JRE만으로는 Java 애플리케이션을 개발할 수는 없습니다.

요약하면, JDK는 Java 애플리케이션을 개발하고 실행하기 위한 도구를 제공하며, JRE는 Java 애플리케이션을 실행하기 위한 환경을 제공합니다. 만약 당신이 Java 개발자라면 JDK를 설치해야 하고, 단지 Java 애플리케이션을 실행하려는 사용자라면 JRE만 설치하면 됩니다.

 

 

📌 == 와 equals 의 차이점

== 연산자와 equals 메소드는 Java에서 객체 또는 값의 동일성 또는 동등성을 비교하는 데 사용되지만, 그들이 하는 일은 다릅니다.

== 연산자
== 연산자는 원시 타입(primitive type, 예: int, float, boolean 등)에서 값을 비교하거나 객체 참조에서 메모리 주소를 비교하는 데 사용됩니다.

예를 들어,

int a = 10;
int b = 10;
System.out.println(a == b); // true, 값이 같으므로

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2); // false, 객체의 참조(메모리 주소)가 다르기 때문에

equals 메소드
equals 메소드는 Java 객체가 논리적으로 동일한지를 비교하는 데 사용됩니다. 기본적으로 equals 메소드는 == 연산자와 동일하게 작동하므로, 객체 참조가 동일한 경우에만 true를 반환합니다.

그러나 equals 메소드는 클래스에 따라 재정의(override)될 수 있으며, 대부분의 내장 Java 클래스(예: String, Integer 등)에서는 이 메소드가 논리적 동등성을 비교하도록 재정의되어 있습니다.

예를 들어,

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2)); // true, 두 문자열의 내용이 같으므로

요약하면, == 연산자는 원시 타입의 값을 비교하거나 객체 참조의 메모리 주소를 비교하는 데 사용되고, equals 메소드는 객체의 논리적 동등성을 비교하는 데 사용됩니다. 이때 equals 메소드의 동작은 해당 클래스에 따라 달라질 수 있습니다.

 

 

📌 두 객체가 동일한 hashCode 를 가지면 Equals() 에 대해

Java에서 두 객체가 동일한 hashCode()를 반환한다면 그것은 그 두 객체가 동등하다는 것을 의미하지는 않습니다. hashCode() 메서드는 객체를 나타내는 정수 값을 반환하며, 이 값은 메모리상의 주소를 기반으로 하지만, 일반적으로 객체의 내용을 기반으로 계산됩니다. 이는 객체의 데이터가 바뀌면 해시 코드도 바뀔 수 있음을 의미합니다.

그러나 Java의 hashCode() 메서드에는 특정 규칙이 있습니다. 만약 두 객체가 equals() 메서드에 의해 동등하다고 판단되면, 그 두 객체는 반드시 동일한 해시 코드를 반환해야 합니다. 이는 HashMap, HashSet 등의 컬렉션에서 객체의 동등성을 판단하는데 사용됩니다.

반대로, 두 객체의 hashCode()가 동일하다고 해서 그 두 객체가 equals()에 의해 동등하다는 것을 보장하지는 않습니다. 즉, 해시 충돌(hash collision)이 발생할 수 있습니다. 이는 두 개 이상의 다른 객체(즉, equals()로 비교했을 때 false를 반환하는 객체)가 동일한 해시 코드를 반환하는 경우를 의미합니다. 이는 해시 함수의 속성 때문에 발생하며, 특히 해시 코드가 가능한 값의 범위가 객체의 수보다 작을 때 발생합니다.

따라서 두 객체가 동일한 hashCode()를 가진다고 해서 그 객체들이 equals()에 의해 동등하다고 할 수는 없습니다. 하지만 equals()에 의해 동등하다고 판단된 객체들은 반드시 동일한 hashCode()를 가져야 합니다.

 

 

📌 String 는 기본 데이터 타입입니까 ?

 Java에서 String은 기본 데이터 타입(primitive data type)이 아닙니다. String은 참조 데이터 타입(reference data type) 혹은 객체 타입(object type) 중 하나입니다.

Java에서는 8개의 기본 데이터 타입이 있습니다:

1. byte
2. short
3. int
4. long
5. float
6. double
7. boolean
8. char


이들은 Java에서 기본적으로 제공하는 데이터 타입으로, 메모리 크기와 형태가 정해져 있습니다.

반면에 String과 같은 참조 데이터 타입은 객체를 참조하며, new 키워드를 사용하여 인스턴스를 생성할 수 있습니다. String은 일반적으로 문자열을 표현하며, 여러 가지 메서드를 가지고 있어 문자열을 조작하는 데 유용합니다.

또한 String은 불변(immutable) 클래스입니다. 즉, 한 번 생성된 String 객체는 변하지 않습니다. String의 메서드 중 어떤 것을 호출하더라도 원래 String 객체는 변하지 않으며, 대신 새로운 String 객체가 생성됩니다. 이러한 특성 덕분에 String은 프로그램에서 안전하게 사용할 수 있습니다.

 

 

📌 자바에서 문자열을 조작하는 클래스는 무엇이 있습니까 ?

String: 불변성을 가진 문자열을 표현합니다. 한번 생성된 String 객체는 변경될 수 없습니다. 문자열 조작 작업이 많을 경우에는 성능상의 이슈가 있을 수 있습니다.

StringBuilder: String 클래스와 비슷하지만, 가변성(mutable)을 가진 클래스입니다. 즉, 한번 생성된 StringBuilder 객체는 변경될 수 있습니다. StringBuilder는 내부적으로 문자열 조작이 빈번하게 일어나는 경우에 사용하면 성능 향상을 가져올 수 있습니다.

StringBuffer: StringBuilder와 동일한 API를 가지며 가변적인 특성을 가집니다. 하지만 StringBuffer는 스레드에 안전(thread-safe)하게 동기화가 되어 있습니다. 즉, 여러 스레드에서 동시에 접근해도 안전하게 동작합니다.

StringTokenizer: String을 특정 구분자를 기준으로 분할하는 데 사용됩니다.

이 외에도 문자열을 조작하거나 처리하는데 필요한 많은 기능들이 Java의 표준 라이브러리에 포함되어 있습니다. 예를 들어, 정규 표현식을 활용하려면 Pattern과 Matcher 클래스를 사용하면 됩니다.

 

📌 String str ="i" 와 String str = new String("i") 는 동일한가 ?

String str = "i";와 String str = new String("i");는 기술적으로 서로 다르게 동작합니다.

String str = "i";: 이 코드는 문자열 리터럴을 사용합니다. 자바에서는 이런 방식으로 생성된 String 객체가 "String Constant Pool"이라는 특별한 영역에 저장됩니다. 동일한 문자열 리터럴이 여러번 사용될 경우, 모든 변수는 메모리 효율성을 위해 같은 객체를 참조하게 됩니다.

String str = new String("i");: 이 코드는 new 키워드를 사용해 새로운 String 객체를 생성합니다. 이런 방식으로 생성된 String 객체는 힙 메모리(heap memory)에 저장되며, 각각의 new 표현식은 새로운, 별개의 String 객체를 생성하게 됩니다. 이는 문자열이 같더라도 서로 다른 객체를 참조하게 됩니다.

따라서, String str = "i";와 String str = new String("i");는 저장되는 위치와 참조하는 객체가 서로 다릅니다.

다음과 같은 예시를 보면 더 명확하게 이해할 수 있습니다.

String str1 = "i";
String str2 = "i";
String str3 = new String("i");

System.out.println(str1 == str2);  // true
System.out.println(str1 == str3);  // false
System.out.println(str1.equals(str3)); // true

str1과 str2는 문자열 리터럴로 생성되어 같은 객체를 참조하기 때문에 ==로 비교하면 true가 반환됩니다. 그러나 str3는 new 키워드로 새로운 객체를 생성하기 때문에 str1이나 str2와 다른 객체를 참조합니다. 그래서 str1 == str3는 false를 반환합니다. 하지만 String 클래스의 equals() 메서드는 객체의 내용을 비교하므로, str1.equals(str3)는 true를 반환합니다.

 

 

📌 문자열을 반전시키는 가장 좋은 방법에 대해

Java에서 문자열을 반전시키는 가장 일반적인 방법 중 하나는 StringBuilder 클래스의 reverse 메소드를 사용하는 것입니다.

다음은 문자열을 반전시키는 간단한 예제 코드입니다:

String str = "Hello World";
String reversed = new StringBuilder(str).reverse().toString();
System.out.println(reversed);


이 코드를 실행하면, 출력 결과는 "dlroW olleH"입니다.

StringBuilder의 reverse 메소드는 문자열을 반전시키는 데 효율적입니다. StringBuilder는 문자열 조작을 위한 가변적인 객체를 제공하므로, 문자열을 반전시키는데 필요한 추가적인 메모리 할당 없이 작업을 수행할 수 있습니다.

물론 다른 방법들도 있습니다. 예를 들어, 문자 배열을 사용하여 문자열을 반전시킬 수 있습니다:

String str = "Hello World";
char[] strArray = str.toCharArray();
String reversed = "";
for (int i = strArray.length - 1; i >= 0; i--) {
    reversed += strArray[i];
}
System.out.println(reversed);

하지만 이 방법은 문자열이 길 경우 성능 문제가 발생할 수 있습니다. 왜냐하면 문자열의 각 문자마다 새로운 문자열 객체가 생성되기 때문입니다. 따라서, 일반적으로는 StringBuilder의 reverse 메소드를 사용하는 것이 좋습니다.

 

 

📌 String 클래스의 일반적인 메서드는 무엇인가

length(): 문자열의 길이(문자 수)를 반환합니다.

charAt(int index): 지정된 인덱스에 있는 문자를 반환합니다.

substring(int beginIndex, int endIndex): 문자열의 특정 부분을 추출하여 반환합니다. beginIndex는 시작 인덱스이고, endIndex는 종료 인덱스입니다. endIndex는 선택적이며, 제공되지 않으면 문자열의 끝까지 부분 문자열을 생성합니다.

contains(CharSequence sequence): 문자열이 특정 문자열을 포함하고 있는지 확인합니다. 포함하면 true, 그렇지 않으면 false를 반환합니다.

indexOf(String str): 문자열에서 특정 문자열이 시작되는 첫 번째 인덱스를 반환합니다. 찾는 문자열이 없으면 -1을 반환합니다.

lastIndexOf(String str): 문자열에서 특정 문자열이 시작되는 마지막 인덱스를 반환합니다. 찾는 문자열이 없으면 -1을 반환합니다.

equals(Object obj): 문자열이 다른 문자열과 동일한지 확인합니다. 동일하면 true, 그렇지 않으면 false를 반환합니다.

equalsIgnoreCase(String str): 문자열이 다른 문자열과 대소문자를 무시하고 동일한지 확인합니다.

startsWith(String prefix), endsWith(String suffix): 문자열이 특정 문자열로 시작하거나 끝나는지 확인합니다.

replace(char oldChar, char newChar): 문자열에서 특정 문자를 다른 문자로 모두 교체합니다.

toUpperCase(), toLowerCase(): 문자열의 모든 문자를 대문자 또는 소문자로 변환합니다.

trim(): 문자열의 앞뒤 공백을 제거합니다.

 

 

📌 추상 클래스에서 추상 메서드는 필수적인가요 ?

추상 클래스에서 추상 메소드는 필수적이지 않습니다.

추상 클래스는 일반 메소드와 필드를 가질 수 있습니다. 그러나 추상 메소드를 하나 이상 가지면 그 클래스는 반드시 추상 클래스로 선언되어야 합니다.

추상 클래스는 인스턴스화 될 수 없으며, 주로 하위 클래스에 의해 확장되어 사용됩니다. 이 클래스를 확장하는 하위 클래스는 추상 클래스가 가지고 있는 모든 추상 메소드를 구현해야 합니다.

추상 클래스를 사용하는 주된 이유 중 하나는 어떤 메소드를 반드시 구현하도록 강제하거나, 클래스의 일부 기능만을 제공하고 서브 클래스에서 나머지 기능을 구현하도록 하기 위함입니다. 하지만 추상 클래스는 추상 메소드 없이도 구현될 수 있으며, 이는 추상 클래스를 사용하는 다른 목적을 가질 때 유용할 수 있습니다. 예를 들어, 서브 클래스 간에 공통의 상태나 기능을 공유하도록 하기 위해 추상 클래스를 사용할 수 있습니다.

 

 

📌 보통의 클래스와 추상 클래스의 차이는 무엇인가요 ?

인스턴스화: 일반 클래스는 객체로 인스턴스화 될 수 있습니다. 즉, 일반 클래스의 인스턴스를 생성할 수 있습니다. 반면에 추상 클래스는 객체로 인스턴스화 될 수 없습니다. 즉, 추상 클래스의 인스턴스를 직접 생성할 수 없습니다. 대신 추상 클래스는 다른 클래스에 의해 상속되어야 합니다.

메소드의 구현: 일반 클래스에서 선언된 메소드는 반드시 구현되어야 합니다. 반면에, 추상 클래스는 구현되지 않은 메소드, 즉 '추상 메소드'를 가질 수 있습니다. 이러한 추상 메소드는 서브클래스에서 구현됩니다.

사용 목적: 일반 클래스는 대부분 객체의 구체적인 행동을 정의하는 데 사용됩니다. 반면에 추상 클래스는 주로 베이스 클래스로 사용되며, 동일한 '종류'에 속하는 여러 객체들의 공통된 특성과 동작을 정의하는데 사용됩니다.

확장성: 일반 클래스는 필요에 따라 확장될 수 있지만, 특정한 행동이나 속성을 강제하거나 제공하지는 않습니다. 반면에, 추상 클래스는 서브 클래스가 반드시 구현해야 하는 하나 이상의 메소드를 지정함으로써 특정 행동을 강제할 수 있습니다.

이러한 차이점들로 인해, 추상 클래스와 일반 클래스는 다양한 상황과 요구사항에 따라 선택되고 사용됩니다.

 

 

📌 final 은 추상 클래스를 수정할 때 사용할 수 있나요 ?

final과 abstract는 서로 배타적인 키워드로, 동시에 사용될 수 없습니다.

final 클래스: final 키워드가 붙은 클래스는 더 이상 확장(상속)될 수 없습니다. 즉, 다른 클래스가 final 클래스를 상속받아 새로운 서브클래스를 생성하는 것을 방지합니다. 또한, final 키워드는 메소드와 변수에도 사용될 수 있어, final 메소드는 오버라이드할 수 없고, final 변수는 값을 재할당할 수 없게 합니다.

추상 클래스: 반면에 abstract 키워드가 붙은 클래스는 반드시 하나 이상의 클래스에 의해 상속되어야 합니다. 추상 클래스는 하나 이상의 추상 메소드를 포함할 수 있으며, 이러한 추상 메소드는 서브클래스에서 반드시 구현되어야 합니다.

따라서, final 키워드는 상속과 오버라이딩을 방지하는 반면, abstract 키워드는 상속과 오버라이딩을 강제하기 때문에, 이 두 키워드는 동시에 사용될 수 없습니다. 즉, 클래스는 final일 수도 있고 abstract일 수도 있지만, 둘 동시에는 될 수 없습니다.

 

 

📌 자바 컨테이너란 무엇인가요 ?

자바 컨테이너는 일반적으로 자바 애플리케이션의 라이프사이클을 관리하는데 사용되는 컴포넌트를 가리키는 용어입니다. 특히, 웹 애플리케이션 컨테이너 또는 서블릿 컨테이너라고도 하며, 서블릿 및 JSP 페이지의 실행을 관리합니다.

컨테이너는 애플리케이션의 시작, 중지, 배포, 언배포와 같은 여러 가지 작업을 수행합니다. 또한, 세션 관리, 보안, 트랜잭션 관리, 리소스 풀링 등과 같은 다양한 서비스를 제공합니다.

자바 플랫폼, 엔터프라이즈 에디션(Java EE, 이전의 J2EE)에서는 두 가지 주요한 종류의 컨테이너를 정의하고 있습니다:

EJB 컨테이너: 이 컨테이너는 엔터프라이즈 자바 빈(Enterprise Java Beans)의 생명주기를 관리합니다. 또한, 시스템 레벨의 서비스를 제공하며, 트랜잭션 처리, 보안, 리모트 접근 등을 처리합니다.

웹 컨테이너 (또는 서블릿 컨테이너): 이 컨테이너는 웹 컴포넌트인 서블릿과 JSP(JavaServer Pages)의 생명주기를 관리합니다. HTTP 요청을 처리하고, 클라이언트와 서버 간의 통신을 담당합니다.

자바 컨테이너의 대표적인 예로는 Apache Tomcat, Jetty, JBoss, GlassFish 등이 있습니다. 이들은 웹 애플리케이션을 호스팅하고 관리하는데 널리 사용됩니다.

 

 

📌 Collection 과 Collections 의 차이는 무엇인가 ?

Collection과 Collections는 자바의 표준 라이브러리 내에 있는 두 가지 다른 것을 나타냅니다.

Collection: java.util.Collection 인터페이스는 자바에서 제공하는 주요 컬렉션 타입들(List, Set, Queue 등)의 루트 인터페이스입니다. 이 인터페이스는 여러 원소를 다루는데 사용되는 기본 메소드들(add, remove, contains, isEmpty 등)을 정의하고 있습니다. Collection은 인터페이스로서, 직접적으로 인스턴스화 할 수 없으며, 대신 그 하위의 구현체들(List, Set, Queue 등)을 사용할 수 있습니다.

Collections: 반면에 java.util.Collections는 유틸리티 클래스입니다. 이 클래스는 정적 메소드만을 포함하며, 이들 메소드는 주로 Collection 객체들을 조작하는 데 사용됩니다. 예를 들어, Collections.sort(List) 메소드는 주어진 리스트를 정렬하고, Collections.binarySearch(List, Object) 메소드는 주어진 리스트에서 이진 탐색을 수행하는데 사용됩니다.

따라서, Collection은 다양한 종류의 데이터 집합을 다루는 기본 인터페이스이며, Collections는 이런 데이터 집합들을 다루는 데 도움이 되는 유틸리티 메소드들을 제공하는 클래스입니다.

 

 

📌 Hash Map 과 Hash Table 의 차이점

HashMap과 Hashtable은 둘 다 Java의 컬렉션 프레임워크의 일부로, 키와 값을 쌍으로 저장하는 맵 구조를 나타냅니다. 그러나 두 클래스 사이에는 몇 가지 중요한 차이점이 있습니다.

동기화: Hashtable은 동기화되어 있어서, 멀티스레드 환경에서 안전(thread-safe)하게 사용할 수 있습니다. 반면에 HashMap은 동기화되어 있지 않으므로, 멀티스레드 환경에서 안전하지 않습니다. HashMap을 동기화하려면 Collections.synchronizedMap() 메소드를 사용해야 합니다.

null 허용: HashMap은 키 또는 값으로 null을 허용합니다. 하나의 null 키와 여러 개의 null 값이 허용됩니다. 반면에 Hashtable은 어떠한 형태의 null 값도 허용하지 않습니다. 키 또는 값으로 null을 사용하려고 시도하면 NullPointerException이 발생합니다.

순회 순서: HashMap은 순서를 보장하지 않습니다. 즉, 요소들은 어떠한 특정 순서로 저장되거나 순회되지 않습니다. 반면에 Hashtable도 마찬가지로 순서를 보장하지 않습니다.

효율성: HashMap은 Hashtable보다 더 효율적인 경우가 많습니다. 이는 HashMap이 동기화를 사용하지 않기 때문에, 동기화로 인한 오버헤드가 없기 때문입니다.

마지막으로, 이 두 클래스 모두 해시 테이블에 기반을 둔 맵입니다. 그러나 Java 1.2부터 HashMap이 도입되면서, Hashtable은 거의 사용되지 않게 되었습니다. 이는 HashMap이 더욱 유연하고 효율적이기 때문입니다. 따라서 동기화가 필요하지 않은 경우에는 HashMap을, 필요한 경우에는 Collections.synchronizedMap() 메소드를 사용하여 HashMap을 동기화하는 것이 일반적으로 좋은 선택입니다.

 

 

📌 List, Set, Map 의 차이점

 

📌 각각 어떤 상황에서 HashMap 과 TreeMap 을 선택하나요 ?

 

📌 HashMap 의 구현원칙에 대해

 

📌 HashSet 의 구현원칙에 대해

 

📌 ArrayList 와 LinkedList 의 차이점은 무엇인가 ?

 

📌 ArrayList 와 Vector 의 차이점에 대해서

 

📌 Queue 에서 pull() 과 remove() 의 차이점

 

📌 thread-safe 한 컬렉션 클래스들은 무엇이 있을까 ?

Java에서는 여러 쓰레드에 안전한(thread-safe) 컬렉션을 제공하고 있습니다. 이러한 컬렉션들은 동시성 컬렉션(Concurrent Collection)이라고도 부릅니다. 이러한 컬렉션들은 동기화를 통해 여러 쓰레드에서 동시에 안전하게 사용될 수 있습니다. 다음은 몇 가지 주요 동시성 컬렉션입니다:

Vector: Vector는 ArrayList와 비슷하지만, Vector의 모든 메소드는 동기화되어 있어 쓰레드에 안전합니다.

Hashtable: Hashtable은 HashMap과 비슷하지만, Hashtable의 모든 메소드는 동기화되어 있어 쓰레드에 안전합니다.

ConcurrentHashMap: ConcurrentHashMap은 HashMap과 유사하지만, 동시성 환경에서 사용될 수 있도록 설계된 맵입니다. ConcurrentHashMap은 전체 맵을 잠그는 대신 섹션(일반적으로 맵의 부분적인 영역)을 잠그는 방식을 사용하여 동시성을 향상시킵니다.

CopyOnWriteArrayList: CopyOnWriteArrayList는 ArrayList의 동시성 버전입니다. 이 클래스는 쓰레드에 안전하며, 모든 변경 사항(추가, 설정, 제거 등)이 발생할 때마다 리스트의 새로운 사본을 만듭니다.

CopyOnWriteArraySet: CopyOnWriteArraySet은 Set 인터페이스의 동시성 구현체입니다. 이 클래스는 내부적으로 CopyOnWriteArrayList를 사용합니다.

BlockingQueue 인터페이스와 그 구현체들: BlockingQueue 인터페이스는 삽입, 제거, 검사 연산을 지원하며, 큐가 비어 있을 때 제거 연산을 기다리거나 큐가 가득 찼을 때 삽입 연산을 기다리는 기능을 제공합니다. 이 인터페이스의 일반적인 구현체로는 ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue 등이 있습니다.

이러한 컬렉션들은 멀티스레드 환경에서 데이터를 안전하게 처리할 수 있게 해줍니다. 그러나 동시성 컬렉션을 사용할 때는 추가적인 오버헤드가 발생할 수 있으므로, 사용 상황에 따라 적절한 컬렉션을 선택하는 것이 중요합니다.

 

 

📌 iterator 이란 ?

Iterator는 Java의 Collection 프레임워크에서 제공하는 인터페이스로, 컬렉션에 저장된 요소들을 순차적으로 접근하는 방법을 제공합니다. 이를 통해 개발자는 컬렉션의 내부 구조를 몰라도 간편하게 요소를 탐색할 수 있습니다.

Iterator는 주로 next(), hasNext(), remove() 등의 메서드를 제공합니다.

next(): 컬렉션에서 다음 요소를 반환합니다. 다음 요소가 없을 경우 NoSuchElementException을 발생시킵니다.
hasNext(): 컬렉션에서 읽어올 다음 요소가 더 있는지 확인합니다. 다음 요소가 있으면 true를, 없으면 false를 반환합니다.
remove(): next()를 통해 최근에 반환된 요소를 컬렉션에서 제거합니다. next() 호출 없이 remove()를 호출하면 IllegalStateException이 발생합니다.
다음은 Iterator 사용의 기본적인 예제입니다:

List<String> list = new ArrayList<>();
list.add("One");
list.add("Two");
list.add("Three");

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    System.out.println(element);
}

 

 

📌 iterator 의 사용 목적은 무엇인가요 ?

 

📌 iterator 와 listlterator 의 차이는 ?

 

📌 병렬과 동시성의 차이점에 대해

"병렬처리"와 "동시성"은 종종 혼용되는 용어이지만, 그들이 지칭하는 개념은 사실상 다릅니다.

동시성(Concurrency): 동시성은 여러 작업이 동시에 실행되는 것처럼 보이게 하는 것을 의미합니다. 이는 싱글 코어 시스템에서도 가능하며, 실제로는 컴퓨터가 매우 빠르게 작업 간에 전환하면서 마치 동시에 처리되는 것처럼 보이게 합니다. 이렇게 함으로써 다수의 작업이 동시에 실행되는 것처럼 보이게 만들 수 있습니다. 이는 특히 I/O 작업을 수행하거나 다수의 작업을 동시에 처리해야 할 때 유용합니다.

병렬처리(Parallelism): 병렬처리는 여러 작업이 동시에 실제로 실행되는 것을 의미합니다. 이를 위해선 멀티코어나 멀티프로세서 시스템이 필요합니다. 병렬처리는 CPU 집약적인 작업을 수행할 때 매우 유용하며, 이를 통해 작업을 분할하고 여러 코어에서 동시에 실행하여 전체 작업 시간을 줄일 수 있습니다.

간단히 말해서, 동시성은 여러 작업을 동시에 관리하는 능력이고, 병렬처리는 여러 작업을 동시에 실행하는 능력입니다. 따라서 병렬처리 시스템은 항상 동시성을 포함하지만, 동시성 시스템이 병렬로 실행될 필요는 없습니다.

 

 

📌 스레드와 프로세스의 차이점에 대해

프로세스와 스레드는 동시성 실행을 가능하게 하는 컴퓨팅의 핵심적인 개념들입니다. 두 개념의 주요 차이는 그들의 독립성, 메모리 공간, 그리고 통신 방식에 있습니다.

프로세스(Process):
프로세스는 실행 중인 프로그램의 인스턴스를 의미합니다. 각 프로세스는 독립적인 메모리 공간, 데이터, 명령어 등을 가지며, 다른 프로세스와 정보를 공유하지 않습니다. 프로세스 간 통신은 Inter-Process Communication (IPC) 메커니즘을 통해 이루어집니다. 프로세스는 하나 이상의 스레드를 가질 수 있습니다.

스레드(Thread):
스레드는 프로세스 내에서 실행되는 가장 작은 실행 단위입니다. 모든 스레드는 해당 프로세스의 메모리 공간과 자원을 공유하며, 각 스레드는 고유한 프로그램 카운터, 레지스터 집합, 그리고 스택 공간을 가집니다. 스레드 간 통신은 주로 공유 메모리를 통해 이루어지며, 따라서 동기화에 주의를 기울여야 합니다.

따라서, 프로세스는 운영체제에 의해 스케줄링되고 관리되는 독립적인 단위이고, 스레드는 프로세스 내에서 실행되는 경량화된 실행 단위로, 자원을 공유하면서 병렬 처리를 가능하게 합니다.

 

 

📌 데몬 스레드는 무엇인가

데몬 스레드(Daemon Thread)는 Java 또는 다른 프로그래밍 언어에서 주로 백그라운드에서 실행되는 스레드를 말합니다. 이 스레드들은 일반적으로 일부 주요 작업을 지원하거나 시스템 서비스를 제공하는데 사용됩니다.

데몬 스레드의 주요 특징 중 하나는 프로그램이 종료될 때 자동으로 종료된다는 것입니다. 즉, 프로그램의 메인 스레드가 종료되면 JVM(Java Virtual Machine)은 데몬 스레드가 아직 완료되지 않았더라도 이를 중단시킵니다. 이것은 프로그램이 종료될 때 필요 없는 백그라운드 작업을 청소하는데 유용합니다.

데몬 스레드를 만드는 방법은 스레드를 생성한 후, setDaemon(true)를 호출하여 데몬 스레드로 설정하는 것입니다. 이 작업은 스레드가 시작되기 전에 수행되어야 합니다. 데몬 스레드는 보통 무한 루프 내에서 실행되며, 필요한 작업을 반복적으로 수행하거나 특정 조건이 충족될 때까지 대기합니다.

하지만 주의할 점은 데몬 스레드가 중요한 작업을 수행하고 있을 때 프로그램이 종료되면, 그 작업이 갑자기 중단될 수 있다는 것입니다. 따라서 데몬 스레드에서는 중요한 데이터를 저장하거나 리소스를 정리하는 등의 작업을 수행하지 않는 것이 좋습니다.

 

 

📌 v스레드를 만드는 방법을 나열

 

📌 runnable 과 callable 의 차이는 무엇인가 ?

 

📌 sleep() 과 wait() 의 차이는 무엇인가 ?

 

📌 thread run() 과 thread start() 의 차이는 무엇인가요 ?

 

📌 스레드 풀의 상태에 대해

 

📌 스레트 풀에서 submit() 과 execute() 의 차이

 

📌 자바 프로그램에서 멀티 스레드 작업의 안정성을 어떻게 보장할 수 있을까 ?

 

📌 reflection 이란 무엇인가 ?

 

📌 자바 직렬화란 무엇인가 ? 어떤 상황에서 필요한가 ?

 

📌 동적 프록시란 무엇인가 ?

 

📌 동적 프록시는 어떻게 사용하나 ?

 

📌 Object Copy 복사가 되는 이유는 어떻게 할 수 있나 ?

 

📌 Object Copy 객체 복사는 어떻게 할 수 있나 ?

 

📌 Object Copy 의 깊은 복사와 얕은 복사의 차이에 대해

 

📌 jsp 와 servlet 의 차이에 대해

 

📌 jsp 를 기본 제공하는 객체는 무엇인가

 

📌 4개의 jsp score 에는 무엇이 있나 ?

 

📌 세션 과정을 설명

세션은 사용자가 웹 사이트를 방문할 때부터 브라우저를 닫거나 로그아웃할 때까지 사용자의 상태를 추적하는 방법입니다. 세션은 서버 측에서 생성되고 관리됩니다. 여기에는 로그인 정보, 사용자가 장바구니에 추가한 항목 등의 정보가 포함될 수 있습니다. 세션은 클라이언트에 대한 유니크한 식별자, 즉 세션 ID를 생성하고 이를 사용하여 특정 클라이언트의 정보를 저장하고 검색합니다.

세션의 일반적인 흐름은 다음과 같습니다.

세션 생성: 사용자가 웹 사이트에 처음 접속하면, 서버는 사용자에게 고유한 세션 ID를 생성합니다. 이 세션 ID는 서버 내의 세션 저장소와 연결되어, 그 세션의 데이터를 저장하고 조회할 수 있게 합니다.

세션 ID 전달: 생성된 세션 ID는 클라이언트에게 전달되어, 클라이언트의 브라우저는 이를 쿠키나 URL 매개변수 등을 통해 저장합니다. 이후 클라이언트가 서버에 요청을 보낼 때마다 이 세션 ID를 함께 전송합니다.

세션 데이터 활용: 서버는 클라이언트로부터 받은 세션 ID를 이용해 세션 저장소에서 해당 세션의 데이터를 조회하고 활용합니다. 예를 들어, 사용자가 로그인하면 사용자의 아이디나 권한 정보를 세션 데이터에 저장하고, 이후 사용자의 요청이 들어올 때마다 이 정보를 이용해 인증 및 인가 작업을 수행할 수 있습니다.

세션 종료: 사용자가 로그아웃하거나 일정 시간동안 활동이 없는 경우(세션 타임아웃), 세션은 종료되고 세션 저장소에서 해당 세션의 데이터는 삭제됩니다.

세션은 사용자 별로 개별적으로 생성되므로, 여러 사용자가 동시에 서비스를 이용하더라도 사용자 간의 데이터가 혼선이 일어나지 않습니다. 하지만 세션 정보는 서버 메모리에 저장되므로, 과도하게 많은 세션은 서버의 부하를 초래할 수 있습니다. 따라서 적절한 세션 관리 전략이 필요합니다.

 

 

📌 쿠키를 사용할 수 없을 때 세션을 대신 사용할 수 있을까 ?

네, 사용할 수 있습니다.

세션과 쿠키는 웹 서버와 웹 브라우저 사이에서 상태를 유지하기 위해 사용되는 방법입니다. HTTP는 자체적으로 상태를 유지하지 않는(stateless) 프로토콜이므로, 이를 보완하기 위해 세션과 쿠키가 사용됩니다.

쿠키는 클라이언트(즉, 웹 브라우저) 측에 정보를 저장하고, 이 정보는 서버에 요청을 보낼 때마다 서버로 전송됩니다. 쿠키는 사용자가 사이트를 사용하는 동안에 필요한 정보(로그인 상태, 장바구니 항목 등)를 저장하는 데 사용될 수 있습니다.

그러나 쿠키가 클라이언트 측에 저장되기 때문에 보안상의 문제가 생길 수 있고, 일부 사용자는 쿠키를 비활성화하거나 제한할 수 있습니다.

이럴 때 세션을 사용할 수 있습니다. 세션 정보는 서버 측에 저장되며, 클라이언트는 세션 ID만을 갖고 있습니다. 이 세션 ID는 요청을 보낼 때마다 서버로 전송되어 해당 세션을 식별하게 됩니다. 세션은 서버 측에 저장되기 때문에 상대적으로 보안성이 높지만, 너무 많은 세션 정보가 서버의 메모리를 차지할 수 있으므로 관리에 주의해야 합니다.

따라서 쿠키를 사용할 수 없는 상황에서는 세션을 사용하여 사용자의 상태를 유지하고 식별하는 것이 가능합니다.

 

 

📌 스프링 MVC 와 struts 의 차이는 무엇인가 ?

Struts와 Spring MVC는 모두 Java 기반 웹 애플리케이션 개발을 위한 프레임워크입니다. 그러나 구조, 설계, 기능 등에 있어 몇 가지 차이점이 있습니다:

설계와 구조:

Struts는 액션 기반 MVC(Model-View-Controller) 패턴을 따르는 웹 프레임워크입니다. Struts는 웹 요청을 처리하고 라우팅하기 위해 '액션'과 '액션 맵핑'을 사용합니다. 이는 주로 고정된 페이지 흐름을 가진, 웹 애플리케이션에 적합합니다.
반면에 Spring MVC는 더 유연한 접근 방식을 제공하는 프론트 컨트롤러 패턴을 사용합니다. Spring MVC는 강력한 디스패처 서블릿이 웹 요청을 적절한 컨트롤러에 라우팅합니다. 이는 동적 페이지 흐름을 가진 웹 애플리케이션에 적합합니다.
통합:

Struts는 일반적으로 웹 계층에 초점을 맞춘 웹 프레임워크로, 다른 기술과의 통합은 개발자의 책임입니다.
Spring MVC는 Spring Framework의 일부로, 데이터 엑세스, 트랜잭션 관리, 설정, 보안 등과 같은 많은 기능들을 통합하고 지원합니다.
유지 관리와 지원:

Struts는 이전에 많이 사용되었지만, 2017년에 발생한 심각한 보안 이슈 이후로 사용이 감소했습니다. Struts 2는 아직도 지원되지만, 그 활동은 상당히 줄어들었습니다.
Spring MVC는 Spring 커뮤니티의 강력한 지원을 받고 있으며 지속적으로 업데이트와 개선이 이루어지고 있습니다. 또한 Spring Boot와 같은 도구를 이용해 초기 설정 과정이 간소화되었습니다.
테스트 용이성:

Spring MVC는 의존성 주입(DI)를 이용해 유닛 테스트와 통합 테스트를 쉽게 작성할 수 있습니다.
Struts에서의 테스트 작성은 Spring MVC보다 상대적으로 복잡할 수 있습니다.
따라서 선택은 프로젝트의 요구사항, 팀의 기술적 능력, 필요한 기능 등 여러 요인에 따라 달라질 수 있습니다.


📌 SQL Injection 을 피할 수 있는 방법은

SQL Injection은 공격자가 악의적인 SQL 코드를 웹 어플리케이션의 데이터베이스에 주입하는 공격입니다. 이런 공격은 데이터베이스의 데이터를 볼 수 있게 하거나, 변경하거나, 심지어는 데이터베이스의 제어를 완전히 잃게 만들 수 있습니다. 다음은 SQL Injection 공격을 피하는 몇 가지 방법입니다:

Prepared Statements (Parameterized Queries) 사용: Prepared Statements는 SQL 쿼리에서 특정 값을 파라미터로 전달하여 사용할 수 있게 하는 기능입니다. 이 기능은 데이터베이스에 쿼리를 전송하기 전에 모든 파라미터의 값을 적절하게 이스케이프 하기 때문에 SQL Injection 공격을 방지하는 데 매우 효과적입니다.

Stored Procedures 사용: Stored Procedures는 데이터베이스에서 직접 실행되는 코드 블록입니다. 이 방식도 Prepared Statements와 유사하게 SQL Injection을 방지할 수 있습니다.

입력값 검증: 사용자로부터 받는 모든 입력은 적절한 형식과 길이를 가지고 있는지 반드시 검증해야 합니다. 검증을 통해 불필요한 또는 악의적인 값을 걸러낼 수 있습니다.

최소 권한의 원칙: 애플리케이션의 데이터베이스 계정은 필요한 최소한의 권한만을 가져야 합니다. 이렇게 하면, 만약 공격이 성공하더라도 공격자가 할 수 있는 피해를 최소화할 수 있습니다.

에러 메시지 관리: 상세한 에러 메시지는 공격자에게 공격을 더 쉽게 수행할 수 있는 정보를 제공할 수 있습니다. 예를 들어, "table 'users' does not exist"와 같은 에러 메시지는 공격자에게 'users'라는 테이블이 존재하지 않음을 알려주므로 공격에 도움을 줄 수 있습니다. 따라서 에러 메시지는 사용자에게 보여주지 않거나 최대한 추상화된 정보만을 제공해야 합니다.

웹 어플리케이션 방화벽 (WAF) 사용: WAF는 악의적인 웹 트래픽을 감지하고 차단하는 보안 레이어입니다. WAF는 일반적으로 알려진 SQL Injection 패턴을 감지하고 차단하여 이런 종류의 공격을 방지하는 데 도움을 줍니다.

이와 같은 방법들을 사용하여 SQL Injection 공격을 방어할 수 있습니다. 그러나 항상 가장 최신의 보안 연구와 최선의 보안 관행을 따르는 것이 중요합니다.

 

 

📌 XSS 공격이 무엇이고, 피할 수 있는 방법은

XSS(Cross-Site Scripting) 공격은 웹사이트에 악의적인 스크립트를 삽입하는 공격 방법입니다. 사용자의 웹 브라우저에서 실행되는 이 스크립트는 사용자의 데이터를 탈취하거나 사용자를 다른 웹페이지로 리다이렉트하거나 웹사이트의 동작을 변조하는 등의 행위를 할 수 있습니다.

XSS 공격은 크게 세 가지 종류로 분류됩니다: Stored XSS, Reflected XSS, 그리고 DOM-based XSS. Stored XSS는 사용자 입력값이 검증 없이 데이터베이스에 저장되고, 이후에 그 값을 출력할 때 스크립트가 실행되는 형태입니다. Reflected XSS는 URL에 포함된 악의적인 스크립트가 웹사이트에 반영되어 실행되는 형태입니다. DOM-based XSS는 자바스크립트를 이용해 DOM의 구조나 내용을 변경하면서 발생하는 XSS 공격입니다.

XSS를 피하는 방법:

사용자 입력값 검증 및 이스케이핑: 사용자로부터 입력 받는 모든 데이터는 웹사이트에서 그대로 출력되기 전에 반드시 이스케이핑(특수 문자를 안전한 형태로 변환)되어야 합니다. 또한 가능한 경우 사용자 입력값에 대해 강력한 검증을 수행해야 합니다.

콘텐츠 보안 정책(Content Security Policy, CSP): CSP는 웹사이트가 실행할 수 있는 스크립트의 출처를 제한하는 방법입니다. CSP는 웹 브라우저에게 어떤 출처의 스크립트를 실행할지 지시할 수 있습니다. 이를 통해 공격자가 웹사이트에 악의적인 스크립트를 삽입하는 것을 방지할 수 있습니다.

HTTP-only 쿠키 사용: HTTP-only 쿠키는 자바스크립트를 통해 접근할 수 없도록 설계되어 있습니다. 이를 통해 XSS 공격으로 인한 쿠키 탈취를 막을 수 있습니다.

이 외에도 XSS 공격을 방어하기 위한 다양한 방법들이 있습니다. 예를 들면, 사용자가 입력한 내용을 안전하게 표현할 수 있도록 프레임워크나 라이브러리의 지원을 받는 것이 있습니다. 예를 들어, React와 같은 프레임워크는 기본적으로 사용자 입력값을 이스케이핑하여 XSS 공격을 방지합니다.

 

 

📌 CSRF 공격이 무엇이고, 피할 수 있는 방법은

CSRF(Cross-Site Request Forgery)는 웹 사이트 취약점을 이용하여 사용자가 자신의 의지와는 무관하게 공격자가 선택한 행동을 실행하게 하는 공격 방법입니다. 이 공격은 사용자가 로그인한 상태에서 발생하며, 공격자는 사용자의 권한을 이용해 비정상적인 요청을 서버에 보낼 수 있습니다.

예를 들어, 사용자가 온라인 뱅킹 서비스에 로그인해 있는 상황에서 공격자가 만든 웹사이트를 방문하면, 이 웹사이트는 사용자의 뱅킹 서비스에 대한 악의적인 요청을 만들어 보낼 수 있습니다. 이 경우 사용자는 자신도 모르게 공격자가 지정한 계좌로 자신의 돈을 송금하게 될 수 있습니다.

CSRF를 피하는 방법:

SameSite 쿠키: 최신 브라우저는 SameSite 쿠키 설정을 지원합니다. 이 설정은 쿠키가 같은 사이트에서만 전송되도록 합니다. 즉, 사용자가 웹사이트 A에 로그인하고 있다고 해도, 웹사이트 B에서는 A의 쿠키를 이용할 수 없습니다.

CSRF 토큰: 서버는 매 요청마다 고유한 CSRF 토큰을 생성하고 이를 세션에 저장합니다. 클라이언트는 이 토큰을 요청에 포함시켜 서버로 보내고, 서버는 이 토큰이 요청마다 일치하는지 확인합니다. 공격자는 CSRF 토큰을 알 수 없으므로 이 방법이 CSRF 공격을 막는 데 효과적입니다.

검증된 Referrer 헤더 사용: 이 방법은 HTTP 요청 헤더의 Referer를 확인해 요청이 신뢰할 수 있는 소스에서 발생했는지 확인하는 것입니다. 하지만 헤더 조작 가능성과 프라이버시 문제 때문에 이 방법만으로는 충분하지 않을 수 있습니다.

이 외에도 사용자의 행동을 잘 관찰하고 비정상적인 패턴을 탐지하는 등 다양한 방법으로 CSRF 공격을 방어할 수 있습니다.

728x90
반응형