풀스택 과정 2주차 - Scanner | 가비지컬렉션 | Short Circuit
1일차, 2일차로 하기엔.. 주말때문에 날짜 계산이 어려울 것 같다..
2주차 -> 1개월 1주차 뭐 이런식으로 해야 하나..?
💡 2025.04. 14 수업 이슈
1. Review
2. Scanner 사용법
오늘은 ... 나는 자바다 책으로 지난주에 배운 내용을 복습했다.
개념을 완벽히 익히고 넘어가는 것을 중요시 하는 것 같다.
나도 대충 알고 나중에 까먹는 것보단 확실히 잡고 넘어가는게 좋은 것 같다.
Scanner
지금까지 테스트 파일에서는 객체를 생성할 때 인자값으로 실제값을 바로 입력했다.
즉, 컴파일 시점에서 실제값이 입력되었다.
프로그램은 실행할 때마다 서로 다른 값을 받아들일 수 있는 통로를 가져야 한다.
실행 시점에서 값을 받아들이기 위해서는 Scanner를사용할 수 있어야 한다.
우리는 실행할 때 키보드를 통해서 원하는 값을 읽어 들이는 Scanner를 사용할 것이다.
- Scanner 객체 생성 = Scanner의 필드와 메소드(멤버)가 메모리에 올라간다.
- Scanner의 메소드 사용(호출)
package com.edu.constructor.test;
import java.util.Scanner;
import com.edu.constructor.Shirt;
public class ShirtTest2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("원하는 셔츠 정보를 키보드로 입력받으세요.");
System.out.println("셔츠 메이커 입력 ==>");
String maker = sc.nextLine();
System.out.println("셔츠 사이즈 입력 ==>");
int size= sc.nextInt();
System.out.println("셔츠 긴팔 여부 입력 ==>");
boolean longSleeved = sc.nextBoolean();
Shirt longT = new Shirt(maker, size , longSleeved);
System.out.println(longT.getDetails());
sc.close();
}
}
이렇게 할 수 있다.
여기서 문자열은 nextLine(); 이다. (엔터를 기준으로 함)
package com.edu.constructor.test;
import java.util.Scanner;
import com.edu.constructor.Shirt;
public class ShirtTest2 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("원하는 셔츠 정보를 키보드로 입력받으세요.");
System.out.println("셔츠 메이커, 사이즈, 긴팔여부 입력>>");
String maker = sc.next();
int size = sc.nextInt();
boolean longSleeved = sc.nextBoolean();
Shirt longT = new Shirt(maker, size , longSleeved);
System.out.println(longT.getDetails());
sc.close();
}
}
공백을 기준으로 출력하려면 sc.next();를 써야 한다.
기본형 Primitive Data Type (소문자..예약어..키워드)
소문자라는 것은 클래스가 아니고 멤버(필드, 메서드)가 없다는 뜻이다.
그래서 자바에서 제공하는 Wrapper Class로 변경해줘야 한다.
int → Integer
boolean → Boolean
byte → Byte
short → Short
long → Long
float → Float
double → Double
char → Character
클래스 이름. 기능(); 빨간색S로되어있는 애들은 이미 메모리에 올라가 있어서 객체를 생성하지 않고 바로 사용할 수 있다.
(원래는 클래스 생성 시 new 클래스로 생성하는데, 이 과정 없이 바로 사용할 수 있다.)
package com.edu.operator.test;
public class OperatorTest {
int size; // Field V
// 메모리 힙에 올라감(기본값 있음)
public static void main(String[] args) {
// local V
// 메모리 스택에 올라감
int i;
int j;
i++; // 기본값을 안가지므로 초기화 하고 사용해야 함
}
}
Field는 메모리 힙에 올라가고 기본값이 주어진다.
지역변수는 메모리 스택에 올라가서 기본값을 안 가지므로 초기화 하고 사용해야 한다.
Short Circuit
| 과 & 는 비트 연산자로
true랑 false 모두 비교해서 true인지 false인지를 구별한다.
반면 || , &&은 논리 연산자로
OR연산에서 앞이 true면 바로 true를 반환한다. (실행 속도 빨라짐)
package com.edu.operator.test;
public class OperatorTest {
int size; // Field V
// 메모리 힙에 올라감(기본값 있음)
public static void main(String[] args) {
// local V
// 메모리 스택에 올라감
int i = 6;
int j = 3;
i++;
System.out.println("연산자 = : assign");
System.out.println("연산자 % : " + i%j);
System.out.println("연산자 / : " + i / j);
int num = 98;
System.out.println("십의 자리: " + num / 10);
System.out.println("일의 자리: " + num % 10);
int k = 10;
System.out.println(++k); // 전위연산자
System.out.println(k++); // 후위연산자
System.out.println(k);
// same object? another object ? //
// o1, o2는 로컬변수, 참조변수이다
Operator1 o1 = new Operator1();
Operator1 o2 = new Operator1();
// Operator1 o2 = null;
System.out.println("Reference Value o1 => " + o1);
System.out.println("Reference Value o2 => " + o2);
System.out.println("Same Object ==> " + (o1 == o2)); // 다른 객체
System.out.println("Another Object ==> " + (o1 != o2)); // 다른 객체
// 주소값이 같으면 Heap에 올라가 있는 같은 객체를 가리킨다.
// 주소값이 다르면 Heap에 올라가 있는 서로 다른 객체를 가리킨다.
// Short Circuit //
// 뒷 부분의 논리연산자를 진행시키지 않고 건너뛸 수 있다.
// 뒷 부분 수행 시 발생할 수 있는 예외 상황을 건너뛸 수 있다.
System.out.println(o1.test1() | o2.test2()); // true | false = true
System.out.println(o1.test1() & o2.test2()); // true & false = false
System.out.println("--------------------------");
// 이게 short circuit이다.
System.out.println(o1.test1() || o2.test2()); // true || false = true. 앞이 true면 뒷부분 볼 필요 없음
System.out.println(o1.test2() && o2.test1()); // false && true = false. 앞이 false면 뒷부분 볼 필요 없음
// 예외를 발생시킬 위험을 건너뛰기 해버림
// == , equals //
System.out.println(o1.equals(o2)); // false ... 주소값 비교하는 함수
System.out.println(o1 == o2); // false.. 값 비교하는 연산자
System.out.println("msg == " + (o1.msg == o2.msg));
// String 데이터값을 비교할 때에는 반드시 equals()를 사용, == 연산자 사용하면 안 됨 !!
System.out.println("msg equals() == " + (o1.msg.equals(o2.msg)));
/*
자바에서 **문자열(String)**은 객체예요.
== 연산자는 객체의 "참조(주소)"를 비교하고,
equals()는 객체의 "값(내용)"을 비교합니다.
*/
} // main
} // class
class Operator1{
String msg = "Hello";
public boolean test1() {
System.out.println("test1() calling...");
return true;
}
public boolean test2() {
System.out.println("test2() calling...");
return false;
}
}
class Operator2{
String msg = "Hello";
public boolean test1() {
System.out.println("test1() calling...");
return true;
}
public boolean test2() {
System.out.println("test2() calling...");
return false;
}
}
여기서 com.edu.constructor는 패키지고 .Programmer 까지 되어있는데,
클래스의 Full name이라고 한다.
FQCN(Full Qualified Class Name)이라고 한다.
@ : at 이라고 생각하면 되는데 그 뒤의 숫자와 문자가 혼합된 문자열은 문자열로 된 주소이다.
class Programmer {
String name;
int price;
NoteBook noteBook;
}
p1 = new Programmer("A", 100);
p2 = new Programmer("B", 200);
이렇게 관계가 있는 클래스가 메모리에 올라가는 과정을 그림으로 그려볼 것이다.
String name = new String(”James”); → 힙에 올라감
String name = “James”; → literal Pool(String Pool)에 올라감
기본형 타입의 공간 → 실제값이 들어감
클래스 타입의 공간 → 객체를 가리키는 주솟값이 들어감(참조, 참조변수)
s1 = s2와 같이 스택 영역으로부터 참조가 끊어지게 되면
기존 s1이 가리키던 객체는 가비지(쓰레기 객체)가 됨.
가비지가 많아지면 메모리 공간이 차고 느려진다.(퍼포먼스 , 성능 ⬇)
바로 사라지지는 않고 자동으로 JVM의 판단으로 가비지 컬렉션에 의해 지워짐.
Garbage Collection(GC) ➡ 쓰레드
이 놈이 제거해줌.
- 언제 제거할 지 모른다.
- 알아서 해준다.
쓰레드는 철저히 우선순위에 의해 동작한다.
static을 남용하면 안되는 이유.. GC의 우선순위에서 많이 밀려나기 때문!
오늘 코딩 과제를 하고 그 과제의 일부의 메모리 구조를 그려본 것이다.