오늘은 금요일입니다. 벌써 항해를 시작한지 5일이 지났네요. 입학시험도 무사히 치르고 일주일동안 많은 것들을 학습했습니다. 아직 Java와 친해지려면 멀었지만요. 프로그래밍 언어는 인간의 언어보다 더 규칙적이라 독일어 배울 때를 생각하면 훨씬 쉬운 것 같습니다만 시간이 좀 필요합니다. 🎼오늘의 노래: 로꼬 - '시간이 들겠지'.
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값
- 배열이 생성되고 나서 특정 인덱스 위치에 새로운 값을 저장
- 변수[인덱스] = 값;
- 향후 값들을 저장할 배열을 미리 만들고 싶다면 new 연산자로 배열 객체 생성
배열 길이
- 배열에 저장할 수 있는 전체 항목의 개수
- .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 매개 변수를 통해서 명령 라인에서 입력된 데이터의 수(배열의 길이)와 입력된 데이터(배열의 항목 값)을 알 수 있음
- (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 에러 발생
- 문자열로 인식되니까 숫자로 바꾸려면 Integer.parseInt() 메소드를 이용해서 정수로 변환함
다차원 배열
- 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;
'TIL' 카테고리의 다른 글
TIL WIL 혼자 공부하는 자바 Java 복습 백준 221113 (0) | 2022.11.13 |
---|---|
TIL 혼자 공부하는 자바 JAVA 챕터 1~5 복습 221112 (0) | 2022.11.12 |
TIL 혼자 공부하는 자바 JAVA 핵심 쏙쏙 Git 3주차 푸시 토큰 오류 해결 221110 (0) | 2022.11.10 |
TIL 입학시험과 핵심 쏙쏙 Git 2주차 (0) | 2022.11.09 |
TIL 혼자 공부하는 자바 JAVA 연산자 핵심 쏙쏙 Git 1주차 221108 (0) | 2022.11.08 |