[DEV] study&learn
article thumbnail
9시 전 급하지 않게 출석 완료!
컨디션, 텐션 유지하자.
아침만큼이라도 패턴화 된 시간을 보내자!!!
할 수 있다!!!!!!!!!!



 

chapter5. 참조 타입

자바의 타입

자바의 타입은 크게 기본 타입(primitive type)과 참조 타입(reference type)으로 분류된다.

  1. 기본 타입 : 정수, 실수, 문자, 논리 리터럴을 정하는 타입을 칭한다.
  2. 참조 타입 : 객체(object)의 번지를 참조하는 타입으로 배열, 열거, 클래스, 인터페이스를 말한다.

 

기본 타입과 참조 타입의 차이점

저장되는 값에 차이가 있다.

기본 타입은 변수에 실제 값을 저장하지만,

참조 타입은 변수에 메모리의 번지를 저장한다! 번지를 통해 객체를 참조한다는 듯에서 참조 타입이라고 부른다.

 

메모리 사용영역

JVM은 운영체제에서 할당받은 메모리 영역을 다음과 같이 세부 역역으로 구분해서 사용한다.

  1. 메소드 영역
    • 메소드 영역은 JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역이다.
    • 메소드 영역에는 코드에서 사용되는 클래스(class)들을 클래스 로더로 읽어 클래스별로 정적 필드(static field)와 상수(constant), 메소드 코드, 생성자(construtor) 코드 등을 분류해서 저장한다.
  2. 힙 영역
    • 힙 영역은 객체와 배열이 생성되는 영역이다.
    • 여기에 생성된 객체와 배열은 JVM 스택 영역의 변수나 다른 객체의 필드에서 참조한다.
    • 어떤 객체를 참조하는 변수나 필드가 없다면, 이 객체는 의미 없는 객체가 되기 때문에 Garbage Collertor를 실행시켜 자동으로 메모리에서 제거한다.
  3. JVM 스택 영역
    • JVM 스택은 메소드를 호출할 때마다 프레임(frame)을 추가(push) 메소드가 종료되면 해당 프레임을 제거(pop)하는 동작을 수행한다.
    • 프래임 내부에는 로컬 별수 스택이 있는데, 기본 타입 변수와 참조 타입 변수가 추가(push)되거나 제거(pop)된다.
    • 스택 영역에 변수가 생성되는 시점은 초기화될 때, 즉 최초로 변수에 값이 저장될 때이다.
    • 변수는 선언된 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거된다.
    • 기본 타입 변수는 스택 영역에 직접 값을 가지고 있지만,
      참조 타입 변수는 스택 영역에 힙 영역의 객체 주소를 가진다.

 

참조 변수의 ==, != 연산

기본 타입 변수의 ==, != 연산은 변수의 값이 같은지, 아닌지를 조사한다.

참조 타입 변수의 ==, != 는 변수의 값을 비교하는 것이 아니라, 힙 영역의 객체 주소를 비교한다.

참조 타입 변수의 == 연산 결과가 true 라면 두 변수는 같은 객체를 참조하고 있다는 의미이다.

 

null & NullPointException

참조 타입 변수는 힙 영역의 객체를 참조하지 않는다는 뜻으로 null(널) 값을 가질 수 있다.

null 값도 초기값으로 사용할 수 있기 때문에 null로 초기화된 참조 변수는 스택 영역에 생성되기는 하지만,

힙 영역의 객체를 따로 참조하지는 않는다.

 

예외(Exception) : 자바는 프로그램 실행 도중에 발생하는 오류를 예외라고 부른다.

그중 NullPointException은 참조 타입 변수를 잘못 사용할 경우 발생한다.

참조 타입의 변수가 null을 가지고 있는 경우, 참조 객체가 없으므로 변수를 통해 객체를 사용할 수 없다.

이처럼 null 상태에서 있지도 않은 객체의 데이터(필드)나 메소드를 사용하는 코드를 실행하면 NullPointException이 발생한다.

 

String 타입

자바는 문자열을 String 변수에 저장한다.

String name = "김형준";

String 타입도 참조 타입이기 때문에, 엄밀히 말하면 문자열을 String 변수에 저장한다는 말은 틀린 표현이다.

→ String 타입 변수는 문자열이 담겨 있는 String객체의 힙 영역 주소를 가지고 있는 것.

 

자바는 문자열 리터럴이 동일하다면 String 객체를 공유하도록 되어있다.

String A = "A";
String B = "A";

A == B // true

 

new 연사자를 통해 String 객체를 생성하게 되면 새로운 객체를 힙 영역에 생성한다.

String A = "A";
String B = "A";
String C = new String("A");

A == B // true
A == c // false

 

동일한 String 객체이건 다른 String 객체이건 상관없이 내부 문자열을 비교하고 싶을 때에는 String 객체의 equals() 메소드를 사용하면 된다.

boolean result = A.equals(C); // A는 원본 문자열, C는 비교 문자열
result // true

 

배열

 

배열이란?

배열은 같은 타입의 데이터를 연속된 공간에 나열하고, 각 데이터에 인덱스(index)를 부여해놓은 자료구조이다.

int[] num = {1, 2, 3, 4, 5} // 배열 선언1, 값의 목록으로 객체 생성
int num[] = {1, 2, 3, 4, 5} // 배열 선언2, 값의 목록으로 객체 생성

num.length // 5

num[3] // 4

.length 는  배열의 길이를 알려주는 메소드이다. 읽기 전용 필드이기 때문에 값을 바꿀 수 없다.

num[3] num은 배열 이름, 3은 인덱스 넘버를 지칭한다. 인덱스 넘버는 배열의 길이 -1 이다. (0부터 시작)

 

배열의 특징

  1. 배열은 같은 타입의 데이터만 저장할 수 있다. (선언과 동시에 저장할 수 있는 타입이 결정)
  2. 한 번 생성된 배열은 길이를 늘리거나 줄일 수 없다.
    (길이를 줄이거나 늘리려면 기존 배열 항목을 새 배열로 복사해야 한다.

 

배열 생성

배열 객체를 생성하려면

  • 값 목록을 이용하거나
    1. 중괄호 { }는 주어진 값들을 항목으로 가지는 배열 객체를 힙에 생성하고, 배열 객체의 번지를 리턴한다.
    2. 값의 목록으로 배열 객체를 생성할 때 주의할 점이 있는데, 
      배열 변수를 이미 선언한 후에는 다른 실행문에서 중괄호를 사용한 배열 생성이 허용되지 않는다.
    3. 그렇기 때문에 배열 변수를 미리 선언한 후 값 목록들이 나중에 결정될 상황이라면,
      new 연산자를 사용해서 값 목록을 지정해주면 된다.
    4. 메소드의 매개값이 배열일 경우에도 마찬가지이다.
// 1.
String[] names = {"김형준", "강인구", "전요환"}; 
name[1] = "변기태" // 강인구 -> 변기태로 값이 바뀐다.

// 3.
String[] names = null;
names = new String[] {"김형준", "강인구", "전요환"}

// 4.
int add(int[] scores) {---}
int result = add(new int[] {90, 80, 85});

 

  • new 연산자를 이용하는 방법이 있다.
    1. 값의 목록을 가지고 있지 않지만, 향후 값들을 저장할 배열을 미리 만들고 싶다면 new 연산자로 다음과 같이 배열 객체를 생성할 수 있다.
    2. new 연산자로 배열을 처음 생성할 경우 배열은 자동적으로 기본값으로 초기화된다.
int[] scores = new int[5]; // 타입[] 변수 = new 타입[길이]
scores[0] = 100; // {100, 0, 0, 0, 0}

String[] names = new String[5]; // 타입[] 변수 = new 타입[길이]
names[0] = "김형준"; // {"김형준", null, null, null, null}

 

명령 라인(명령 프롬프트) 입력

프로그램 실행을 위해 main() 메소드가 필요하다.

그럼 main() 메소드의 매개값인 String[] args 는 도대체 왜 필요한 것일까?

 

명령 라인(명령 프롬프트)에서

public static void main(String[] args) {---}

코드를 java 명령어로 실행하면 JVM은 길이가 0인 String 배열을 먼저 생성하고

main() 메소드를 호출할 때 매개값으로 전달한다.

 

나는 명령 프롬프트 안 쓰는데...?

자바가 지정한 규칙이라고 생각하자! (유일한 엔트리 포인트로 지정)

 

다차원 배열

수학의 행렬과 비슷하다고 생각하면 된다.

위와 같은 배열을 생성하는 코드

int[][] scores = new int[2][];
scores[0] = new int[2];
scores[1] = new int[3];

위의 배열에서 scores[0][2]는 ArrayIndexOutOfBoundsException을 발생시킨다.

scores[0]이 가리키는 배열B는 인덱스를 0~1까지만 가지고 있기 때문이다.

 

객체를 참조하는 배열

위와 같은 배열을 생성하는 코드

String[] strArray = new String[3];
strArray[0] = "java"; 
strArray[1] = "C++";
strArray[2] = "C#";

 

배열 복사

배열은 한 번 생성하면 크기를 변경할 수 없다는 특징이 있다.

때문에 더 많은 저장 공간이 필요하다면 더 큰 배열을 새로 만들고 이전 배열로부터 항목 값들을 복사해야 한다.

 

1. for문을 이용한 배열 복사

int[] oldArray = {1, 2, 3};
int[] newArray = new int[5];

for (int i = 0; i < oldArray.length; i++) {
	newArray[i] = oldArray[i];
}

 

2. System.arraycopy() 메소드를 이용한 배열 복사

System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);

System.arraycopy(원본 배열, 복사 시작 인덱스, 새로운 배열, 붙여 넣기 시작 인덱스, 복사할 개수); 의 구조를 가진다.

 

향상된 for문

자바는 배열이나 컬렉션을 좀 더 쉽게 처리하기 위해 향상된 for문을 제공한다.

향상된 for문은 반복 실행을 위해 루프 카운터 변수와 증감식을 사용하지 않는다.

int[] nums = {100, 90, 80};

int sum = 0;
for(int score : nums) {
	sum += score;
}

for문의 괄호 ( )에는 배열에서 꺼낸 항목을 저장할 수 있는 변수 선언과 콜론(:) 그리고 사용할 배열을 나란히 작성한다.

 

열거 타입

열거 타입은 한정된 값인 열거 상수 중에서 하나의 상수를 저장하는 타입이다.

public enum Week { // Week 열거 타입 이름
	MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY // MONDAY ~ SUNDAY 열거 상수
}

여기서 Week가 열거 타입이다.

public enum 은 열거 타입을 선언하기 위한 키워드이다.

 

열거 타입은 관례적으로 첫 글자를 대문자로 하고 나머지는 소문자로 구성한다.

여러 단어로 구성된 이름이라면 각 단어의 첫 글자는 대문자로 한다. (예, MemberGrade)

 

다음은 Week로 변수를 선언하고, 저장하는 코드이다.

Week today;

today = Week.SUNDAY;

today 변수에 저장할 수 있는 것은 Week에 선언된 7개의 열거 상수 중 하나이다.

열거 상수는 단독으로 사용할 수 없고 반드시 '열거 타입, 열거 상수'의 형태로 사용한다.

 

열거 상수는 열거 타입의 값으로 사용되는데, 관례적으로 모두 대문자로 작성한다.

여러 단어로 구성된 이름이라면 각 단어 사이를 밑줄(_)로 연결한다. (예, LOGIN_SUCCESS)


Calendar은 왜 new 연산자를 안 써?

class를 사용하려면 new 연산자를 통해 선언하여 객체화시켜야 한다고 한다.

하자만 Calendar은

Calendar now = Calendar.getInstance();

와 같은 형태로 사용된다.

 

왜??

추상 클래스여서 그렇단다.

 

그럼 추상 클래스란?

추상(abstract)은 실체 간에 공통되는 특성을 추출한 것을 의미한다. 객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 한다면 클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다. abstract 클래스나 메소드를 사용하기 위해서는 반드시 상속해서 사용하도록 강제하는 것이 바로 abstract이다.

추상 클래스는 실체 클래스의 공통되는 필드와 메소드를 추출해서 만들었기 때문에 객체를 직접 생성해서 사용할 수 없다. 즉, 추상 클래스는 new 연산자를 사용해서 인스턴스를 생성시키지 못한다.


백준 알고리즘

간단하면서도 어렵다.

더 좋은 코드로, 더 간결한 코드로 만들고 싶다.

 

내일 주사위 문제 코드 다시 생각해보기!!

 

2480번: 주사위 세개

1에서부터 6까지의 눈을 가진 3개의 주사위를 던져서 다음과 같은 규칙에 따라 상금을 받는 게임이 있다.  같은 눈이 3개가 나오면 10,000원+(같은 눈)×1,000원의 상금을 받게 된다.  같은 눈이 2개

www.acmicpc.net


🎯 내일의 계획

  1. 자바 기본 강의 완강하기
  2. 주사위 문제 다른 방식으로 한 번 더
  3. 챕터 6 완독
  4. 아래에 대해서 알아보기
    Buffer ? InputStream ?
    객체 vs 인스턴스
    다형성
    추상 클래스? (추상 메서드가 1개라도 있는 클래스를 의미, 추상체 = spec 이라고도 함) 
    추상 클래스 vs 인터페이스
    상속
  5. 아래 URL 읽어 보기
 

링킹(Linking)

할 일 다 끝내고 시간 남으면 놀아달라 했더니심야 영화 보러 갈까? 라는 내 님의 말을 듣고의욕이 집중력이 상승했다. 그러니 바로 다음 개념인 링킹에 대해 정리해보겠다. 우리는 앞서 개발자

resian-programming.tistory.com

 

 

[실무 면접 준비 - 4] 객체지향 & JVM (OOP & JVM)

 

imbf.github.io

 

https://d2.naver.com/helloworld/1230

 

profile

[DEV] study&learn

@devjuni

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!