게시글
질문&답변
파일 input,output 말하는 스트림의 뜻을 모르겠습니다.
IO 기본1 의 InputStream, OutputStream에 설명해주십니다!저는 스트림을 크기가 무제한인 바이트 큐로 보면 이해하기 쉽더라구요. 읽을 때는 내가 큐에서 빼는 사람이 되는 거고, 쓸 때는 큐에 넣는 사람이 되는 거구요. 바이트가 쭉 흘러들어오는 파이프라고 볼 수도 있구요. 하지만 큐처럼 순서대로 들어와야하고, 항상 한 방향으로만 흐르는 거죠.
- 0
- 2
- 61
질문&답변
Join 실습 질문
메인 스레드가 RUNNABLE 상태에서만 log()를 실행할 수 있으므로 항상 RUNNABLE이 출력됩니다.생각하는자 님이 적어주신 코드처럼 상태를 조회하는 스레드와 log를 출력하는 스레드를 분리하면 WAITING을 확인할 수 있습니다.제가 실행한 코드는 다음과 같습니다. 길이를 줄이기 위해 SumTask의 계산 부분을 제거하고 Task 생성 부분은 인라인으로 넣었습니다.package thread.control.test; import static util.MyLogger.log; import static util.ThreadUtils.sleep; public class JoinMainV3 { public static void main(String[] args) { Thread mainTask = new Thread(new MainTask(), "MainTask"); mainTask.start(); log("MainTask 스레드 상태: " + mainTask.getState()); sleep(1000); log("MainTask 스레드 상태: " + mainTask.getState()); sleep(1500); log("MainTask 스레드 상태: " + mainTask.getState()); } static class MainTask implements Runnable { @Override public void run() { log("Start"); Thread thread1 = new Thread(new Task(), "thread-1"); Thread thread2 = new Thread(new Task(), "thread-2"); thread1.start(); thread2.start(); log("join() - MainTask 스레드 대기 시작"); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } log("MainTask 스레드 대기 완료"); log("End"); } } static class Task implements Runnable { @Override public void run() { log("작업 시작"); sleep(2000); log("작업 완료"); } } }로그 결과는 다음과 같습니다. 두 번째 조회 시 WAITING 상태가 나오는 것을 확인할 수 있습니다.11:02:29.123 [ main] MainTask 스레드 상태: RUNNABLE 11:02:29.124 [ MainTask] Start 11:02:29.143 [ MainTask] join() - MainTask 스레드 대기 시작 11:02:29.146 [ thread-1] 작업 시작 11:02:29.147 [ thread-2] 작업 시작 11:02:30.149 [ main] MainTask 스레드 상태: WAITING 11:02:31.155 [ thread-2] 작업 완료 11:02:31.155 [ thread-1] 작업 완료 11:02:31.156 [ MainTask] MainTask 스레드 대기 완료 11:02:31.157 [ MainTask] End 11:02:31.663 [ main] MainTask 스레드 상태: TERMINATED
- 0
- 2
- 70
질문&답변
[12:42] 구두 설명과 pdf 설명이 다른 부분의 질문
강의자료 해당 부분 위의 설명에 "main 스레드가 4초 뒤에 work 스레드에 interrupt()를 건다." 라는 설명이 있으므로, TIMED_WAITING 상태에 있는 것은 work 스레드가 맞습니다.또 사소하지만 2번에서 "이때 work 스레드는 Thread.sleep(3000)으로 인해 TIMED_WAITING 상태였는데"라고 말씀해주셨는데, while문의 조건을 확인하고 있거나 log를 찍고 있을 수도 있을 것 같습니다. 이후 거의 즉시 Thread.sleep(3000)을 호출하여 예외가 발생할 것이므로 크게 차이는 없겠지만요.나머지는 모두 잘 이해하신 것 같습니다!
- 0
- 2
- 87
질문&답변
hashCode를 오버라이딩 했을때 반환하는게 틀려요.
AI 답변에 추가하면 IntelliJ를 통해 각 메소드를 따라가보면 다음과 같습니다.public final class Objects { public static int hashCode(Object o) { return o != null ? o.hashCode() : 0; } public static int hash(Object... values) { return Arrays.hashCode(values); } } public final class Arrays { public static int hashCode(Object[] a) { if (a == null) return 0; int result = 1; for (Object element : a) result = 31 * result + (element == null ? 0 : element.hashCode()); return result; } }따라서 hashCode(id) + 31 = hash(id)로 나옵니다.또한 IntelliJ의 자동완성 기능은 AI 답변과 같이 매개변수가 하나이기 때문에 hashCode()를 추천한 것으로 보입니다.
- 1
- 2
- 299
질문&답변
제네릭 상한 설정을 위해 생성자를 활용하는 것이 extends보다 못한 점이 무엇인가요?
생각하는자 님의 답변에 첨언하면, Box에서 T는 아무 클래스나 올 수 있기 때문에 다음과 같은 코드도 가능합니다.Cat cat = new Cat("고양이", 100); Box foodBox = new Box(cat);이때 Animal → Food로의 변환은 타입매개변수 T를 사용하기에 컴파일러가 확인하지 않아 오류가 발생하지 않습니다.그런데 만약 Box에public T getAnimal() { return animal; }와 같이 getAniaml()이 있다면,Food food = foodBox.getAnimal();에서 Animal → Food 로 타입을 바꾸려 시도하기 때문에 ClassCastException이 발생합니다.따라서 클래스 내 모든 T에 제약을 걸기 위해 을 사용하는 것입니다.
- 0
- 2
- 121
질문&답변
다운캐스팅
System.out.println(obj);로 출력하는 경우 println() 내부적으로 Object 클래스의 toString() 메소드를 호출하여 String 객체를 사용하기에 문제가 없습니다.
- 0
- 2
- 99