오늘은 금요일입니다. 벌써 항해를 시작한지 5일이 지났네요. 입학시험도 무사히 치르고 일주일동안 많은 것들을 학습했습니다. 아직 Java와 친해지려면 멀었지만요. 프로그래밍 언어는 인간의 언어보다 더 규칙적이라 독일어 배울 때를 생각하면 훨씬 쉬운 것 같습니다만 시간이 좀 필요합니다. 🎼오늘의 노래: 로꼬 - '시간이 들겠지'.

it takes time

Chapter 05-1 참조 타입과 참조 변수

기본타입과 참조 타입

  • 기본 타입(primitive type) 변수는 실제 값을 변수안에 저장
  • 참조 타입(배열, 열거, 클래스, 인터페이스) 변수는 메모리의 번지를 변수 안에 저장
  • 번지를 통해 객체를 참조한다는 뜻에서 참조 타입이라고 부름 -> heap memory

메모리 사용 영역

  • JVM은 Runtime Data Area(운영체제에서 할당받은 메모리 영역)을 아래와 같이 세부 영역으로 구분해서 사용
  • 메소드 영역 Method area: JVM이 시작할 때 생성되고 모든 스레드가 공유하는 영역; 코드에서 사용되는 class들을 클래스 로더로 읽어 클래스 별로 정적 필드(static field)와 상수constant, 메소드 코드, constructor(생성자) 코드 등을 분류해서 저장
  • 힙 영역 Heap Area: 객체와 배열이 생성되는 영역; JVM 스택 영역의 변수나 다른 객체의 필드에서 참조
    • 참조하는 변수나 필드가 없다면 의미 없는 객체가 되기 때문에 JVM이 쓰레기로 취급하고 쓰레기 수집기(Garbage Collector)를 실행시켜 자동으로 제거
    • 객체를 제거하기 위해 별도의 코드를 작성할 필요가 없음
    • 자바는 코드로 객체를 직접 제거하는 방법을 제공하지 않음
  • JVM 스택 영역 Stack area: 메소드를 호출할 때마다 Frame을 추가(push)하고 메소드가 종료되면 해당 프레임을 제거(pop)하는 동작을 수행
    • 프레임 내부에는 로컬 변수 스택이 있음 
    • 기본 타입 변수와 참조 타입 변수가 Push 되거나 Pop 
    • 최초로 변수에 값이 저장 될 때 stack 영역에 변수가 생성됨
    • 변수는 선언됨 블록 안에서만 스택에 존재하고 블록을 벗어나면 스택에서 제거 됨
    • 기본 타입 변수는 스택 영역에 직접 값을 가지고 있지만, 참조 타입 변수는 스택 영역에 힙 영역의 객체 주소를 가짐
    • 자바에서는 배열을 객체로 취급

메모리 사용 영역

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

  • 기본 타입 변수의 ==, != 연산은 true, false를 조사하지만 참조 타입 변수들은 동일한 객체를 참조하는지, 다른 객체를 참조하는지 알아볼 때 사용
  • 동일한 번지 값을 갖고 있다는 것 == 동일한 객체를 참조함

 

null과 NullPointerException

  • 참조 타입 변수는 힙 영역의 객체를 참조하지 않는다는 뜻으로 null 값을 가질 수 있음
  • null값을 초기값으로 사용할 수 있기 때문에 null로 초기화 된 참조 변수는 스택 영역에 생성됨
  • 참조 타입 변수가 null 값을 가지는지 확인하려면
    • 변수 ==, != null 연산을 수행하면 됨
  • 예외Exception: 프로그램 실행 도중에 발생하는 오류
    • 사용자의 잘못된 입력
    • 코드 잘못 작성
    • 가장 많이 발생하는 예외: NullPointerException-> 참조 타입 변수를 잘못 사용하면 발생함
      • 참조 변수가 null을 가지고 있을 경우에는, 참조 객체가 없으므로 변수를 통해 객체를 사용할 수 없음
      • null이 없는 상태에서 객체의 데이터나 메소드를 사용하는 코드 실행시 발생

String 타입

  • 문자열이 직접 변수에 저장되는 것이 아니라, 문자열은 String 객체로 생성되고 변수는 String 객체를 참조함
  • 문자열 리터럴이 동일하면 String 객체를 공유함
  • 공유하지 않고 별개의 객체에 저장하려면-> new 연산자를 사용해서 직접 String 객체를 생성
    • new 연산자= 객체 생성 연산자
  • 문자열 리터럴로 생성 vs. new 연산자로 생성 
    • 동일한 문자열 리터럴로 String 객체 생성했을 경우: ==연산의 결과는 true
    • new 연산자로 생성 했을 경우: ==연산 결과는 false
    • == 연산자는 변수의 저장된 객체의 번지가 동일한지를 검사하기 때문
    • 동명이인 같은 걸 입력할 때 쓰는 방법일까....?
  • 객체에 상관없이 내부 문자열을 비교하고 싶을 때 -> equals() 메소드를 사용
  • String 변수는 참조 타입으로 초기값으로 null을 대입할 수 있음
    • String 변수가 참조하는 String 객체가 없다는 의미
    • String hobby = null 
  • 참조를 잃은 String 객체는.... goes to the Garbage Collector

 

Chapter 05-2 배열

배열이란? array

  • 같은 타입의 데이터를 연속된 공간에 나열하고 각 데이터에 인덱스(index)를 부여해놓은 자료 구조
  • 인덱스는 0부터 시작함
  • 배열의 특징
    • 같은 타입의 데이터만 저장; 다른 타입 저장하면 타입 불일치 컴파일 에러 발생 type mismatch
    • 한 번 생성된 배열은 길이를 늘리거나 줄일 수 없음
      • 새로운 배열을 생성하고, 기존 배열 항목을 새 배열로 복사하는 수밖에 없음

배열 선언

  • 배열을 사용하기 위해서는 배열 변수를 선언해야함
  • 형식1: 타입[] 변수;
  • 형식2: 타입 변수[];
  • 배열 변수는 참조 변수
  • 배열은 객체로 힙 영역에 생성되고 배열 변수는 힙 영역의 배열 객체를 참조함
    • 참조할 배열 객체가 없다면 배열 변수는 null값으로 초기화 됨
    • 배열 변수가 null 값을 가진 상태에서 변수로 값을 읽거나 저장하면 -> NullPointerException 에러 발생
    • 배열을 생성하고 배열 변수가 참조하는 상태에서 값을 저장하거나 읽어야함

배열 생성

  • 값 목록 이용 또는 new 연산자 이용
  • 값 목록으로 배열 생성
    • 타입[] 변수 = {값0, 값1, 값2, 값3, ...}
    • 배열 변수를 이미 선언한 후에는 다른 실행문에서 중괄호를 사용한 배열 생성이 안됨 -> 컴파일 에러!
    • 배열 변수를 미리 선언한 후 값 목록들이 나중에 결정되는 상황에는 -> new 연산자 사용해서 값 목록을 지정!
      • 변수 = new 타입[] {값0, 값1, 값2, 값3, ...}
    • 메소드의 매개값이 배열일 경우에도 new 연산자를 사용
      • int result = add( new int[] {값0, 값1, 값2} );
public class prac {
    public static void main(String[] args) {
        int[] scores;
        scores = new int[] {83,90, 87};
        int sum1 = 0;
        for (int i=0; i<3; i++){
            sum1 += scores[i];
        }
        System.out.println("총합 : " + sum1);

        int sum2 = add( new int[]{83, 90,87});
        System.out.println("총합 : " + sum2);
        System.out.println();
    }

    public static int add(int[] scores){
        int sum =0;
        for(int i=0; i<3;i++){
            sum += scores[i];
        }
        return sum;
    }
}

 

  • new 연산자로 배열 생성
    • 향후 값들을 저장할 배열을 미리 만들고 싶다면 new 연산자로 배열 객체 생성
      • 타입[] 변수 = new 타입[길이];
      • 길이 == 배열이 저장할 수 있는 값을 개수
    • new 연산자로 배열을 처음 생성할 경우-> 기본값 0으로 초기화; String이라면 null값
    • 배열이 생성되고 나서 특정 인덱스 위치에 새로운 값을 저장
      • 변수[인덱스] = 값;

 

배열 길이

  • 배열에 저장할 수 있는 전체 항목의 개수
  • .length 사용
    • 읽기 전용 필드기 때문에 값을 바꿀수 없음
    • for 문 사용할 때 유용

배열의 length 필드

public class prac {
    public static void main(String[] args) {
        int[] scores = {83,90,87};
        int sum =0;
        for(int i=0; i<scores.length; i++){
            sum+=scores[i];
        }
        System.out.println("총합 : " + sum);

        double avg = (double) sum/scores.length;
        System.out.println("평균 : " + avg);
    }
}
  • < 연산자를 사용한 이유는 배열의 마지막 인덱스는 배열 길이보다 1이 적기 때문~~
    • 인덱스 초과해서 사용시 -> ArrayIndexOutOfBoundsException 에러 발생

 

명령 라인 입력

  • public static void main(String[] args){ .... }
    • (String[] args)가 필요한 이유
      • 명령 라인(명령 프롬프트)에서 위 코드를 java 명령어로 실행하면 JVM은 길이가 0인 String 배열을 먼저 생성하고 Main() 메소드를 호출할 때 매개값으로 전달
    • main() 메소드는 String[] args 매개 변수를 통해서 명령 라인에서 입력된 데이터의 수(배열의 길이)와 입력된 데이터(배열의 항목 값)을 알 수 있음

  •  
  • 매개 값을 주고 실행하는 법 (명령 프롬프트(터미널)에서 실행하는 방법)
    • JDK 11 이후 버전: java -p . -m chap05/sec02.exam05.MainStringArrayArgument 10 20
    • JDK 8 이전 버전: java sec02.exam05.MainStringArgument 10 20
  • args는 {"10", "20"}을 array로 참조
    • 문자열로 인식되니까 숫자로 바꾸려면 Integer.parseInt() 메소드를 이용해서 정수로 변환함
      • 정수로 변환할 수없는 문자열이라면 -> NumberFormatException 에러 발생

 

다차원 배열

  • 2차원 배열: 행과 열로 구성된 배열; 가로 인덱스와 세로 인덱스를 사용함
    • 자바는 중첩 배열 방식으로 구현
    • int[][] scores = new int [2][3]
  • 배열의 정확한 길이를 알고 인덱스를 사용해야 함
    • 아니면 ArrayIndexOutOfBoundsException 에러 발생
  • int[][] scores = { {95, 80}, {92, 96}};
행, 열 0 1
0 95 92
1 80 96

 

int score = scores[0][0]; /95
int score = scores[1][1]; /96

 

배열 속의 배열

public class prac {
    public static void main(String[] args) {
        int[][] mathScores = new int[2][3];
        for (int i = 0; i < mathScores.length; i++) {
            for (int k = 0; k < mathScores[i].length; k++) {
                System.out.println("mathScores[" + i + "][" + k + "]=" + mathScores[i][k]);
            }
        }
        System.out.println();

        int[][] englishScores = new int[2][];
        englishScores[0] = new int[2];
        englishScores[1] = new int[3];
        for (int i = 0; i < englishScores.length; i++) {
            for (int k = 0; k < englishScores[i].length; k++) {
                System.out.println("englishScores[" + i + "][" + k + "]=" + englishScores[i][k]);
            }
        }
        System.out.println();

        int[][] JavaScores = {{95, 80}, {92, 96, 80}};
        for (int i = 0; i < JavaScores.length; i++) {
            for (int k = 0; k < JavaScores[i].length; k++) {
                System.out.println("JavaScores[" + i + "][" + k + "]=" + JavaScores[i][k]);
            }
        }
    }
}

중첩for문을 보니 이제 기분이 좋아진다... for문 좋아요😍

 

 

객체를 참조하는 배열

  • 참조 타입(클래스, 인터페이스) 배열은 각 항목에 객체의 번지를 가짐
    • String은 클래스 -> String[] 배열은 String 객체의 번지를 가짐 -> String[] 배열은 String 객체의 번지를 참조함
    • String[] 배열의 항목은 String 변수와 동일하게 취급
      • Ex) == 대신 equals() 메소드 사용 

배열 복사

  • for 문을 사용하거나 System.arraycopy() 메소드를 사용함

for문으로 배열 복사

public class prac {
    public static void main(String[] args) {
        int[] oldIntArray = {1,2,3};
        int[] newIntArray = new int[5];

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

        for(int i=0; i<newIntArray.length; i++){
            System.out.print(newIntArray[i] + ", ");
        }
    }
}

 

  • System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

System.arraycopy()로 배열 복사

public class prac {
    public static void main(String[] args) {
        String[] oldStrArray = { "java", "array", "copy"};
        String[] newStrArray = new String[5];

        System.arraycopy( oldStrArray, 0, newStrArray, 0, oldStrArray.length);

        for(int i=0; i< newStrArray.length; i++){
            System.out.print(newStrArray[i] + ", ");
        }
    }
}
  • 복사되지 않은 항목은 null 처리 됨
  • 참조 타입 배열이 복사되면 복사되는 값이 객체의 번지이므로 새 배열의 항목은 이전 배열의 항목이 참조하는 객체와 동일

 

항상된 for문 enhanced for statements

  • for(타입 변수: 배열){ ... } 
  • 배열의 항목 개수 만큼 반복하고 자동적으로 for문을 종료; 반복할 때마다 변수에는 배열에서 가져온 항목이 저장됨

향상된 for문

public class prac {
    public static void main(String[] args) {
        int[] scores = { 95, 71, 84, 93, 87};

        int sum = 0;
        for (int score : scores){
            sum = sum + score;}
        System.out.println("점수 총합 = " +sum);

        double avg = (double) sum / scores.length;
        System.out.println("점수 평균 = " +avg);
    }
}

 

확인 문제🥲🥲

3. 

int[][] array = {
	{95, 86},
    {83, 92, 96},
    {78, 83, 93, 87, 88}
};

array.length -> 3 //3줄

array[2].length -> 5 //3번째 줄은 5개 있음

 

4. for문 이용해서 배열의 항목에서 최대값 구하기

public class prac {
    public static void main(String[] args) {
        int max = 0;
        int[] array = { 1, 5, 3, 8, 2};

        //작성 위치
        for(int i=0; i<array.length; i++){
            if (max < array[i]) {
                max = array[i];
            }
        }

        System.out.println("max: " + max);
    }
}

 

5. 중첩for문을 이용해서 주어진 배열의 전체 항목의 합과 평균값 구하기

public class prac {
    public static void main(String[] args) {
        int[][] array = {
                {95, 86},
                {83, 92, 66},
                {78, 83, 93, 87, 88}
        };

        int sum = 0;
        double avg = 0.0;

        //작성 위치
        int count =0;
        for(int i=0; i<array.length; i++){
            for(int k=0; k<array[i].length; k++){
                sum += array[i][k];
                count++;
            }

        }
        avg = (double) sum/ count;

        System.out.println("sum: " +sum);
        System.out.println("avg: " +avg);

    }
}

 

7. 학생 점수 구하기

import java.util.Scanner;

public class prac {
    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.println("선택> ");

            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 < scores.length; i++) {
                    System.out.println("scores[" + i + "]> ");
                    scores[i] = Integer.parseInt(scanner.nextLine());
                }
            } else if (selectNo == 3) {
                for (int i = 0; i < scores.length; i++) {
                    System.out.println("scores[" + i + "]:" + scores[i]);
                }


            } else if (selectNo == 4) {
                int max = 0;
                int sum = 0;
                double avg = 0.0;
                for (int i = 0; i < scores.length; i++) {
                    max = (max < scores[i]) ? scores[i] : max;
                    sum += scores[i];
                }
                avg = (double) sum / studentNum;
                System.out.println("최고 점수: " + max);
                System.out.println("평균 점수: " + avg);
            } else if (selectNo == 5) {
                run = false;

            }

        }
        System.out.println("프로그램 종료!!!");
    }


}

 

tenary operator: 삼항연산자

max = (max <scores[i]) ? scores[i] : max;

==

int max;

if(max<scores[i]){scores[i];} else{max;}

 

더 단순한 variables로 설명하자면,,,,

 

return (a>b ? a:b);

==
int a=10, b=5;
if(a>b)
	return a;
else
	return b;

+ Recent posts