배열은 수학에서 사용하는 배열을 프로그래밍적인 리스트의 형태로 구현한 것이다.
간단히 말하면, 엘범이라 생각하면 좋다. 여러가지 사진을 각각의 다른 페이지에 넣어서 저장하는 엘범처럼
배열도 각 변수를 하나의 상자안에 각각 넣어둔다.
String[] weeks = {"월", "화", "수", "목", "금", "토", "일"};
실제 위는 변수 선언인데, 이 경우 ['월' 이란 사진]을 <0번째 상자>에 담고 ['화' 라는 사진]을 <1번째 상자>에 담고 ~~~~ ['일' 라는 사진]을 <6번째 상자>에 담은 { weeks 라는 엘범 }을 만든다는 의미이다.
더 정확한 CS 식 표현은
- weeks라는 이름의 String 타입의 배열을 선언한다
- 배열 안에는 7가지의 문자를 추가한다
- 각 문자는 하나의 연속된 메모리 공간에 데이터를 순서대로 저장한다
- 문자는 각각의 인덱스를 부여받아 주소로서 접근이 가능하다
흔히 이 엘범에 해당하는 부분을 자료구조 라고 부른다.
+ 자료구조
- 데이터를 효율적으로 저장하고 관리하는 방법으로 배열은 그 중에 하나의 형태일 뿐이다.
- 컴퓨터 과학에서 효율적인 접근 및 수정을 가능케 하는 자료의 조직, 관리, 저장 이라 정의되어 있다...
- 고정된 크기: 배열은 생성 시 크기가 고정되며, 데이터가 추가되거나 삭제되지 않는다.
- 인덱스를 통한 접근: 각 데이터는 고유한 인덱스 번호로 접근할 수 있어 효율적인 데이터 조회가 가능합니다.
생성
위에서 설명을 했지만, 세부적인 내용은 아래와 같다.
- int 타입의 배열 array를 생성한다.
- 참조형 변수 처럼 new를 사용하여 int 정수 8개를 포함할 리스트를 생성한다.
- int로 타입을 지정한 만큼, 모든 리스트 내의 변수는 0으로 초기화 되어 있다.
+ int는 0, boolean 은 false, String 은 null 값과 같은 초기값이 정해져 있다.
+ new를 쓰는 이유는, heap에 메모리를 할당하고 초기화 해달라는 명령이다.('들어갈거니 자리만들어 달라' 는 말)
// 배열 생성
//배열 생성후 초기화하면 배열의 주소가 할당된다.
int[] intArray = new int[3]; // 초기값 {0,0,0}
boolean[] boolArray = new boolean[3]; // 초기값 {false, false, false}
String[] stringArray = new String[3]; // 초기값 {"","",""}
//배열 선언만 해놓고 나중에 초기화를 시킬수도 있다.
int[] intArray2;
intArray2 = new int[3]; // 초기값 {0,0,0}
초기화
- 변수나 배열, 객체 등 메모리에 할당된 공간에 처음 값을 설정하는 과정을 말한다.
- 초기화는 변수나 데이터 구조의 값이 예측 가능한 상태에서 작업을 시작할 수 있으므로, 에러를 줄이고 코드의 안정성을 높일 수 있다는 장점이 있다.
명시적 초기화
- 사용자가 직접 값을 할당하여 초기화하는 방법
// 배열 초기화
import java.util.Arrays; // Arrays 클래스를 import 해주세요!
public class Main {
public static void main(String[] args) {
//1. 배열에 특정값 대입하며 선언
int[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"a", "b", "c", "d"};
//2-1. for문을 통해 값을 대입
for (int i = 0; i < intArray.length; i++) {
intArray[i] = i;
}
//2-2. 향상된 for문을 통한 배열 출력
for (int i : intArray) {
System.out.print(i); // 01234
}
System.out.println(); // 줄바꿈
//3. 배열의 주소를 모두 같은값으로 초기화
Arrays.fill(intArray, 1);//배열의 모든 값을 1로 초기화
for (int i : intArray) {
System.out.print(i); // 11111
}
}
}
// 출력
01234
11111
묵시적 초기화
- 자바에서는 배열이나 객체의 멤버 변수는 자동으로 기본값으로 초기화된다. 위의 int의 0처럼 말이다.
int[] numbers = new int[5]; // int 배열의 모든 요소가 0으로 초기화됨
boolean[] flags = new boolean[3]; // boolean 배열의 모든 요소가 false로 초기화됨
생성자 초기화
- 객체를 생성할 때, **생성자(Constructor)**를 통해 객체의 필드를 초기화할 수 있다.
public class Person {
String name;
int age;
// 생성자를 이용한 초기화
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Person person = new Person("홍길동", 25); // 객체 생성 시 생성자를 통한 초기화
순회
- 배열안에 담겨있는 변수들을 하나씩 꺼내서 사용하는 것을 순회라고 합니다.
- 이 순회도 정말 많은 방식이 존재한다 (부르트포스와 같은 완전탐색 부터 다양하다... 코테에서 자주 출몰한다...)
//길이가 8인 정수배열 선언
int[] intArray = new int[3];
// 배열이 초기화된 값을 출력해본다.
for(int i=0; i<intArray.length; i++) { // .length 는 배열의 길이
System.out.println(intArray[i]);
}
// 출력
0
0
0
// int[] intArray = new int[3];
// intArray = {1,2,3}
// System.out.println(intArray[1]);
// 결과 = 2
+ 추가로 .length()라는 메서드가 있는데 배열의 길이를 반환해준다. 위의 경우에 intArray.length()를 입력하면 배열 안에 변수가 3개이니 3이 입력된다.
복사
얕은 복사 | 참조형 변수인 배열은 heap에 실제 값이 저장되고 stack에 주소가 저장된다 얕은 복사는 = 을 사용하는 복사로, 실제 값이 저장되는 것이 아닌 주소를 공유하게 된다 |
깊은 복사 | 여기는 반대로 주소를 하나 더 생성한다 즉, 자리를 1개 더 만든 것임으로 메모리를 더 차지한다. |
분명 p, q라는 2개의 변수가 생성되었지만 실제 값은 100하나만 있고 p, q가 같은 100의 주소를 들고 있다. 다만 반대의 경우 100, 90이라는 값이 heap에 저장되었고 당연히 stack도 따로 생성된다.
// 얕은 복사
int[] a = { 1, 2, 3, 4 };
int[] b = a; // 얕은 복사
b[0] = 3; // b 배열의 0번째 순번값을 3으로 수정했습니다. (1 -> 3)
System.out.println(a[0]); // 출력 3 <- a 배열의 0번째 순번값도 3으로 조회됩니다.
// 깊은 복사 메서드
// 1. clone() 메서드
int[] a = { 1, 2, 3, 4 };
int[] b = a.clone(); // 가장 간단한 방법입니다.
// 하지만, clone() 메서드는 2차원이상 배열에서는 얕은 복사로 동작합니다!!
// 깊은 복사 메서드
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
// 2. Arrays.copyOf() 메서드
int[] a = { 1, 2, 3, 4 };
int[] b = Arrays.copyOf(a, a.length); // 배열과 함께 length값도 같이 넣어줍니다.
}
}
String 배열
// 선언 후 하나씩 초기화 할 수 있습니다.
String[] stringArray = new String[3];
stringArray[0] = "val1";
stringArray[1] = "val2";
stringArray[2] = "val3";
// 선언과 동시에 초기화 할 수 있습니다.
String[] stringArray1 = new String[]{"val1", "val2", "val3"};
String[] stringArray2 = {"val1", "val2", "val3"};
위의 int와 다르게 문자열의 배열이 선언되는 String은 위 처럼 프로그래머가 각 변수를 초기화할 수 있지만, 만약 초기화를 따로 하지 않으면 각 변수에 null 값이 저장된다.
+ 간혹 null이 0인줄 아는 사람들이 있던데, null은 엄밀히 말하면 완전히 비어있는 값을 말한다
+ 변수나 객체가 아무것도 가리키지 않거나 할당되지 않았을 때 흔히 null이 설정된다.
+ String = char[]??
- 엄밀히 말하면 문자열( String )과 문자 배열( char[] )은 다르다.
- String은 참조형 데이터, char은 기본 데이터 배열이다.
그래서 뭐가 다른가
- 불변성:
- String은 불변(immutable) 객체로 한 번 생성되면 수정할 수 없습니다. 대신 새로운 String 객체를 생성합니다.
- char[]는 가변이어서 배열의 각 요소를 자유롭게 변경할 수 있습니다.
- 메서드:
- String은 문자열을 다루기 위한 다양한 메서드들이 내장되어 있습니다 (예: length(), substring(), toUpperCase(), equals() 등).
- char[]는 기본 배열로만 동작하며, 문자 배열을 처리하려면 수동으로 루프를 돌거나 메서드를 작성해야 합니다.
- 메모리:
- String은 객체로 힙 메모리에서 관리되고, 문자열 리터럴을 사용하는 경우 String Pool에 저장될 수 있습니다.
- char[]는 배열이므로 힙 메모리에 저장됩니다. 배열은 메모리에서 연속적으로 공간을 차지합니다.
실제 String에는 아래와 같은 다양한 기능이 추가적으로 존재한다.
메서드
|
응답값 타입
|
설명
|
length()
|
int
|
문자열의 길이를 반환한다.
|
charAt(int index)
|
char
|
문자열에서 해당 index의 문자를 반환한다.
|
substring(int from, int to)
|
String
|
문자열에서 해당 범위(from~to)에 있는 문자열을 반환한다. (to는 범위에 포함되지 않음)
|
equals(String str)
|
boolean
|
문자열의 내용이 같은지 확인한다. 같으면 결과는 true, 다르면 false가 된다.
|
toCharArray()
|
char[]
|
문자열을 문자배열(char[])로 변환해서 반환한다.
|
new String(char[] charArr)
|
String
|
문자배열(char[]) 을 받아서 String으로 복사해서 반환한다.
|
// String 기능 활용하기
String str = "ABCD";
// length()
int strLength = str.length();
System.out.println(strLength); // 4 출력
// charAt(int index)
char strChar = str.charAt(2); // 순번은 0부터 시작하니까 2순번은 3번째 문자를 가리킵니다.
System.out.println(strChar); // C 출력
// substring(int from, int to)
String strSub = str.substring(0, 3); // 0~2순번까지 자르기 합니다. (3순번은 제외)
System.out.println(strSub); // ABC 출력
// equals(String str)
String newStr = "ABCD"; // str 값과 같은 문자열 생성
boolean strEqual = newStr.equals(str);
System.out.println(strEqual); // true 출력
// toCharArray()
char[] strCharArray = str.toCharArray(); // String 을 char[] 로 변환
// 반대로 char[] 를 String로 변환하는 방법
char[] charArray = {'A', 'B', 'C'};
String charArrayString = new String(charArray); // char[] 를 String 으로 변환
다차원 배열
- 이름만 들어도 이게 뭔가 싶은 다차원 배열은 우리가 흔히 말하는 차원 개념과 동일하다
Rank 1의 경우 차원(axis)가 1개임으로 1차원 배열, Rank 3의 경우 차원(axis)가 3개임으로 3차원 배열이라 부른다. 어럽게 생각할 필요 없이
1 차원은 책 1개
2차원은 앨범 여러개를 담은 책장 1개
3차원은 책장 여러개를 담은 창고 1개
라고 보면 쉽다.
선언은 간단한데, 그냥 위와 같다.
// 반복문을 통한 초기화
int[][] array = new int[2][3]; // 최초 선언
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
arr[i][j] = 0; // i, j 는 위 노란색 네모박스 안에있는 숫자를 의미하며 인덱스 라고 부릅니다.
}
}
// 중괄호를 사용해 초기화
int[][] array = {
{1, 2, 3},
{4, 5, 6}
};
가변 배열
- Java 프로그래밍에서는 2차원 배열을 생성할 때 열의 길이를 생략하여, 행마다 다른 길이의 배열을 요소로 저장할 수 있다.
- 이렇게 행마다 다른 길이의 배열을 저장할 수 있는 배열을 가변 배열이라고 한다.
// 가변 배열
// 선언 및 초기화
int[][] array = new int[4][];
// 배열 원소마다 각기다른 크기로 지정 가능합니다.
array[0] = new int[3];
array[1] = new int[4];
array[2] = new int[5];
array[3] = new int[2];
// 중괄호 초기화할때도 원소배열들의 크기를 각기 다르게 생성 가능합니다.
int[][] array2 = {
{10, 20},
{10, 20, 30},
{10, 20, 30, 40},
{10, 20, 30, 40, 50},
{10, 20}
};
- 이보다 위의 차원은 int[][][] MultiArray = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}} 이런식으로 늘리면 된다. 보통 3차원까지만 사용한다.
오늘 문제
public class FindElement3DArray {
public static void main(String[] args) {
int[][][] array = new int[3][3][3];
// 배열 초기화
int value = 1;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
array[i][j][k] = value++;
}
}
}
// 특정 값 찾기 (예: 15)
int target = 15;
boolean found = false;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) {
if (array[i][j][k] == target) {
System.out.println("Found " + target + " at position (" + i + ", " + j + ", " + k + ")");
found = true;
break;
}
}
if (found) break;
}
if (found) break;
}
if (!found) {
System.out.println(target + " not found in the array.");
}
}
}
// 결과 : Found 15 at position (1, 1, 2)
public class FindElement3DArray { // 클래스 선언: FindElement3DArray 클래스를 정의합니다.
public static void main(String[] args) { // main 메서드: 프로그램이 실행될 시작 지점입니다.
int[][][] array = new int[3][3][3]; // 3x3x3 크기의 3차원 배열을 선언합니다.
// 배열 초기화
int value = 1; // 배열에 채울 값의 초기값을 1로 설정합니다.
// 3차원 배열의 모든 요소를 채우는 반복문입니다.
for (int i = 0; i < 3; i++) { // 첫 번째 차원 (i) 반복: 3번 반복
for (int j = 0; j < 3; j++) { // 두 번째 차원 (j) 반복: 3번 반복
for (int k = 0; k < 3; k++) { // 세 번째 차원 (k) 반복: 3번 반복
array[i][j][k] = value++; // 현재 위치에 값(value)을 넣고, 값을 증가시킵니다.
}
}
}
// 특정 값 찾기 (예: 15)
int target = 15; // 찾고자 하는 값(target)을 15로 설정합니다.
boolean found = false; // 값을 찾았는지 여부를 저장할 변수입니다. 초기값은 false입니다.
// 3차원 배열을 순차적으로 탐색하는 반복문입니다.
for (int i = 0; i < 3; i++) { // 첫 번째 차원 (i) 반복
for (int j = 0; j < 3; j++) { // 두 번째 차원 (j) 반복
for (int k = 0; k < 3; k++) { // 세 번째 차원 (k) 반복
if (array[i][j][k] == target) { // 현재 위치의 값이 target과 같으면
System.out.println("Found " + target + " at position (" + i + ", " + j + ", " + k + ")"); // target 값을 찾았을 때 해당 위치를 출력합니다.
found = true; // 값을 찾았으므로 found를 true로 설정합니다.
break; // 내부 반복문을 종료합니다. (k 반복문)
}
}
if (found) break; // target을 찾았으면 j 반복문을 종료합니다.
}
if (found) break; // target을 찾았으면 i 반복문을 종료합니다.
}
// 값을 찾지 못한 경우
if (!found) { // found가 여전히 false라면, target을 찾지 못한 경우입니다.
System.out.println(target + " not found in the array."); // 찾지 못했다고 출력합니다.
}
}
}
'Back-End (Web) > JAVA' 카테고리의 다른 글
[JAVA] 객체지향 프로그래밍 (1) | 2024.11.12 |
---|---|
[JAVA] 참조형 자료구조 정리(LIST / STACK / QUEUE / SET / MAP) (0) | 2024.11.11 |
[JAVA] 반복문 (0) | 2024.11.11 |
[JAVA] 조건문 (0) | 2024.11.11 |
[JAVA] 연산자 (0) | 2024.11.11 |