- JRE, JDK의 차이점
- JRE - Runtime관련
- JDK - 개발 + JRE
- == 과 equals의 차이점
- 오버라이딩한 객체를 비교할때 ==과 equals는 같은 동작을 진행한다
- 하지만 str1과 str2가 각각 있다고 가정했을떄 equals는 true지만 == 는 false가 나온다
- equals → 객체 내용비교
- == → 같은 객체 또는 같은 참조(주소)를 비교 (기본 데이터는 값을, 객체는 참조위치(메모리주소)를 비교)
- 2개의 객체가 동일한 HashCode를 갖고있으면 무조건 equals가 true로 나와야하는가?
- 아니다. HashCode는 해싱 기법에 사용되는 해시함수를 구현한것이다.
- 해시충돌 - 서로 다른 객체나 데이터가 동일한 해시 코드를 갖는문제
public int hashCode() { int h = 0; int len = value.length; for (int i = 0; i < len; i++) { h = 31 * h + value[i]; } return h; } //h = 31 * h + value[i]: //이는 각 문자의 유니코드 값을 더하면서, 31이라는 소수를 곱해 누적된 해시 코드를 계산하는 방식 //문자열의 길이가 같거나, 특정 값에 의해 충돌이 발생할 수 있습니다. //"FB"와 "Ea"는 서로 다른 문자열이지만 해시 코드가 같습니다(2236). // F의 유니코드 값은 70, B의 유니코드 값은 66. // h = 31 * 0 + 'F' = 70 // h = 31 * 70 + 'B' = 2236. // E의 유니코드 값은 69, a의 유니코드 값은 97. // 해시 코드는 h = 31 * 0 + 'E' = 69, 그리고 h = 31 * 69 + 'a' = 2236.
- 자바의 final의 기능
- 변수,메서드, 클래스 등에 변형이 안되도록 수정을 막아버리는것
- 변수 - 값 변경, 중간할당 불가 (초기화 값이 그대로감)
- 메서드 - 오버라이드 불가
- 클래스 - 상속불가
- 자바의 Math.Round(-1,5)의 결과는?
- 반올림을 진행하는데 -1번쨰 자리(소수점 첫번째에서 반올림)
- 5 초과는 올림, 5 이하는 내림
- String은 기본타입?
- String는 int, char 같은 기본 데이터 타입이 아닌 참조 데이터 타입이다
- Stack이 아닌 Heap부분에서 문자열 데이터가 생성된다 →
- String은 불변이라 String a = “A”: a+”B”일때 a에 글자를 더하는게 아닌 AB를 새로 만들어 주소를 다시 참조하는 형태이다
- “AB”가 아닌 “A”는 gabage가 되며 GC가 이를 수집하고 삭제한다
- JAVA에선 성능 최적화를 위해 String Pool 이란걸 사용하는데 동일한 내용의 String 객체는 메모리 낭비를 막기위해 재사용된다.
- 자바의 문자열을 조작하는 클래스
- 앞서 말한 Stirng의 불변성으로 인해 문자열을 조작할경우 성능적인 낭비가 발생할수있으며 StringBuffer, StringBuilder를 사용하여 해당 문제를 해결할수 있다.
- StirngBuffer - 멀티쓰레드 환경에서도 안전하다 → 동기화(synchronized)가 자동으로 적용, 문자열을 자주 변경할경우 성능저하를 피할수있다.
- StringBuilder - StringBuffer에서 동기화만 빠진것 → 단일 스레드 환경에선 더욱 빠른 성능을 제공한다
- String str = “i”와 String str = new String(”i”)가 동일할까?
- 다르다!
- str i 는 문자열 상수를 선언하는 형태로 i 라는 문자열이 만들어지며 JVM의 constant pool(상수 풀)에 저장된다.
- 만일 str2 - “i”를 사용할경우 상수풀에 존재하는 i를 돌려쓰는는것이다. (싱글톤)
- new String은 새로운 String 객체를 생성하는 방식으로 i가 상수 풀에 존재하여도 JVM이 관리하는 heap 공간에 새로운 객체를 저장한다.
- 만일 str2 =”i”를 선언하고 str과 비교할경우 두 변수가 같은 주소를 가리키며 str2 = new String(”i”)를 할경우 서로 다른 주소를 가리킨다.
- 문자열을 반복시키는 가장 좋은 방법
- 리스트를 사용해 반복문으로 변경시키는 방법
- 직접 리스트를 만들어 반복문으로 변경하는 작업
String b = "asdf"; sb = new StringBuilder(); char[] charArray = b.toCharArray(); for(int i = chrArray.length -1; i>=0; i--){ sb.append(charArray[i]); }
- 라이브러리 메서드를 이용하는 방법 (StringBuilder,StringBuffer)
- StringBuilder
String a = "asdf"; StringBuilder sb = new StringBuilder(); sb.append(a).reverse();
- 리스트를 사용해 반복문으로 변경시키는 방법
- String 클래스의 일반적인 메서드
- endWith : 문자열 마지막에 지정한 문자가 있는지 판단후 있으면 true, 없으면 false 반환
- equlas : Object의 메서드이나 오버라이드된것으로 String의 값만 비교해 True, false 를 반환한다
- indexOf : 지정한 문자가 문자열 몇번째에 있는지 반환
- length : 문자열 길이 반환
- replace : 문자열에 지정한 문자 “asd”가 있으면 “hello”로 바꿔서 출력
- subString : 문자열에 지정한 범위에 속하는 문자열을 반환 (시작범위 값은 포함, 끝나는 범위 값은 미포함)
- 추상클래스의 추상 메서드는 필수인가?
- 추상메서드는 필수가 아니며 추상클래스는 추상메서드를 갖지않아도 무방하다.
- 추상클래스 - abstract를 사용해 선언된것, 인스턴스화 불가
- 추상메서드 - 구현부가 없는 메서드로 추상클래스는 추상메서드를 0개 가질수 있다.
- 구체클래스 - 추상클래스를 할당받은 클래스로 추상메서드를 무조건 구현해야한다
- 보통 클래스와 추상클래스의 차이
- 실제 내용이 안들어가있어도 문제가 없다.
- 클래스의 상속에선 부모 메서드를 오버라이딩 하는것이 필수가 아니며 자식에게 특정 메서드를 구현하라고 강요할수 없다.
- 추상클래스는 추상 메서드를 자식 클래스가 구현하는게 강제이기에 해당 클래스를 상속받는 자식클래스는 항상 해당 메서드를 구현해야한다.
- final은 추상클래스를 수정할때 사용이 가능한가?
- final이 붙는순간 상속이 불가능한 클래스로 바뀐다 → 추상클래스는 자체로 인스턴스가 불가능 하기에 구체 클래스에게 상속을 해줘야 한다 → 상속불가한데 상속을 해줘야한다? → 컴파일 에러
- 애초에 final과 abstract는 같이 붙을수 없고 컴파일 단계에러 에러가 나온다
- 자바 컨테이터란?
- 객체들을 저장하기 위한 저장소(컨테이너도 객체!)이다.
- 배열은 원시타입의 배열을 사용할떄 크기를 미리 선언해놓는데 1번 정할경우 바꿀수 없는 제약이 생긴다
- 이때 자바 컨테이너가 java.util 라이브러리에 컨테이너 클래스가 있으며 List,Set,Queue,Map이 존재한다.
- Collection, Collections의 차이
- Collection - 데이터의 자료구조를 다루는 Collection 프레임워크(List, Set, Map*)에 필요한 메서드가 선언되있는 인터페이스
- add,contains,clear 등 자료구조 관련 메서드가 정의되있따.
- Map은 Collection을 구현하지 않았으나 Collection으로 본다. (Key-값의 쌍)
- Collections - 컬렉션과 관련된 메서드를 제공하는 클래스
- fill, copy, sort등과 같은 Arrays에서 제공하는 메서드들은 물론 멀티 쓰레드 프로그래밍에 필요한 동기화 처리가 가능하도록 제작된 Collection을 반환하는 메서드도 제공
- Collection - 데이터의 자료구조를 다루는 Collection 프레임워크(List, Set, Map*)에 필요한 메서드가 선언되있는 인터페이스
- List,Set,Map의 차이점
- List - 순서가 있는 데이터구조로 중복을 허용, 인덱스를 통해 데이터 접근이 가능 (ArrayList, LinkedList)
- Set - 순서가 없고 중복값 미허용(중복값은 자동으로 제거), 순서가 없기때문에 iterator(순차접근)를 사용하여 검색속도가 빠르다 (HashSet, TreeSet)
- Map - key,value의 형태로 key는 미중복, value는 중복허용, iterator를 사용하여 접근은 ㄱ가능하나 KeySet(), entrySet()을 사용해 순회해야한다 (HashMap,TreeMap)
- HashMap과 Hashtable의 차이
- HashMap
- 동기화가 보장되지 않아 멀티스레드 환경에서 불안전하나 단일 스레드에선 더 나은 성능을 제공
- 검색에 뛰어난 성능을 갖고 Key,value로 null을 허용한다
- HashTable
- 동기화가 보장되어 멀티스레드 환경에서 사용이 가능
- HashMap보다 처리속도가 느리다.
- Key,Value로 Null이 허용되지 않는다.
- HashMap
- 어떤 상황에서 HashMap과 TreeMap을 사용하는가?
- HashMap은 해시함수를 사용하여 빠른 탐색시간을 갖는게 장점(O(1))이며 정렬되지 않는다(key로 검색해버리면 되니까!)
- TreeMap은 HashMap보다 느린탐색(O(logN))을 갖는다
- TreeMap은 Red-Black Tree로 관리하여 Key값을 기준으로 정렬된 상태를 유지하는데 key가 오름차순으로 자동정렬되기에 정렬된 순서로 데이터에 접근한다
- 정렬보다 빠른 탐색을 우선해야 할경우 HashMap을 사용
- 빠른 탐색보다 정렬이 우선되면 TreeMap을 사용
- 추가 궁금증 - key가 0~100까지 있다고 가정했을때 30번째 key를 찾는다고 가정했을때 TreeMap은 3~4번이면 찾는게 아닌가??
- HashMap은 key를 입력받았을때 해시값으로 계산한뒤 이를 이용해 한번에 위치를 특정할수 있다.
- TreeMap은 이진탐색으로 0~50, 51~100(루트노드) → 0~25, 26~50 → … 이런 형식으로 나무 뿌리처럼 타고 들어가기에 더 느리다.
- 만약 해시 충돌이 나타날경우 hash값에 여러개의 key가 매핑될수도 있는데 해시값이 존재하는 버킷에서 체이닝, 오픈 어드레싱 방식으로 충돌을 처리한다. (키가 30개인데 테이블(버킷) 크기가 10개면 3개씩 중복이 나타나는데 이런경우 해시충돌이 발생한다)
- 버킷 - 해시 테이블에서 데이터를 저장하는 공간 (key의 해시값 보관소)
- 체이닝 - 하나의 버킷에 여러개의 요소를 저장하는 방법으로 해당 버킷에 있는 데이터를 리스트 형태로 저장하며 삽입된 데이터는 버킷의 리스트 끝에 추가되고 해당 해시값에 매핑된 리스트를 순회하며 원하는값을 탐색
- 버킷 0: (key1 -> value1) -> (key3 -> value3) 해당 상황에서 key1과 key3은 동일한 해시값을 갖게되어 버킷 0번에 들어가있는 형태이다. 여기서 사용자가 key3을 검색할경우 순차적으로(key1 -> key3의 순서) 탐색하며 키가 일치할경우 해당하는 값을 반환 index 목적으로 사용되는 key1,key3의 해시값이 123123으로 동일할경우 해시충돌이 일어나며 이때 index키가 같으니 대신 사용할수 있는 후보키로 key의 value를 사용하여 한번 더 탐색
- 오픈 어드레싱 - 충돌이 발생했을떄 빈 버킷을 찾아 데이터를 저장하는형식으로 1개의 버킷에 여러 요소를 저장하는게 아닌 비어있는 버킷을 찾아서 저장한다
- HashMap의 구현원칙
- Key는 저장된 값을 찾기위하여 컬렉션 내부에서 유일해야한다 (PK일것)
- HashMap은 내부적으로 Entry 또는 Node라는 내부 객체로 묶어서 저장하게되는데 키-값 쌍을 저장하는 형태라 키와 값 서로 연관성을 유지할수 있게된다. HashMap의 1개 배열엔 Entry, Node 객체가 저장되며 그 안에서 key와 value가 같이 저장된다.
- 즉, 1개의 HashMap은 키와 값이 서로 연관된 값이기에 키, 값을 각자 배열로 사용하여 필요할때마다 가져오기 보단 키,값을 1개의 클래스로 정의해 둘을 1개의 배열로 다루는것이 데이터 무결성측면에서 더 바람직하기 떄문이다
- HashMap의 hashCode는 Object의 hashCode메서드를 사용하며 각 주소값을 해싱하기에 가장 좋은 방식이기도 하지만 String 클래스와 비슷하게 equals를 재정의 해야한다면 hashCode도 재정의 해야 해싱을 구현한 컬렉션 클래스도 정상적인 동작이 가능하다
- HashMap은 HashCode를 사용해 해당 객체가 저장될 객체를 결정하는데 같은 해시코드를 가진 키는 같은 버킷에 저장되며 버킷에서 equals로 동일한 키인지 검사르 진행한다.
- HashCode(버킷위치 - 저장주소), equals(객체 동일여부)
- 만일 a=b 를 진행할경우 equals()를 재정의 한다면 둘은 동일한 객체가 되는데 HashCode는 해당 객체가 동일한 HashCode를 반환해야한다
- 하지만 a는 1번버킷, b는 2번 버킷에 저장되어있기에 다른 HashCode를 가지며 이로인해 키를 제대로 못찾게된다.
a = (1,test) b = (2,hello) a=b a = (1,test), b= (2,test)
- HashSet의 구현원칙
- HashSet을 구현할땐 Set의 특징처럼 중복된 요소가 저장되면 안되며 저장순서를 유지하지 않는다.
- HashSet의 hashCode는 Object의 hashCode 메서드를 사용하여 각주소값을 해싱해야 정상적으로 동작한다.
- 오버라이딩을 통해 작성된 hashCode가 만족해야할 3가지 조건
- 실행중인 애플리케이션에서 동일한 객체에 대해 여러번 hashCode를 호출할때 동일한 int를 반환해야한다(실행할떄마다 동일한 int를 반환할 필요는없다) → 일관성
- equals메서드를 이용한 비교에서 true를 얻은 두 객체는 hashCode()로 해시값을 호출했을떄 항상 같아야한다. →
- 서로 다른 객체들에 대해 반드시 다른 해시코드를 반환할 필요는 없지만 가급적 서로 다른 해시코드를 반환하는게 바람직하다. → equals로 false를 반환하는 객체는 같은 hashCode를 가질수 있으나 서로 다른 해시코드를 반환하는게 효율적이다.
- equals는 내용이 같은지 비교하는 함수인데 hashcode가 동일할수가 있다 (해시충돌) 3-2 문항 참조
String str1 = "FB"; String str2 = "Ea"; System.out.println(str1.hashCode()); // 2236 System.out.println(str2.hashCode()); // 2236 System.out.println(str1.equals(str2)); // false
'JAVA' 카테고리의 다른 글
Call by value와 Call by reference (0) | 2024.02.24 |
---|---|
DocumentBuilderFactory와 예제 (0) | 2024.02.18 |
스레드풀 (0) | 2023.03.07 |
프로세스와 스레드 (0) | 2023.03.07 |
동일성(identity)과 동등성(equality) (0) | 2023.02.26 |