오늘은 금요일입니다. 벌써 항해를 시작한지 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 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]);
}
}
}
}
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);
}
}
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("프로그램 종료!!!");
}
}