private static int incrementAndGet(AtomicInteger atomicInteger) { int getValue; boolean result; do { getValue = atomicInteger.get(); log("getValue: " + getValue); result = atomicInteger.compareAndSet(getValue, getValue + 1); log("result: " + result); } while (!result); return getValue + 1; } getValue = atomicInteger.get(); 에서 조회한 값이 compareAndSet() 연산을 할때 바뀌지 않아야 바꿀려고 한 값으로 바꾸고 true를 반환한다고 이해했습니다. 궁금한 부분은 getValue = atomicInteger.get(); 여기서 값을 조회하거나 중간에 스레드가 바꾼 값을 조회 한다는걸 compareAndSet()에서 구분을 할 수 있나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용] 여기에 질문 내용을 남겨주세요. package generic.ex4; // 클래스 옆에 <> 넣으면 제네릭 타입 public class GenericMethod { public static Object objMethod(Object obj) { System.out.println("Object print: " + obj); return obj; } // 메서드 안에 <> 넣으면 제네릭 메서드 public static <T> T genericMethod(T t) { System.out.println("Generic print: " + t); return t; } public static <T extends Number> T numberMethod(T t) { System.out.println("bound print: " + t); return t; } } 여기 public static <T> T genericMethod(T t) 코드를 보면 static일 때 사용이 가능한데 강의 자료에서 여기 static일 땐 사용이 불가능하다는 말이 이해가 잘 안 갑니다. 둘의 차이점이 무엇인가요?
CPU 코어와 메모리가 동작하는 이미지가 자주 나왔는데요 헷갈리는 부분이 있어서 질문 합니다. 스레드, 프로세스, 메모리 등 여러 개념들이 존재하지만 CPU와 직접적으로 통신(?) 하는 주체는 스레드라고 이해를 해도 될까요? 1번이 맞다면 스레드는 본인이 실행한 코드 한줄 한줄을 CPU로 보내고 CPU는 해당 코드 한줄을 해석하고 그에 따라서 프로세스에 할당된 메모리 영역(힙, 데이터, 코드)이나 스레드에 할당된 메모리 영역(스택)에 접근해서 데이터를 읽거나 저장한다 라고 이해를 해도 될까요? Java 의 thread 는 OS의 kernel thread 와 1:1로 mapping 되는걸로 알고 있는데 그러면 CPU는 kernel thread 와 통신 한다고 이해하면 될까요?
property.arraySize이 문제인것 같은데 private void DrawSkillDatas() { // Skill의 Data가 아무것도 존재하지 않으면 1개를 자동적으로 만들어줌 if (skillDatasProperty.arraySize == 0) { // 배열 길이를 늘려서 새로운 Element를 생성 skillDatasProperty.arraySize++; // 추가한 Data의 Level을 1로 설정 skillDatasProperty.GetArrayElementAtIndex(0).FindPropertyRelative("level").intValue = 1; } if (!DrawFoldoutTitle("Data")) return; EditorGUILayout.PropertyField(isAllowLevelExceedDatasProperty); // Level 상한 제한이 없다면 MaxLevel을 그대로 그려주고, // 상한 제한이 있다면 MaxLevel을 상한으로 고정 시키는 작업을 함 if (isAllowLevelExceedDatasProperty.boolValue) EditorGUILayout.PropertyField(maxLevelProperty); else { // Property를 수정하지 못하게 GUI Enable의 false로 바꿈 GUI.enabled = false; var lastIndex = skillDatasProperty.arraySize - 1; // 마지막 SkillData(= 가장 높은 Level의 Data)를 가져옴 var lastSkillData = skillDatasProperty.GetArrayElementAtIndex(lastIndex); // maxLevel을 마지막 Data의 Level로 고정 maxLevelProperty.intValue = lastSkillData.FindPropertyRelative("level").intValue; // maxLevel Property를 그려줌 EditorGUILayout.PropertyField(maxLevelProperty); GUI.enabled = true; } EditorGUILayout.PropertyField(defaultLevelProperty); for (int i = 0; i < skillDatasProperty.arraySize; i++) { var property = skillDatasProperty.GetArrayElementAtIndex(i); var isUseCastProperty = property.FindPropertyRelative("isUseCast"); var isUseConcentrateProperty = property.FindPropertyRelative("isUseConcentration"); var chargeDurationProperty = property.FindPropertyRelative("chargeDuration"); var chargeTimeProperty = property.FindPropertyRelative("chargeTime"); var needChargeTimeToUseProperty = property.FindPropertyRelative("needLeastChargeTime"); var perfectDamageChargeTimeProperty = property.FindPropertyRelative("perfectDamageChargeTime"); var perfectDamageChargeTimeDetectionProperty = property.FindPropertyRelative("perfectDamageTimeDetection"); EditorGUILayout.BeginVertical("HelpBox"); { // Data의 Level과 Data 삭제를 위한 X Button을 그려주는 Foldout Title을 그려줌 // 단, 첫번째 Data(= index 0) 지우면 안되기 때문에 X Button을 그려주지 않음 // X Button을 눌러서 Data가 지워지면 true를 return함 if (DrawRemovableLevelFoldout(skillDatasProperty, property, i, i != 0)) { // Data가 삭제되었으며 더 이상 GUI를 그리지 않고 바로 빠져나감 // 다음 Frame에 처음부터 다시 그리기 위함 EditorGUILayout.EndVertical(); break; } EditorGUI.indentLevel += 1; if (property.isExpanded) { // SkillData Property 내부로 들어감 -> Property == level field; property.NextVisible(true); DrawAutoSortLevelProperty(skillDatasProperty, property, i, i != 0); // Level Up for (int j = 0; j < 2; j++) { property.NextVisible(false); EditorGUILayout.PropertyField(property); } // PrecedingAction // Toggle Type일 때는 PrecedingAction을 사용하지 않을 것이므로, // Instant Type일 때만 PrecedingAction 변수를 보여줌 property.NextVisible(false); if (useTypeProperty.enumValueIndex == (int)SkillUseType.Instant) EditorGUILayout.PropertyField(property); // Action And Setting for (int j = 0; j < 8; j++) { // 다음 변수의 Property로 이동하면서 그려줌 property.NextVisible(false); EditorGUILayout.PropertyField(property); } // Cast property.NextVisible(false); if (IsDrawPropertyAll && !isUseConcentrateProperty.boolValue) EditorGUILayout.PropertyField(property); else property.boolValue = false; property.NextVisible(false); if (isUseCastProperty.boolValue) EditorGUILayout.PropertyField(property); // Charge property.NextVisible(false); if (IsDrawPropertyAll && !isUseCastProperty.boolValue) EditorGUILayout.PropertyField(property); for (int j = 0; j < 5; j++) { property.NextVisible(false); if (isUseConcentrateProperty.boolValue) EditorGUILayout.PropertyField(property); } // 최대 chargeTime 값을 chargeDuration 값으로 제한 chargeTimeProperty.floatValue = Mathf.Min(chargeTimeProperty.floatValue, chargeDurationProperty.floatValue); // 최대 needChargeTime 값을 chargeTime 값으로 제한 needChargeTimeToUseProperty.floatValue = Mathf.Min(chargeTimeProperty.floatValue, needChargeTimeToUseProperty.floatValue); perfectDamageChargeTimeProperty.floatValue = Mathf.Clamp(perfectDamageChargeTimeProperty.floatValue, needChargeTimeToUseProperty.floatValue, chargeTimeProperty.floatValue); // Effect property.NextVisible(false); EditorGUILayout.PropertyField(property); //// EffectSelector의 level 변수를 effect의 최대 level 제한함 for (int j = 0; j < property.arraySize; j++) { var effectSelectorProperty = property.GetArrayElementAtIndex(j); // Selector의 level Property를 가져옴 var levelProperty = effectSelectorProperty.FindPropertyRelative("level"); // Selector가 가진 effect를 가져옴 var effect = effectSelectorProperty.FindPropertyRelative("effect").objectReferenceValue as Effect; var maxLevel = effect != null ? effect.MaxLevel : 0; var minLevel = maxLevel == 0 ? 0 : 1; levelProperty.intValue = Mathf.Clamp(levelProperty.intValue, minLevel, maxLevel); } } 파란색인 부분에서 계속 걸리는데 무슨 문제인지 모르겠습니다. 파란색 뒷부분은 너무 길어져서 잘랐습니다. skillDatasProperty를 가져오는거라 Skill의 skillDatas가 [SerializeField] private SkillData[] skillDatas;배열인것도 확인을 하였지만 if (property.isArray) { int size = property.arraySize; Debug.Log("사이즈 :" + size); } else { Debug.LogError("이 속성은 배열 또는 리스트가 아닙니다."); }이걸로 확인하니 배열이 아니라고 오는데 어떻게 배열이 아니게 된건지 모르겠습니다.
자바는 왜 XtoOne에 대해서는 EAGER를 기본적용하고, OneToX에는 LAZY를 기본 적용하는 지 알고싶습니다. EAGER로 설정되어있는 경우는 아마 항상 같이 딸려와야 하는 연관관계로 해석하는 듯 한데 지연 로딩을 디폴트로 하는 것이 더 많은 사람들이 원하는 바가 아닐까요?
package hello.HelloSpring.service; import hello.HelloSpring.domain.Member; import hello.HelloSpring.repository.MemberRepository; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.transaction.annotation.Transactional; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @SpringBootTest @Transactional class MemberServiceIntegrationTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Test public void 회원가입() throws Exception { //Given Member member = new Member(); member.setName("hello"); //When Long saveId = memberService.join(member); //Then Member findMember = memberRepository.findById(saveId).get(); assertEquals(member.getName(), findMember.getName()); } @Test public void 중복_회원_예외() throws Exception { //Given Member member1 = new Member(); member1.setName("spring"); Member member2 = new Member(); member2.setName("spring"); //When memberService.join(member1); IllegalStateException e = assertThrows(IllegalStateException.class, () -> memberService.join(member2));//예외가 발생해야 한다. assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다."); dependencies dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' developmentOnly("org.springframework.boot:spring-boot-devtools") implementation 'org.springframework.boot:spring-boot-starter-aop' implementation 'org.springframework.boot:spring-boot-starter-jdbc' runtimeOnly 'com.h2database:h2' testImplementation 'org.assertj:assertj-core' // AssertJ 포함 testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3' } error code > Task :compileJava FAILED 1 actionable task: 1 executed C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:4: error: package org.junit.jupiter.api does not exist import org.junit.jupiter.api.Test; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:6: error: package org.springframework.boot.test.context does not exist import org.springframework.boot.test.context.SpringBootTest; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:8: error: package org.assertj.core.api does not exist import static org.assertj.core.api.Assertions.assertThat; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:8: error: static import only from classes and interfaces import static org.assertj.core.api.Assertions.assertThat; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:9: error: package org.junit.jupiter.api does not exist import static org.junit.jupiter.api.Assertions.assertEquals; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:9: error: static import only from classes and interfaces import static org.junit.jupiter.api.Assertions.assertEquals; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:10: error: package org.junit.jupiter.api does not exist import static org.junit.jupiter.api.Assertions.assertThrows; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:10: error: static import only from classes and interfaces import static org.junit.jupiter.api.Assertions.assertThrows; ^ C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:11: error: cannot find symbol @SpringBootTest ^ symbol: class SpringBootTest C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:17: error: cannot find symbol @Test ^ symbol: class Test location: class MemberServiceIntegrationTest C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:27: error: cannot find symbol @Test ^ symbol: class Test location: class MemberServiceIntegrationTest C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:25: error: cannot find symbol assertEquals(member.getName(), findMember.getName()); ^ symbol: method assertEquals(String,String) location: class MemberServiceIntegrationTest C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:36: error: cannot find symbol IllegalStateException e = assertThrows(IllegalStateException.class, ^ symbol: method assertThrows(Class<IllegalStateException>,()->member[...]ber2)) location: class MemberServiceIntegrationTest C:\Users\CKIRUser\Music\�� ����\Programing\�迵��\������ �Թ�\hello-spring\src\main\java\hello\HelloSpring\service\MemberIntegrationTest.java:38: error: cannot find symbol assertThat(e.getMessage()).isEqualTo("�̹� �����ϴ� ȸ���Դϴ�."); ^ symbol: method assertThat(String) location: class MemberServiceIntegrationTest 14 errors FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':compileJava'. > Compilation failed; see the compiler error output for details. * Try: > Run with --info option to get more log output. > Run with --scan to get full insights. BUILD FAILED in 1s JUnit 과 AssertJ이 의존성에 추가해도 인식이 안되는 것 같습니다. 또한 test도 의존성에 추가해도 인식이 안되는 것 같습니다. 해본 조치 사항에는 test 코드에서 컴파일 경고가 나는 것을 확인하고 alt + enter로 직접 의존성을 추가 했고 또 gpt를 이용하여 의존성 코드를 수정해봤습니다. 이러한 조치에도 컴파일 오류는 계속됩니다 해결 방법 알려주시면 감사하겠습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 회원 도메인과 리포지토리 만들기 파트에서 Member을 사용하게 되면 import.hellospring.domain.Member를 불러오는데 제 intellij에서 import java.lang.reflect.Member를 불러오게 됩니다. 둘다 Member를 불러오는 import 인데 뭐가 다른지 물어보고 싶습니다. [질문 내용] 여기에 질문 내용을 남겨주세요.
강의를 듣고 간단한 게시판을 만들고 있습니다. 구현을 하다가 이런식으로 양방향 편의메서드를 작성했습니다. Post(게시글)을 생성할 때 setBoard()를 사용해서 Board.posts 리스트에 생성된 Post 객체를 넣도록 하고 있습니다. public void setBoard(Board board) { this.board = board; if (!board.getPosts().contains(this)) { board.getPosts().add(this); } 여기서 든 고민이 있습니다. 예를 들어 한 게시판에 게시글이 100만개 혹은 엄청난 양의 게시글이 쌓여있다고 가정을 한다면 contains()를 하는 과정이 O(N) 이 걸려 성능이 안좋아질거라고 생각했습니다. 근데 논리적으로 생각했을 때 Board(게시판)에 똑같은 객체(=PK가 같은) Post(게시글) 가 들어갈 일이 있을까? 라는 생각을 해서 굳이 중복 검사하는 로직이 필요하나라는 생각이 들었습니다. 이럴 경우는 어떻게 생각하시나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. package generic.animal; public class Animal { private String name; private int size; // 생성자 만들기 // (Alt + Insert) Generate - Constructor public Animal(String name, int size) { this.name = name; this.size = size; } public String getName() { return name; } public int getSize() { return size; } // sound 메서드 public void sound() { System.out.println("동물 울음 소리"); } @Override public String toString() { return "Animal{" + "name='" + name + '\'' + ", size=" + size + '}'; } } 이 코드에서 set()은 안 만들고 get()만 만드는 이유는 무엇인가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 맴버 메소드 호출은 은 힙 영역에 생성되지 않고 메소드 영역에서 참조 후 그걸 main 함수에서 불러올 시 스택 영역에 해당 메소드가 쌓이는걸로 이해 했습니다 그럼 힙 영역에 생성되는 맴버 변수의 경우 main 함수에서 불러올 시 스택 영역에 쌓이지 않는지 궁금합니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용] 여기에 질문 내용을 남겨주세요. package generic.ex1; public class BoxMain3 { public static void main(String[] args) { GenericBox<Integer> integerBox = new GenericBox<Integer>(); integerBox.set(10); // integerBox.set("문자"); // integer 타입만 허용, 컴파일 오류 발생 Integer integer = integerBox.get(); } } GenericBox<integer> 이렇게 작성하면 T 타입이 Integer로 바뀐거라고 하셨는데 그러면 Integer integer = integerBox.get();을 굳이 안 해도 되고 integerBox.get();이렇게만 적어줘도 되는 거 아닌가요? 또 다시 Integer 타입으로 설정해주는 이유는 무엇인가요?