학원 13일차 - Java

103449 단어 학원자바자바

2021.04.14

배열

배열을 만드는 목적

  • 한번에 변수를 여러개 만들기 위해서
  • 같은 자료형 + 같은 성격의 데이터 -> 다량으로 저장하기 위한 공간 필요.
int[] kor = new int[3]; //int방x3개
kor[0] = 100; //국어점수 
kor[1] = 90; //국어 점수
kor[2] = 80; // 영어점수 -> 배열을 만드는 목적에 부합되는 데이터만 집어넣어야함.


int[] score = new int[3];
score[0] = 100; //국어점수
score[1] = 90; //영어점수
score[2] = 80; //수학점수

System.out.println(kor[0]);//국어 점수 
System.out.println(score[1]); //어떤 과목의 점수..?

//배열의 장점: 방을 번호화 시켜서 방 여러개를 효과적으로 탐색하고 관리 할 수 있음.
//배열의 단점: 배열의 방마다 어떤 데이터가 들어있는지 정확히 알기 어려움.

//[index] 표기법 > Indexer(인덱서)
//score[0]

메모리 구조

  • 값형과 참조형(모든 자료형)은 메모리에 공간이 한번 할당되면 그 공간의 크기를 변경할 수 없다.★
  • 메모리에 잡힌 공간은 변경이 불가능하다.
  • 모든 지역 변수는 값형, 참조형에 상관없이 무조건 Stack에 생성된다.
  1. 값형(8가지)

    • 데이터가 변해도 공간의 크기가 변하지 않는다.★
  1. 참조형(String, Array, Calendar, Math, BufferedReader...)

    • 데이터에 따라 공간의 크기가 일정하지 않다.★

    • 공간의 크기를 미리 예측 불가능하다.

  • 값형
//값형, 원시형
//0000 0000 0000 0000 0000 0000 0000 1010  -> int n = 10;         -> 4byte
//0000 0000 1001 1000 1001 0110 1000 0000  -> int n = 10000000;   -> 4byte

int n = 10;		
n = 10000000;

boolean b = true;
double d = 3.14;

System.out.println(n);

  • 참조형
//참조형
//글자 하나당 2byte
String s1 = "홍길동";  // 6byte
String s2 = "안녕하세요"; // 10byte

s1 = "반갑습니다";
s2 = "하하";

System.out.println(s1);

  • 값형의 배열 - 공간에 데이터를 넣을 수 있음
int[] num2 = new int[3]; //int x 3 = 12byte

num2[0] = 100;
num2[2] = 300;

System.out.println(num2[2]);

  • 참조형의 배열 - 공간에 데이터를 넣을 수 없어서 또 다른 참조를 함.
String[] name = new String[3];

name[0] = "홍길동";
name[1] = "아무개";
name[2] = "하하하";

System.out.println(name[2]);


값형 복사 vs 참조형 복사

  • 값형 복사
    • Side Effect가 없다. (하나를 건들여도 다른 곳에 영향을 미치지 않는다. )
int a = 10;
int b;

b = a;

System.out.println(a); //10
System.out.println(b); //10

a++; //수정

System.out.println(a); //11
System.out.println(b); //10
  • 배열 복사(참조형 복사)
    • Side Effect가 있다.
    • 복사된 변수가 있었을 때 그 중 하나를 조작하면 나머지도 영향을 받는다.(주의!!!!!!!!!!)
private static void m7() {
    int[] num1 = new int[3];

    num1[0] = 100;
    num1[1] = 200;
    num1[2] = 300;

    output(num1); //100  200  300		

    int[] num2 = new int[3];
    
    // - int[] = int[] 같은 자료형끼리 복사
    // - 모든 참조형 변수끼리의 복사는 데이터 복사가 아닌 참조 주소 복사가 일어난다. ★★★★
    num2 = num1; // 복사
    
    output(num2); //100  200  300

    num1[0] = 500; //수정

    output(num1); //500  200  300
	
    //num1[0]의 수정이 num2[0]의 수정으로 반영???
    output(num2); //500  200  300
}

//메소드
//int[] num = num1; 참조형이 매개변수나 리턴값으로 넘어가는 경우, 주소값을 복사한다.★
private static void output(int[] num) {

    for (int i=0; i<num.length; i++) {
        System.out.printf("%d  ", num[i]);
    }
    System.out.println();
}


배열복사(참조형 복사)

  1. 얕은 복사, Shallow Copy
  2. 깊은 복사, Deep Copy

<정리> 참조형 복사

  1. 변수끼리 복사 -> 얕은 복사 -> 원본을 건드리면 복사본 수정된다.
  2. 실제 공간끼리 복사 -> 깊은 복사 -> 원본을 건드려도 복사본 영향을 받지 않는다.
int[] num1 = new int[3];

num1[0] = 100;
num1[1] = 200;
num1[2] = 300;

int[] num2; //= new int[3]; 생략가능

//얕은 복사 - 참조형 복사(주소값끼리 복사) -> 같은 배열이 조작됨. 
num2 = num1;


int[] num3 = new int[3];

num3[0] = 100;
num3[1] = 200;
num3[2] = 300;

int[] num4 = new int[3]; //배열은 꼭 만들어야 한다!!

//깊은 복사
for (int i=0; i<num3.length; i++) {
    //int = int
    //값형 복사(데이터 복사)
    num4[i] = num3[i];	
}

num3[0] = 500; //수정

output(num3); //500 200 300
output(num4); //100 200 300
  • 깊은 복사


배열탐색

  • for문을 사용해서 배열의 요소(Element)에 접근하기
String[] name = new String[5];

name[0] = "홍길동";
name[1] = "아무개";
name[2] = "유재석";
name[3] = "강호동";
name[4] = "신동엽";

//배열 탐색 -> for문을 사용해서 배열의 요소(Element)에 접근하기
for (int i=0; i<name.length; i++) {
    System.out.println(name[i]);
}
System.out.println();
  • 향상된 for문(Enhanced for Statement)
    • 배열나 컬렉셜을 대상으로만 사용이 가능하다.(iterator를 지원하는 자료형에 한해서..)
    • 루프 변수가 없다. > 안정성 높음 + 코드 간결함 (가독성)
    • 배열의 모든 요소를 순차적으로(★★★) 자동 탐색한다. > 다른 방식으로는 탐색 불가능
    • 속도가 for문보다 빠르다.
    • 읽기 전용 반복문 : 요소의 값을 수정할 수 없다.★★ -> 요소의 값을 수정하면 안된다!!!!
for (변수 : 집합) {
    
}
for (String temp : name) {
    System.out.println(temp);
}
System.out.println();
  • 일반 for문 vs 향상된 for문 => 수정가능 유무
//일반 for문
for (int i=0; i<name.length; i++) {
    System.out.println(name[i]);
    name[i] += "님"; //수정 -> name[i] = name[i] + "님"
}
System.out.println();


//향상된 for문 -> 배열을 직접 건들이지 않고 임시변수(지역변수)를 건들이기 때문에 수정이 반영되지 않는다. 
for (String temp : name) {
    System.out.println(temp);
    temp = "고객: " + name; //수정 -> 고객: 홍길동님
}
System.out.println();


//출력 -> 향상된 for문은 읽기 전용이기 때문에 수정되지 않음.
for (String temp : name) {
    System.out.println(temp);
}

int[] num = new int[10];

//쓰기 -> 일반 for문
for (int i=0; i<num.length; i++) {
    num[i] = (int)(Math.random() * 100) + 1; //1~100 난수를 배열에 넣기
}

//읽기 -> 일반 for문 or 향상된 for문
for (int n : num) {
    System.out.println(n); //배열을 순차적으로 탐색함.
}

값형 vs 참조형 - 초기화

//변수 선언
int n; //null
String s; //null

//지역 변수(★★★)는 초기화하지 않으면 사용이 불가능하다.
//System.out.println(n);
//System.out.println(s);

//<초기화해야할 값이 정해지지 않았지만 일단 초기화를 해야 하는 경우>

//참조형(주소값) 변수는 null로 초기화를 할 수 있다.
s = null;
s = "";

//값형 변수는 절대로 null로 초기화를 할 수 없다.
//n = null;
n = 0;

배열의 특징(참조형의 특징) 중 하나

  • 배열은 방을 만들면 개발자의 의도와 상관없이 모든 방이 특정값으로 초기화가 된다. -> 생성자

  • 어떤 값으로 초기화?(★★★)

    1. 정수 배열 > 0
    2. 실수 배열 > 0.0
    3. 문자 배열 > '\0'(null 문자, 문자코드값(0))
    4. 논리 배열 > false
    5. 참조형 배열 > null
int[] num = new int[5];

//초기화를 하지 않았는데 에러가 나지 않는다?? -> 특정값으로 자동초기화 된다. 
//정수형
System.out.println(num[0]); //num[0] 자료형 -> int
System.out.println(num[1]);
System.out.println(num[2]);
System.out.println(num[3]);
System.out.println(num[4]);

//실수형
double[] num2 = new double[3];
System.out.println(num2[0]);

//참조형
char[] list1 = new char[3];
System.out.println(list1[0]);
System.out.println((int)list1[0]); //캐스팅해서 확인

//논리형
boolean[] list2 = new boolean[3];
System.out.println(list2[0]);

//참조형
String[] list3 = new String[3];
System.out.println(list3[0]);

배열 초기화 리스트, 배열 초기자(Initializer)

타입[] 변수 = new 타입[]{,,};

타입[] 변수 = {,,};
int[] num1 = new int[5]; // 정수 배열 생성

//초기화
for (int i=0; i<num1.length; i++) {
    num1[i] = (i+1) * 100; 
}

//출력
for (int n : num1) {
    System.out.println(n);  //100 200 300 400 500
}


int[] num2 = new int[5]; //152, 45, 36, 98, 354 (불규칙한 값)

num2[0] = 152;
num2[1] = 45;
num2[2] = 36;
num2[3] = 98;
num2[4] = 354;

//A. 배열초기화 리스트 
int[] num3 = new int[] { 152, 45, 36, 98, 354 };

//B. 배열초기화 리스트 
int[] num4 = { 152, 45, 36, 98, 354 }; //★★★★★

String[] name = { "홍길동", "아무개", "하하하" };

boolean[] flag = { true, false, false, true, false };

char[] cs = { 'A', 'B', 'C' };

프로젝트 적용 - 데이터 만들기

  • 더미 데이터 특징 : 유효하지 않은 데이터일 수도 있음. -> 감안하고 만들 것!

  • 회원 정보 x 100명 분량의 데이터 만들기

  • 미리 정해야 할 것 - 회원 정보

    • 이름 : 문자열
    • 나이 : 숫자
    • 성별 : 숫자(1.남자, 2.여자)
    • 주소 : 문자열
  • Math.random() + 배열 을 이용

int count = 100; //회원수

//배열 생성(저장소)
String[] name = new String[count]; //이름
int[] age = new int[count]; //나이
int[] gender = new int[count]; //성별
String[] address = new String[count]; //주소

//기초 데이터 : 임의의 회원 정보를 생성하기 위한 기반 데이터

//이름(성)
String[] n1 = { "김", "이", "박", "최", "정", "한", "유", "조", "임", "왕" };

//이름(이름)
String[] n2 = { "대", "은", "창", "미", "준", "우", "나", "혜", "운", "인", "영", "수", "민", "호", "환", "혁", "현", "희", "준", "원" };


//주소
String[] a1 = { "서울시", "인천시", "부산시", "광주시", "대전시" };
String[] a2 = { "동대문구", "서대문구", "중구", "남구", "북구" };
String[] a3 = { "역삼동", "대치동", "성내동", "논현동", "염재동" };


//n1[임의의 방번호]
//System.out.println(n1[(int)(Math.random() * n1.length)]
//					+ n2[(int)(Math.random() * n2.length)]
//					+ n2[(int)(Math.random() * n2.length)]);


//배열에 담기
for (int i=0; i<count; i++) {

    //이름(성+이름+이름)
    name[i] = n1[(int)(Math.random() * n1.length)]
        + n2[(int)(Math.random() * n2.length)]
        + n2[(int)(Math.random() * n2.length)];
	
    //나이 -> 슷자 랜덤 그대로 사용
    age[i] = (int)(Math.random() * 41) + 19; //0~40 -> 19~59세

    //성별(1-남자 2-여자)
    gender[i] = (int)(Math.random() * 2) + 1;//0~1 -> 1~2

    //주소
    address[i] = a1[(int)(Math.random() * a1.length)] //시
        + " "
        + a2[(int)(Math.random() * a2.length)] //구
        + " "
        + a3[(int)(Math.random() * a3.length)] //동
        + " "
        + ((int)(Math.random() * 330) + 1) //번지
        + "번지";
}

//출력
for (int i=0; i<count; i++) {
    System.out.printf("[%s] %d세, %s, %s\n"
                      , name[i]
                      , age[i]
                      , gender[i] == 1 ? "남자" : "여자"
                      , address[i]);
}

배열의 업무(용도)에 맞는 사용법★★★★ - 시프트

  • 책상 > 상자 x 3개 있다고 가정했을 때, 여러가지 용도로 사용하고 싶다면 사용법이 다양함
  • 기본 사용법
    1. 방을 순차적으로 접근
    2. 원하는 방을 선택해서 접근
기본 사용법
public class Ex27_Array {
	
	public static void main(String[] args) {
        
    //기본 사용법
    //1. 방을 순차적으로 접근
    //2. 원하는 방을 선택해서 접근

    int[] num = new int[] { 5, 9, 7, 10, 3, 1, 2, 6, 7, 10 };

    //1. 차례대로 접근, 가장 기본적인 사용법
    
    //일반 for문으로 접근 - 변화를 줄 수 있다.
    for (int i=0; i<num.length; i++) {
        System.out.println(num[i]);
    }
    System.out.println();

    //향상된 for문으로 접근 - 변화를 줄 수 없다. 
    for (int n : num) {
        System.out.println(n);
    }
    System.out.println();

    //2. 특정방의 요소만 접근
    System.out.println(num[5]); // 5번째 방에 들어있는 값 : 1
    
    num[5] = 1000; //수정
    
    System.out.println(num[5]); // 1000
    }
}
줄서기
  • 비어있는 첫번째 방에 값을 넣어주기
public class Ex27_Array {

    public static void main(String[] args) {

        int[] list = new int[10];


        output(list); // 0 0 0 0 0 0 0 0 0 0 (초기화 규칙에 따라 0이 출력)	 

        add(list, 10); //list에 비어있는 방 중 가장 처음 방에 10(넣고 싶은 데이터)을 넣어주세요.

        output(list); //빈방에 숫자가 잘 들어갔는지 확인 : 10  0  0  0  0  0  0  0  0  0 

		//빈방에 차례로 값 채우기
        add(list, 20);
        add(list, 30);
        add(list, 40);
        add(list, 50);
        add(list, 60);
        add(list, 70);
        add(list, 80);
        
        output(list); //10  20  30  40  50  60  70  80  0  0 
        

    }//main

    private static void add(int[] list, int n) {
        //빈방 번호를 넣어줄 지역변수
        int index = -1;

        //가장 앞에 있는 빈방이 어딘지?
        for (int i=0; i<list.length; i++) {
            if (list[i] == 0) { //초기값이 0이니까 0을 찾으면 빈방.
                //빈방!!
                index = i; //처음 만나는 빈방번호
                break;
            }
        }

        //System.out.println(index);
        list[index] = n; //빈방에 10(값)를 넣어줌.

    }

    
    //값을 추출하는 메서드
    public static void output(int[] list) {

        for (int i=0; i<list.length; i++) {
            System.out.printf("%d  ", list[i]);
        }

        System.out.println();

    }

}

오른쪽 시프트, Right Shift (끼어들기, insert모드)
public class Ex27_Array {

    public static void main(String[] args) {

        int[] list = new int[10];

        add(list, 10);
        add(list, 20);
        add(list, 30);
        add(list, 40);
        add(list, 50);
        add(list, 60);
        add(list, 70);
        add(list, 80);

        output(list); //10  20  30  40  50  60  70  80  0  0 

        //30과 40 사이에 90을 추가하기(3번째 방)
        insert(list, 3, 90);

		output(list); // 10  20  30  90  40  50  60  70  80  0


    }//main

	//오른쪽 시프트
    private static void insert(int[] list, int index, int n) {
        
		//데이터를 삽입하기 전 값들을 오른쪽으로 먼저 이동시킴 
        //index가 큰 쪽(오른쪽)부터 이동
        //i=list.length-2 이유 : 제일 끝 방은 옮길 방이 없기 때문에, 오른쪽에서 두번째 방(length-2)부터 끝방으로 먼저 옮긴다.
        //i>=index (반복을 몇번 할건지) : 끼워 넣을 위치(index)까지만 값을 옮긴다.
        for (int i=list.length-2; i>=index; i--) {

            list[i+1] = list[i]; //왼쪽값을 오른쪽값으로 덮어씌움

            //output(list); -> 값이 옮겨지는 과정을 볼 수 있음

        }

        list[index] = n; //원하는 데이터(90)을 원하는 위치에 삽입
    }


    //값을 첫번째 빈방부터 채워주는 메소드
    private static void add(int[] list, int n) {

        int index = -1;

        for (int i=0; i<list.length; i++) {
            if (list[i] == 0) {

                index = i; 
                break;
            }
        }

        list[index] = n;
    }

    //값을 추출하는 메서드
    public static void output(int[] list) {

        for (int i=0; i<list.length; i++) {
            System.out.printf("%d  ", list[i]);
        }

        System.out.println();

    }

}
  • C부터 오른쪽으로 이동, B도 오른쪽으로 이동한 후, D를 삽입

  • 제일 끝 방은 옮길 방이 없기 때문에, 오른쪽에서 두번째 방(length-2)부터 끝방으로 먼저 옮긴다.

왼쪽 시프트, Left Shift
public class Ex27_Array {

    public static void main(String[] args) {

        int[] list = new int[10];

        add(list, 10);
        add(list, 20);
        add(list, 30);
        add(list, 40);
        add(list, 50);
        add(list, 60);
        add(list, 70);
        add(list, 80);

        output(list); //10  20  30  40  50  60  70  80  0  0 

        insert(list, 3, 90);

        output(list); // 10  20  30  90  40  50  60  70  80  0

        delete(list, 5); //왼쪽 시프트 : 5번째 방의 값을 삭제

        output(list); // 10  20  30  90  40  60  70  80  0  0


    }//main
	
    
    //왼쪽 시프트 : 중간의 값을 없애면 오른쪽에서 왼쪽으로 값이 이동.
    private static void delete(int[] list, int index) {

        //list[index] = 111;

        //왼쪽 시프트(왼 -> 오)
        for (int i=index; i<=list.length-2; i++) {
            list[i] = list[i+1]; //오른쪽 방을 왼쪽에 복사
        }

    }

    //오른쪽 시프트
    private static void insert(int[] list, int index, int n) {

        for (int i=list.length-2; i>=index; i--) {

            list[i+1] = list[i]; 

        }

        list[index] = n; 
    }


    //값을 첫번째 빈방부터 채워주는 메소드
    private static void add(int[] list, int n) {

        int index = -1;

        for (int i=0; i<list.length; i++) {
            if (list[i] == 0) {

                index = i; 
                break;
            }
        }

        list[index] = n;
    }

    //값을 추출하는 메서드
    public static void output(int[] list) {

        for (int i=0; i<list.length; i++) {
            System.out.printf("%d  ", list[i]);
        }

        System.out.println();

    }

}

좋은 웹페이지 즐겨찾기