본문 바로가기
멀티캠퍼스/Spring

20230802 (수)

by 세크레투스 2023. 8. 2.
반응형
SMALL

1. 복습

- primitive : 숫자 1개

- reference : 주소, 대입연산만 가능.

- new Scanner()

- new Random()

- new String()

- new는 Heap이라는 공간에 할당되며, reference는 new의 리턴값이다.

- new 리턴값은 할당된 공간의 참조값

- 참조타입 = new ~~~()

 

- 배열 : 동일 데이터 타입을 요소로 가지고 연속적으로 저장되어 운영됨.

  • 한번 할당되면 크기 고정
  • 연속적으로 저장 = 인덱스(번호)
  • int[] 변수명;
    • 참조값을 저장할 수 있는 4byte가 잡힘.
    • 값을 지정을 안했기 때문에 어떤 값이 들어가는지 알 수 없다.
    • 타입(int, long, double, String)에 상관없이 배열은 항상 4byte이다.
    • 배열의 크기 : 요소를 몇개 가지는 배열인가? (byte 크기가 절.대. 아님!)
  • int[] 변수명 = {1, 2, 3};
    • 원래는 정식적으로 int[] 변수명 = new int[] {1,2,3}; 이 맞음.
    • 하지만 이미 선언된 타입을 보고 컴파일러가 타입을 추론할 수 있기 때문에 대입할 때 생략이 가능함.
    • 그리고 new역시 당연히 선언을 하고있기 때문에 생략이 가능함.
    • 이처럼 컴파일러가 추론할 수 있는 것들은 생략이 가능한데, 이것을 타입추론이라고 함.
    • int[] 변수명 = new int[] {1,2,3}; // 하드코딩
  • int[] numbers = new int[100];
    • new int[]; 의 대괄호 안에는 개수를 넣어줌.
    • int[] numbers = new int[100]; 해석
      • heap이라는 공간 안에 int 100개가 들어갈 수 있고, 0으로 자동초기화가 됨.
      • int 타입 = 0, double = 0.0, char = NULL, boolean = false, 참조 = null 로 초기화.
    • numbers [0], numbers [1], numbers [2] ...
      • 0부터 시작하는 이유는, 시작주소이기 때문.
      • 시작주소(numbers) + 1개 요소크기 * 인덱스 = offset

2. 본수업

  • 많은 양의 데이터를 다루는 기술 2가지 : 배열과 컬렉션 비교
  • 배열(Array)
    • 배열은 언제 사용하면 좋을까?
      • 데이터들의 타입이 동일한 경우
      • 데이터들이 3개 이상인 경우
      • 데이터들의 수가 정해져 있는 경우
    • 사용하면 안좋은 경우
      • 타입들이 다양한 경우
      • 수가 변경이 있는 경우
        • Collection 계열의  class를 사용
        • ArrayList(80%)
        • HashMap, Set
    • int[] num = new int[3];
      • int만 넣겠다는 의미, 같은 타입만 넣을 수 있다.
      • 고정된 크기를 가진다. (크기 변경 불가능)
    • 배열은 많은 양의 데이터를 다루기 위한 특수한 부품
      • String[] names = {"홍", "송", "정", "박", "장"};
        • 6개 + length 총 7개를 RAM에 할당
        • 이 때 배열에 의해 차례대로 names[0], names[1], names[2], names[3], names[4]의 인덱스 값을 갖는다.
      • for (int i = 0; i < names.length; i++) { System.out.println(names[i]); }
      • for (String s : names) { System.out.println(s); }
        • for each는 names의 주소 5개를 한번에 변수 s로 불러온다.
        • advanced for문이라고도 불린다.
      • for( in 배열 )
        • index를 줌.
      • for( of 배열 )
        • 값을 줌.
        • for each(advanced for)문과 동일하다.
    • 배열의 초기값은 자동으로 들어가있다. (자동초기화)
      • int[] s = new int[4];
        • int s[] = new int[4]; 와 동일
        • 정수는 0, 실수는 0.0, 문자는 NULL, 문자열(참조형)은 null, boolean은 false로 초기화
      • 배열.length에서 length는 상수이다. 이미 결정된 값이기 때문에 우리가 임의로 바꿀 수 없다.
      • java.lang.ArrayIndexOutOfBoundsException: Index 1000 out of bounds for length 1000 at java_study.chapter05.ArrayEx2.main(ArrayEx2.java:20)
        • 잘못된 인덱스 값을 사용했을 때 나오는 에러. (대표적인 에러임.)
    • 배열을 만드는 방법 2가지
      • 선택기준 : 배열에 넢을 값이 생성시점에서
        • 정해지지 않은 경우 : int[] x = new int[10];
        • 정해진 경우 : int[] x = {1, 2, 3};
    • 배열을 사용하는 경우 (조건 3가지)
      • 많은 데이터 양
      • 같은 타입의 데이터
      • 고정된 크기 : 이게 항상 문제가 됨. 치명적인 단점.
        • 크기 조절 불가능
        • 다른 타입의 데이터들을 넣을 수는 있으나, 형변환 등을 해야함으로 선호하지 않음.
        • 제너릭을 사용한 컬렉션 선호
      • 장점 : 속도
      • 자료구조 (data structure) : 2개 이상의 여러 데이터를 다룰 때, 그 데이터를 어떤 구조로 운영할 것인지를 뜻함.
      • System.out.println(num); // 참조값, 주소확인
      • System.out.println(num[0]); // 인덱스 값 확인.
    • 에러인 상황, 에러가 아닌 상황
int[] arr = { 1, 2, 3, 4 }; // new int[] 생략

//(1) 에러
arr={10,11,12}; // 이거는 당연히 안된다. 왜냐하면 타입선언도 없고, [] 배열인지 표시도 안해줬기 때문에 당연히 에러가 남.

//(2) 정상
arr = new int[] { 10, 11, 12 }; // 에러 아님.
int[] arr2 = new int[] { 5, 6, 7, 8 }; // 정식 문법
  • for-each문 : 무조건 순서대로 하나씩 꺼내옴.
  • 배열명[배열명.length-1]; : 마지막 요소 인덱스
  • 참조형(reference) 배열
    • String[] names = new String[2];
    • names = new String[] {"a", "b"};
      • 참조형이기 때문에, 값을 초기화 시킬때도 반드시 new String[]을 써줘야 함.
    • 주소 2개를 저장할 수 있는 배열이 됨.
  • 기본(primitive) 배열
    • int[] numbers = new int[2]; // heap에 int 2개의 공간이 잡힘.
    • numbers[0] = 10;
    • 값을 2개 저장할 수 있는 배열
  • stack 영역
  • 상수 영역
  • heap 영역

객체의 필요성을 위해서 한 코딩.. (아직 객체에 대해서 배우지 않음. 배열까지만 배움.)

package java_study.chapter05;

public class ArrayEx4 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		// 친구 이름
		String[] names = { "홍길동", "김길동", "박길동", "송길동", "정길동" }; // 선언문에서만 가능한 표현
		for (int i = 0; i < names.length; i++) {
			System.out.println(names[i] + " ");
		}
		System.out.println();

		// 우리 가족 5명의 나이를 넣어보세요. 전체 출력
		int[] ages = { 50, 40, 30, 20, 10 };
		for (int i = 0; i < ages.length; i++) {
			System.out.println(ages[i] + " ");
		}

		System.out.println();
		// 친구들의 발 사이즈를 넣어보세요. 전체 출력
		int[] shoes = { 134, 235, 245, 255, 300 };
		for (int i = 0; i < shoes.length; i++) {
			System.out.println(shoes[i] + " ");
		}

		System.out.println();
		// 친구들의 성별을 넣어보세요. 전체 출력
		char[] gender = { '남', '여', '남', '남', '여' };
		for (int i = 0; i < gender.length; i++) {
			System.out.println(gender[i] + " ");
		}

		for (int i = 0; i < 5; i++) {
			System.out.println(i + " " + names[i] + " " + ages[i] + " " + shoes[i] + " " + gender[i]);
		}
	}

}

나는 하단에 저렇게 추가를 해줬는데,

강사님은 이렇게 코딩하심.

그거나 그거나..

 

  • 참조형에 대한 이야기
    • CPU(피코세컨드의 가장 빠른 속도) - (Process) - Main Memory(그나마 CPU의 속도를 따라갈 수 있음.) - Loading(자동차에 짐을 싣는다.) (Loader : Loading을 실행하는 것들. 운영체제에 있음.) - HPP - Program - OS
    • Process : 운영체제가 관리를 한다 는 의미.
    • 코드파트 (컴파일 결과를 의미하며, 명령어 순서가 고정됨. 크기와 내용도 고정됨.) - 데이터파트 (항상 상황에 따라서 변함.)
  • stack 영역
    • stack : 쌓다.
    • 원통인데 위쪽에만 구멍이 뚫려있다.
    • 넣을때도 위에서만 넣을 수 있으며, 꺼낼때도 위에서만 꺼낼 수 있다.
    • 맨 밑에 있는 것은 가장 처음에(오래전에) 들어간 것. 맨 위에 있는 것은 가장 나중에(최근에) 들어간 것.
    • 그래서 스택의 성격을 Last In First Out 이라고 함. (LIFO)
    • 자료구조에서 많이 쓰임.
    • main() 에 할당된 변수 : 지역변수
    • 함수호출에서 stack을 쓸 때 속도가 아주 중요하다.
    • 초기화 하는 것은 시간을 잡아먹는 행위이기 때문에 지역변수에서는 초기화를 안해준다.
    • 쓰레기 값 : 뭔지 모른다.
      • 왜? 초기화를 안하니까 다음 스택에 이전에 저장된 값이 그대로 남아있어서.
    • 함수가 끝나면 지워지거나 사라지는 것이 아니라, top의 위치만 바뀌는 것이다.
      • 그것에 지워진거나 마찬가지이다. 왜냐하면 접근을 못하므로. 하지만 이전에 쓰였던 값이 그대로 남아있어서 쓰레기 값이라고 부른다.
      • 이렇게 된 이유는, 아주 빠르게 stack을 운영해야 하기 때문에 쓰레기 값을 초기화하는 과정이 없기 때문이다.
    •  
     

  • main의 지역변수 args
    • 그 하단에 str, str2
    • 이것을 한꺼번에 통칭하는 것 : stack frame
  • 코드영역, 리터럴 상수영역 = 읽기 전용
    • 자바(JAVA)에서는 메소드 영역이라고 부른다.
    • 그 이유는 99%정도 메서드가 다 채우는 영역이여서이다.
      • 지역변수는 Stack에서 운영함.
      • 아랫단에는 Stack이, 윗단에는 Heap이 운영함.
      • stack과 heap의 차이

String str = new String("Hello"); //1번 주소
str = new String("World"); //2번 주소

String str2 = new String("World"); //3번주소
// 2개는 내용은 같지만, 주소가 다름.
str == str2; //false
str = str2; //값 복사 X, 참조값 복사 O
//str과 str2 모두 3번주소, 1번과 2번주소는 쓰레기값이 됨.
str = null; //아무것도 참조하지 않는다.
// 3번주소는 str2에서 참조중이므로 쓰레기값이 아님.
  • 이전에 사용했던 데이터(쓰레기)를 다시 가져오는 방법 : Java VM(Virtual Machine)에서 G.C.(Garbage Collector)를 통해 회수함. -> 그때 사라짐. (다음 메모리를 할당할 수 있다.)
  • life time, access scope
    • 규칙이 정해져 잇음. (규칙 : 언제 생성되고 언제 사라지는가?)
      • 언제 생기는가? : new 호출할때.
      • heap에 할당되는 변수 : 동적(Dynamic)할당 (개발자 맘대로)
      • stack에 할당되는 변수 : 정적할당 (이미 정해져있음. 못바꿈.)
      • 동적할당의 의미 : 생성과 소멸의 시점이 정해져있지 않다.
      • 자바는 Java VM 때문에 메모리 관리가 매우 쉽다. : 메모리를 잘못 쓸 일이 낮음.
      • 하지만, C나 C++에서는 메모리를 직접 해제해줘야 하기 때문에 메모리를 잘못 쓸 염려가 있음.
      • str = str2; 와 같은 상황은 함수 호출 시, 매개변수로 값을 넘겼을 때 자주 일어나는 현상이다.
        • call by reference라고 함. : 원본에 영향을 줌.
      • call by value, call by reference를 잘 비교하는 것이 중요하다.
      • 리터럴(값) : 메소드영역에 저장
        • 리터럴은 int a = 100; 이라고 했을때, 말 그대로 오른쪽에 저장되는 값을 의미하는 것.
      • 객체 : heap에 저장
        • 객체는 변수, 데이터 구조, 함수, 메서드가 될 수 있으며, 식별자가 참조하는 메모리의 값이다.
      • 가비지컬랙터에서 메모리가 할당이 됐는지 안됐는지를 아는 방법 : 참조 카운트를 통해서.
    • 메소드 정의 및 호출
  • 여러 개의 메소드가 포함된 클래스 
class LuxuryHelloJava {
	//메인 메서드 = 엔트리 포인트
    // void : 이부분에 리턴 타입 값이 들어감. 그러나, 리턴값이 없으므로 void로 표시.
	public static void main(String args[]) {
    	printCharacter('*', 30);
        System.out.println("Hello, Java");
        printCharacter('-', 30);
    }
    // void : 이부분에 리턴 타입 값이 들어감. 그러나, 리턴값이 없으므로 void로 표시.
    static void printCharacter(char ch, int num) {
    	for(int cnt = 0; cnt < num; cnt++) {
        	System.out.print(ch);
        }
        System.out.println();
    }
}

 

  • 메소드를 사용하면 좋은 이유 : 코드 재사용에 용이하다. (코드 중복을 줄일 수 있다.)

 

package java_study.chapter05;

public class StartTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//점점 커지는 별의 수
		for (int i = 1; i <= 5; i++) {
			printStars('*', i);
		}
		//점점 작아지는 별의 수
		for (int i = 5; i > 0; i--) {
			printStars('*', i);
		}

//		for (int i = 5; i > 0; i--) {
//			System.out.println("몇번?*");
//		}
	}

	static void printStars(char ch, int num) {
		for (int j = 0; j < num; j++) {
			System.out.print(ch);
		}
		System.out.println();
	}
}

  • 결과를 리턴하는 메서드
    • 리턴 값(return value) : 메소드가 호출한 쪽으로 넘겨주는 메소드의 실행 결과
    • 리턴 값을 리턴하는 메소드 호출문의 형식
    • 타입 변수 = 메소드이름(파라미터1, 파라미터2, 파라미터3);
      • 변수 : 메소드의 리턴 값을 대입할 변수의 이름
      • 파라미터
      • 메소드 타입이랑 변수 타입이 일치해야 함.
    • paramter변수 = 지역변수임.
      • 파라미터는 주소값이 복사됨.
    • primitive → reference 혹은 reference → primitive데이터 이동이 전.혀. 안됨.
  • Call By Value
package java_study.chapter05;

public class CallByValueEx {

	public static void main(String[] args) {
		// primitive 타입
		int x = 100;
		int y = 200;

		swap(x, y);
		System.out.printf("변경 전 - x: %d, y : %d\n", x, y);
		System.out.println(System.identityHashCode(x));
		System.out.println(System.identityHashCode(y));
	}

	static void swap(int x, int y) {
		int temp;
		temp = x;
		x = y;
		y = temp;
		System.out.printf("변경 후 - x: %d, y : %d\n", x, y);
		System.out.println(System.identityHashCode(x));
		System.out.println(System.identityHashCode(y));
	}

}
  • Call By Reference
package java_study.chapter05;

public class CallByReferenceEx {

	public static void main(String[] args) {
		// reference 타입
		int[] data = { 100, 200 };
		System.out.printf("변경 전 : %d, %d\n", data[0], data[1]);

		swap(data);
		System.out.printf("원본 변경 후 : %d, %d\n", data[0], data[1]);
	}

	// 배열의 첫번째, 두번째 엘리먼트 교환
	static void swap(int[] data) {
		int temp;
		temp = data[0];
		data[0] = data[1];
		data[1] = temp;

		System.out.printf("변경 후 : %d, %d\n", data[0], data[1]);
	}
}

 

  • 바꾸고자 하는 단어를 한꺼번에 바꾸는 법 : 해당 단어를 드래그 후 Refactor 메뉴 -> Rename
  • 또는 alt + shift + enter
  • 맥은 option + command + R

 

반응형
LIST

'멀티캠퍼스 > Spring' 카테고리의 다른 글

20230809 (수)  (0) 2023.08.09
20230808 (화)  (0) 2023.08.08
20230807 (월)  (0) 2023.08.07
20230731 (월)  (0) 2023.08.04
20230801 (화)  (0) 2023.08.01