[혼공자바] 2주차 공부기록(조건문&참조타입/변수)

Say·2025년 7월 13일
0
post-thumbnail

조건문과 반복문

if문 & Switch문

✅ if문 동작원리


✅ Switch문 동작원리

❣️스위치문 실습

스위치문과 관련한 과제도 같이 수행했다!
random 함수를 사용해서 숫자를 무작위로 변수에 저장하고 스위치문을 사용해서 숫자를 출력해보는 간단한 실습이었다.

랜덤으로 숫자를 출력하니 당연히 결과도 실행할 때마다 다르게 나온다는 것!

for문과 while문

✅ for문

✅ while문

✅ do - while문


참조 타입과 참조 변수

⬇️ 한 눈에 보는 기본 타입과 참조 타입 분류표

기본 타입과 참조 타입

🤨 기본 타입으로 선언된 변수와 참조 타입으로 선언된 변수의 차이점이 뭘까?

제일 기본적인 차이점은 아무래도 저장되는 값 그 자체라고 볼 수 있다.
기본 타입의 경우 실제 값을 변수 안에다가 직접 저장하지만
참조 타입의 경우 변수의 메모리의 주소를 변수 안에 저장한다.
‘주소’를 통해 객체를 참조한다는 뜻 → 참조 타입

간단하게 그림으로 이 말을 이해해보자면..?

메모리 사용 영역

  • JVM이 사용하는 메모리 영역
    • 메소드 영역
      • JVM이 시작될 때 생성
      • 모든 스레드가 공유하는 영역
      • 클래스 별 정적 필드, 상수, 메소드 코드, 생성자 코드 등을 분류해 저장
    • 힙 영역
      • 객체와 배열이 생성되는 영역
      • JVM 스택 영역의 변수나 다른 객체의 필드에서 참조
    • JVM 스택
      • 메소드 호출할 때마다 프레임 push
        • 메소드 종료 → 해당 프레임 pop
      • 프레임 내부 → 로컬 변수 스택 O
        • 기본 타입 변수, 참조 타입 변수 pop, push 이뤄짐
      • 변수 생성 시점
        • 초기화 시
        • 선언된 블록 안에서만 스택에 존재
          • 블록 벗어나면 칼같이 제거
    • 기본 타입 변수 → 스택 영역 → 직접 값 O
    • 참조 타입 변수 → 스택 영역 → 힙 영역의 객체 주소 가짐
    • 배열 → 객체 취급

null과 NullPointerException

  • 참조 타입 변수 → null값 가질 수 있음: 힙 영역의 객체를 참조하지 X 라는 뜻
    • null로 초기화된 참조 변수도 스택 영역에 생성 O (⭐️ 힙에 객체 주소가 생기지 않음)
  • NullPointerException → 참조 타입 변수를 잘못 사용하면 발생
    • EX) null 상태에서 있지도 않은 객체의 데이터나 메소드를 사용하는 코드를 실행

    • 💡예시를 들어보자

      int[] exampleArray = null;
      exampleArray[0] = 10; // NullPointerException 발생.

      exampleArray는 배열 변수. 즉 참조 변수!

      그래서 null 초기화는 가능하지만

      exampleArray 변수가 참조하는 배열 객체가 없기 때문에 오류가 발생하는 것.

String 타입

  • 문자열 → String 변수에 저장

    • ❕좀 틀린 말이다.
    • 문자열이 직접 변수에 저장되는 것이 아니라,
    • 문자열은 String 객체로 생성되고
    • 변수는 String 객체를 참조하는 것!
      • 문자열 리터럴 → 힙 영역에 객체로 생성되고 변수에는 객체의 번지 값이 저장.
  • 큰 따옴표로 감싼 문자 리터럴 대입

    • 변수 = “문자열”;

    • 코드 예시

      String name1 = "홍세희";
      String name2 = "홍세희";
       문자 리터럴이 동일 → **String 객체 공유 가능!**
  • new 연산자(✅객체 생성 연산자) 사용 → 직접 String 객체 생성 가능

    • 다른 String 객체를 참조한다. → 주소값이 다르다!
  • 위에서의 내용을 코드를 통해 확인해보자.

    주소값을 확인하기위해 디버깅 모드를 사용했다. (인텔리제이에서 실행)

    코드는 밑과 같이 작성!

    
    public class Main {
        public static void main(String[] args) {
            String name1 = "세이"; 
            String name2 = "세이"; 
        }
    }
    public class Main {
        public static void main(String[] args) {
            String name1 = new String("세이2");
            String name2 = new String("세이2");
        }
    }


결과는 다음과 같이 나온다.
흠.. 뭔가 byte[4]@441byte[4]@448 에서 보면 @ 뒤에 부분이 객체의 주소값이지 않을까? 라는 생각을 했는데 new String()을 통해 생성한 name1, name2에서 보면.. 주소값이 448로 똑같네..?

일단.. 실제 메모리 주소는 JVM의 추상화와 보안 정책 때문에 공식적으로 지원되지 않는다고 한다!

IntelliJ의 디버거가 보여주는 값 → JVM 내부의 객체 식별자 → 실제 메모리 주소 ❌

실제로 확인은 못해서 아쉽군.

그러면 저 byte[]는 뭘까?

"세이2"라는 문자열 리터럴은 JVM의 String Pool에 저장되어 있는데

new String("세이2") 생성자는 내부적으로 이 리터럴의 byte[]를 참조해서 새 String 객체를 만든다.

따라서 두 new String("세이2") 객체는 서로 다른 String 객체지만,

내부 byte[] 배열은 동일한 리터럴을 참조하여 같은 주소값(byte[4]@442)을 가진다!

따라서 디버거가 보여주는 것은 내부 byte[] 배열의 참조값이다!

객체의 주소는 알 수 없었지만.. 디버거에 나오는 숫자의 정체를 알 수 있었던.. 삽질 아닌 삽질이었다-

배열

배열이란?

  • 같은 타입의 데이터를 연속된 공간에 나열
  • 각 데이터에 인덱스를 부여하는 자료구조
  • 다른 타입의 값을 저장하려고 하면 타입 불일치 컴파일 에러 발생

배열 선언

  • 타입[] 변수; OR 타입 변수[];

배열 생성

  • 타입[] 변수 = {값0, 값1, 값2, …};
  • 변수 = new 타입[] {값0, 값1, …};
  • new 연산자로 배열 생성하기
    • 향후 값들을 저장할 배열을 미리 만들고 싶다면?
      • 타입[] 변수 = new 타입[길이]; 로 하면 된다!
      • 나중에 배열 변수.length; 로 배열의 길이를 측정할 수 있다.

열거 타입

열거 타입

  • 한정된 값인 열거 상수 중, 하나의 상수를 저장하는 타입
    public enum Alpha {
    	A,
    	B,
    	C,
    	D
    }
    • Alpha → 열거 타입
    • Alpha str; 로 변수 선언
    • str = Alpha.A; 로 변수에 저장 가능

열거 타입 선언

  • 열거 타입 이름 → 소스 파일 이름과 대소문자가 모두 일치해야함
  • 열거 상수 → 여러 단어로 구성될 경우 ⇒ 단어 사이를 ‘_’로 연결하는 것이 관례

열거 타입 변수

위에서 간단하게 언급을 했는데 다시 살펴보자면

1️⃣ 열거타입 변수;

로 선언 후,

2️⃣ 열거타입 변수 = 열거타입.열거상수;

로 변수에 열거 상수를 저장한다.

열거상수도 객체인가?

정답은 🙆‍♀️.

열거 상수는 열거 객체로 생성된다!

[추가]2주차의 내용을 총괄하는 실습을 해보자!

조건문과 반복문을 둘 다 사용해볼 수 있는 실습문제가 있었는데 이것저것 적용을 해볼 수 있었다.

public class Main {

    public static void main(String[] args) {
        boolean run = true;
        int studentNum = 0;
        int[] scores = null;
        Scanner scanner = new Scanner(System.in);

        while(run) {
            System.out.println("-----------------------------------");
            System.out.println("1.학생수 | 2.정수입력 | 3.정수리스트 | 4.분석 | 5. 종료");
            System.out.println("-----------------------------------");
            System.out.print("선택> ");

            int selectNo = Integer.parseInt(scanner.nextLine());

            if (selectNo == 1) {
                System.out.print("학생 수>");
                studentNum = Integer.parseInt(scanner.nextLine());
                scores = new int[studentNum];
            } else if (selectNo == 2) {
                for (int i = 0; i < studentNum; i++) {
                    System.out.print("scores" + "[" + i + "]> ");
                    scores[i] = Integer.parseInt(scanner.nextLine());
                }
            } else if (selectNo == 3) {
                for (int i = 0; i < scores.length; i++) {
                    System.out.printf("scores[%d]> %d\n", i ,scores[i]);
                }
            } else if (selectNo == 4) {
                int maxScore = 0;
                if (scores != null) {
                    maxScore = Arrays.stream(scores)
                                        .max()
                                        .getAsInt();
                }

                double averageScore = 0;
                if (scores != null) {
                    averageScore = Arrays.stream(scores)
                                        .average()
                                        .getAsDouble();
                }

                System.out.println("최고 점수: " + maxScore);
                System.out.println("평균 : " + averageScore);

            } else if (selectNo == 5) {
                run = false;
            }
        }
        System.out.print("프로그램 종료");
    }
}


코드에 따라 메모리 영역이 어떻게 정의되는지 그림으로 그려보았다-🐥
(주소는 임의로 설정했다. )

null로 선언한 scores라는 배열을 나중에 어떻게 초기화하는지에 대해서 까먹지만 않는다면 NullPointerException을 마주쳐서 서비스가 다운되어버리는 일은.. 없을 것..

profile
Say Hi!

0개의 댓글