프로그래밍 언어응용-배열, 객체1(캡슐화)
# A_Arr
0. 변수(Varriable)
: 메모리(RAM)에 데이터값을 저장하기 위한 공간
- 변수의 특징
1.값이 바뀔 수 있다.
2.크기가 정해져있다.
3.형변환이 가능하다.
4. stack메모리 -> 기본자료형
5. 코드블록 안에서 선언되고 사용된다.
6. 연산이 가능하다
7. 초기화는 한 번만 가능하다.
8. 자료형이 지정되어있다.
9. 식별자를 붙여서 사용한다.
10. 공간이 하나다. => 하나의 값만 저장이 가능하다.*****
11. 참조형은 주소값을 저장한다.
1. 배열 (Array)
: 하나의 공간에 여러개의 값을 담을 수 있음
단, "같은 자료형의 값들"이여야 함.
=> 배열의 각 인덱스 자리에 실제 값이 담김 *** 인덱스는 "0"부터 시작함.
1) 배열 선언
변수의 경우엔?
자료형 변수식별자;
* 배열 선언법
1) 자료형 배열식별자[];
2) 자료형[] 배열식별자;=> 주로 사용
int a;//변수 선언!
int arr1[]; // 1번 방법으로 int형 배열을 선언!
int[] arr2; // 2번 방법으로 int형 배열을 선언!
2) 배열 할당
이 배열에 몇 개의 값이 들어갈지 배열의 크기를 정해주는 과정
지정한 갯수만큼 값이 들어갈 공간이 만들어짐.
[표현법]
int[] arr; //정수형 배열 arr이라고 읽음
arr = new int[5]; //5칸짜리로 할당이 됨.
int[] arr2 = new int[5]; // 선언과 동시에 할당.
heap에 int를 넣을 수 있는 5개의 공간이 생김
배열은 참조형 => 참조형 : new
int[] arr1;
arr1 = new int[15];
int[] arr2 = new int[5];
3) 배열의 각 인덱스에 값 대입
[표현법]
배열이름[인덱스] = 값;
=> 인덱스는 0부터 시작
int sum = 0;
for (int i = 0; i<arr2.length; i++) {
//System.out.println(arr2[i]);
sum += arr2[i];
System.out.println(sum); //합계도 가능!
}
배열의 가장 큰 장점: 반복문을 사용 가능
4) String형 배열
(1) 배열의 선언과 할당 names 30칸짜리
String[] names = new String[30];
(2) 배열의 인덱스에 값을 입력
names[0] = "강O란";
names[1] = "강O환";
names[2] = "고O진";
names[3] = "김O진";
names[4] = "김O준";
names[5] = "김O헌";
names[6] = "김O혜";
names[7] = "김O수";
names[8] = "박O정";
names[9] = "박O근";
names[10] = "박O림";
names[11] = "박O진";
names[12] = "서O연";
names[13] = "송O리";
names[14] = "신O호";
names[15] = "오O은";
names[16] = "유O호";
names[17] = "이O민";
names[18] = "이O정";
names[19] = "이O준";
names[20] = "이O경";
names[21] = "이O원";
names[22] = "이O솔";
names[23] = "임O혁";
names[24] = "주O경";
names[25] = "주O준";
names[26] = "최O빈";
names[27] = "황O영";
names[28] = "황O필";
names[29] = "임O빈";
names[100] = "이O철"
names[100]문법적으론 맞게 잘 썼지만, 인덱스의 길이 바깥에 있음.
ArrayIndexOutBound : 100 == 배열의 인덱스 범위를 벗어났다
at com.kh.array.A_Array.method2(A_Array.java:166)<=여기서 인덱스 범위 벗어났음을 알려줌
for(int i = 0; i<=names.length/*==정수형 30*/-1; i++) {
//배열의 크기는 30으로 할당했기 떄문에 0부터 names.length는 30 즉 31개가 됨 => 30번째 인덱스를 찾는 오류발생
System.out.printf("출석번호: %d번 %s \n",i+1,names[i]); //문법적으로는 맞게 씀
}
5) 예제1
int형 배열을 선언, 다섯칸을 할당하고 임의의 정수 다섯개를 대입하여 반복문을 이용해 합계 출력하기
int[] arr = new int[5];
arr[0] = 5;
arr[1] = 15;
arr[2] = 439634;
arr[3] = 54545;
arr[4] = 3434;
int sum=0;
for(int i = 0; i<=arr.length-1; i++) {
sum += arr[i];
}
System.out.println(sum);
6) 예제2
- 사용자로부터 입력을 통해 배열에 값을 담기 : 다섯칸 짜리로(정수)
int[] nums = new int[5];
Scanner sc = new Scanner(System.in);
for(int i =0; i<nums.length; i++) {
System.out.println("정수를 입력해주세요.>");
nums[i] = sc.nextInt();
System.out.println("nums라는 배열의" + i + "번째 인덱스에 들어가는 값" + nums[i]);
}
- 해당배열에서 가장 작은값 , 즉 최소값을 구하는 기능을 만들어보자.
int min =nums[0];
for(int i = 0; i<nums.length; i++) {
if(nums[i]<min) {
min=nums[i];
}
}
System.out.println("최소값: " + min);
7) 배열의 한계
int[] iArr/*stack영역*/ = new int[3];//heap영역 0, 1, 2 //배열 변수의 용량이 인덱스(배열변수용량*3)의 용량보다 적어서 들어가지 못하므로 주소값이 대신 들어감
double[] dArr = new double[5]; //0 1 2 3 4
System.out.println(iArr);//주소값 출력
System.out.println("iArr의 크기: " + iArr.length); //주소에 직접 참조하러 감
//배열이름.length: 배열의 길이(크기) => 정수
System.out.println(dArr);
System.out.println("dArr의 크기: " + dArr.length);
- 둘의 인덱스값을 출력할 경우
System.out.println(iArr[0]); //0
System.out.println(dArr[1]); //0.0
=> 자료형의 기본형이 들어가있음
* 자료형
기본자료형:boolean, char, byte, short, int, long, float, double
=>실제 값을 바로 담을 수 있음 : 일반 변수
참조자료형: String, int[], double[], short[] ..
=> 주소값을 담고 있는 변수 : 참조변수(레퍼런스 변수)
String[] KH정보교육원종로점 = new String[3];
KH정보교육원종로점[0] = "A강의장";
KH정보교육원종로점[1] = "B강의장";
KH정보교육원종로점[2] = "C강의장";
System.out.println(KH정보교육원종로점[2]);
참조 자료형에서는 ==(동등 비교 시 ) 주소값을 비교하기 때문에 우리가 원하는 값을 얻을 수 없음!
문자열.equals("비교할문자열")
System.out.println("iArr의 해시코드 값: " + iArr.hashCode() );
System.out.println("dArr의 해시코드 값: " + dArr.hashCode() );
해시코드: 주소값을 십진수의 형태로 나타낸것
int[] iArr2 = new int[3];
System.out.println(iArr == iArr2);// 두 값의 주소값(가리키고 있는 곳)이 같니? //false
System.out.println("iArr2의 해시코드값:"+iArr2.hashCode());
배열의 한계
== 한 번 지정한 배열의 크기는 변경 불가 => 배열의 크기를 변경하고자 한다면? 어쩔 수 없이 배열을 다시 만들어야 함
8) 배열의 래퍼런스 포인트 (가비지 컬렉터)
String [] sArr = new String[3];
sArr[0] = "이";
sArr[1] = "승";
sArr[2] = "철";
for (int i =0; i<=sArr.length-1; i++) {
System.out.println(sArr[i]); //이승철
}
System.out.println("sArr의 해시코드:" + sArr.hashCode()); //1829164700 //변경되는 순간 가르키던 배열변수가 사라짐.둥둥떠다님
sArr = new String[5];
System.out.println("변경된 sArr의 해시코드:" + sArr.hashCode() ); //2018699554 //주소값이 변경됨.sArr이 가르키는 것이 새로운 값이 됨.
가르키는 것 =래퍼런스 포인트
* 래퍼런스 포인트는 0개(가비지 컬럭터가 수거해감), 1개, 여러개 일 수 있음.
연결이 끊어진 기존의 배열은?
Heap영역에 둥둥 떠다니다가 일정시간이 지나면 가비지컬럭터(GC)가 삭제 시켜줌 > 자동 메모리 관리
배열은 항상 고유한 주소값이 부여됨.
기존 배열 이름에 할당만 다시하면?
=> 기존에 참조하고 있던 연결이 끊기고 새로운 배열과 연결됨.
=> 새로운 곳을 참조함.
주소값이 다르면 다른 배열 => 100%(반드시 참)
현재 연결고리를 끊고만 싶다면?
sArr = null
null : 아무것도 존재하지 않음을 의미
참조자료형에는 null이라는 개념이 추가됨. => 주소값이 있는지 없는지(없으면 null)
참조자료형의 기본값 ==> null (주소값이 없다)
9) 배열선언 및 할당과 동시에 초기화(대입)까지 한 번에 끝내는 방법
방법 1.
int[] arr1 = new int[] {1,3,8,5};
방법2.
int[] arr2 = {1,3,8,5}; //가장 많이 씀
System.out.println("arr1 == arr2 : " + (arr1 == arr2));//연산자우선순위 꼭 지키기** 산술연산자=>비교연산자 순이기에 꼭 괄호!
//false 다른 곳에 저장되어있음.
10) 배열의 복사 - 얕은복사
- 얕은 복사(한 가지): 배열의 주소값을 복사
public void method8() {
int[] origin = {1,2,3,4,5};
System.out.println("--원본 배열 출력--");
//1 2 3 4 5
for(int i = 0; i<origin.length; i++) {
System.out.print(origin[i] + " ");
}
int[] copy = origin; //copy에 origin의 주소값을 대입 => copy와 origin은 같은 곳을 가르킴.
System.out.println("\n --복사본 배열 출력");
for(int i = 0; i<copy.length; i++) {
System.out.print(origin[i]+ " ");
}
origin[2] = 99;
System.out.println("\n--원본배열--");
for(int i = 0; i<origin.length; i++) {
System.out.print(origin[i] + " ");//1 2 99 4 5
}
System.out.println("\n--복사본 배열 출력 --");
for(int i = 0; i<copy.length; i++) {
System.out.print(copy[i] + " "); //1 2 99 4 5
}
//분명히 원본 배열만 수정했는데
//복사한 배열도 수정이 이뤄졌다.
// => 두개가 똑같나?
System.out.println("원본배열의 해시코드: " + origin.hashCode());
System.out.println("복사본 배열의 해시코드: " + copy.hashCode());
}
얕은 복사 => 배열의 주소값이 복사되어 원본과 복사본이 같다. (같은 배열을 가리키게 하는 것)
11) 배열의 복사 - 깊은복사
(1)
int[] origin = {1,2,3,4,5};
//1단계 : 기존과 동일한 크기의 새 배열 생성 및 할당
int[] copy = new int[origin.length];
//2단계:
System.out.println("\n --원본배열출력--");
for(int i = 0; i<copy.length; i++) {
copy[i] = origin[i];
System.out.print(origin[i] + " ");
}
origin[2] = 88;
System.out.println("\n --원본배열출력--");
for(int i = 0; i< origin.length; i++) {
System.out.print(origin[i] + " ");
}
System.out.println("\n --복사본배열출력--");
for(int i = 0; i< copy.length; i++) {
System.out.print(copy[i] + " ");
}
System.out.println("\n원본 배열의 해시코드:" + origin.hashCode());
System.out.println("복사본 배열의 해시코드:" + copy.hashCode());
해시코드의 주소값을 100% 맹신할 수 없음 > 다른 곳에 있음에도 같은 주소값을 가질 수도 있음(충돌발생가능성은o)
하지만 주소값이 다르다면 둘은 다른 것./ 주소값 복사 XXXXXXXXX
(2) 새로운 배열 생성후 System 클래스에서의 arraycopy() 호출
몇 번 인덱스부터 몇 개를 어느 위치부터 넣을건지 직접 지정 가능, ()안에 작성!
[표현법]
System.arraycopy(원본배열이름, 원본배열에서 복사를 시작할 인덱스, 복사본배열이름, 복사본배열에서 복사를 시작할 인덱스, 복사할 갯수);
System.arraycopy(origin, 0, copy, 0, 5);
System.arraycopy(origin, 0, copy, 3, 5);//밑에 추가를 하더라도 덮어쓰기 해서 실행됨.
System.out.println("--복사본 출력--");
for(int i =0; i<copy.length; i++) {
System.out.print(copy[i] + " ");
}
System.out.println("\n원본 배열의 해시코드:" + origin.hashCode());
System.out.println("복사본 배열의 해시코드:" + copy.hashCode());
(3) copyOf() 사용
Arrays클래스에서 제공하는 copyOf()호출
[표현법] 복사본 배열 = Arrays.copyOf(원본배열이름, 복사할 갯수)
public void method11() {
int[] origin = {1, 2, 3, 4, 5};
int[] copy = Arrays.copyOf(origin, 10);
System.out.println("--복사본 출력--");
for(int i = 0; i<copy.length; i++ ) {
System.out.print(copy[i]+ " ");
}
System.arraycopy() : 몇 번 인덱스부터 몇 개를 어느위치의 인덱스에 복사할 것인지 모두 지정가능(상세하게)
Arrays.copyOf() : 무조건 원본배열의 0번 인덱스부터 복사진행(내가 지정한 갯수만큼, 인덱스 수 늘리기 가능)
(4) clone()
[표현법] 복사본배열이름 = 원본배열이름.clone;
int[] origin = {1,2,3,4,5};
//얕은복사
//int[] copy = origin;
//깊은 복사
int[] copy = origin.clone();
//인덱스 직접 지정 x, 복사할 갯수 x => 원본배열과 완전히 똑같이 복사
//Arrays.toString(내용을 출력하고 싶은 배열의 식별자)
//toString =>이쁘게 보기
//배열의 요소를 출력해줌
//ex) [1,2,3,4,5]
System.out.println(Arrays.toString(copy));
# Object_chap1
객체지향 프로그래밍: 현실세계에서 독립적인 존재(객체)들 간의 상호작용(행위)을 프로그래밍언어로 구현하는 것
* 구현하고자 하는 프로그램 상의 객체(변수)를 만들기 위해서는 (생성하기 위해서는) 클래스(틀)를 만들어야 함.
=> 클래스라는 틀을 먼저 만들어야 함.
ex) 붕어빵틀과 붕어빵 블루프린트
클래스란? 각 객체들의 정보(정보, 행위)드을 담아내는 그릇 또는 틀
클래스는 어떻게 만드는가?
* 클래스: 객체들의 정보를 담아내는 그릇같은 존재 => VO(Value Object)
<Cat.java> : VO
public class Cat {
//[필드부]
// 접근제한자 자료형 필드이름;
//클래스가 가지고 있는 변수는 필드(멤버변수, 클래스변수)라고 부름.
//접근제한자: 이 필드에 접근할 수 있는 범위를 제한할 수 있음.
// public > protected > default > private
// 클래스 안에서 필드를 선언할 때는 반드시 접근 제한자를 써줄 것임.
public String name;
public String hairColor;
public String footColor;
public String eyescolor;
public int age;
public int weight;
//[생성자부]
//[메소드부]
public void bless() {
age -= 1;
System.out.println("은혜갚기");
}
public void eat(int kg) {
weight += kg;
}
public void jump() {
//100kg되면 멈춤
if (weight <= 10) {
System.out.println("멈춤");
} else {
System.out.println("점프");
weight -= 1; }
}
}
<Run.java>
Cat c1 = new Cat(); //객체를 생성 =>new키워드 사용! 메모리의 heap영역에 할당됨
Cat c2 = new Cat();
- 값 넣기
c1.name = "콩이";
c1.hairColor = "회색";
c1.footColor = "흰색";
c1.eyescolor = "연두색";
c1.age = 7;
c1.weight = 5;
c2.name = "녹차";//stack에서 heap으로 접근 (.)
c2.hairColor = "갈색";
c2.footColor = "갈색";
c2.eyescolor = "검정색";
c2.age = 4;
c2.weight = 10;
- 직접적으로 필드에 접근해서 값 대입
- 직접적으로 필드에 접근해서 값 조회
모두 가능.
하지만, 직접적으로 접근해서 값을 대입하고 조회할 경우 => 보안의 문제가 생길 수 있음
객체지향의 설계 원칙 중 하나가 정보은닉 => 정보은닉을 하기 위한 기술 중 캡슐화(Encapsulation)
1. 캡슐화
캡슐화 과정을 통한 완벽한 클래스 형태를 갖추게 하자
캡슐화하지 않으면 : 외부로부터 직접 접근이 가능하기 때문에 함부로 값이 변질되거나 조회를 막지 못하는 문제가 발생
정보보안의 3요소 : 기밀성(외부로 안보이게), 무결성(외부로부터 결함이 생기지 않고 데이터 그대로), 가용성(사용가능한 상태)
=> 캡슐화 작업: 정보은닉 기술 중 하나
데이터의 "접근 제한"을 원칙으로 하여 외부로부터 직접접근을 막는 방법
단, 대신에 간접적으로나마 처리(값대입, 조회)할 수 있게끔 만들어줘야 함.
=> 캡슐화 작업의 2단계
1. 값을 숨긴다. : public 대신 private으로 접근제한자를 바꿔준다.
2. 간접적으로나마 값을 처리할 수 있는 메소드를 만든다. (getter / setter)
1단계 ) 클래스영역내 가용범위 [필드]
private String name;
private char gender;
private int age;
접근제한자 반환형 메소드식별자(매개변수) {
메소드 호출 시 실행할 코드;
}
접근제한자: 호출할 수 있는 범위를 제한
반환형: 매소드의 결과값의 자료형을 지정해준다. ||void -> 돌려줄 값이 없다.
매개변수: 매소드 호출 시 입력값으로 넣어주는 값을 받아주는 변수. 해당 메소드 실행 중에만 사용이 가능하다. 생략가능
(1) 데이터를 기록 및 수정하는 기능의 메소드 : setter 메소드(필드에 값을 seting)
[규칙]
① setter 메소드는 접근 가능하도록 만들어야하기 때문에 public 접근 제한자를 이용.
② set필드명으로 이름을 짓되 낙타봉표기법(camelCase)을 지키도록 한다.
ex) setName, setAge, setGender
③ 모든 필드에 대해서 반드시 전부 다 작성을 해줘야한다.
- 이름을 기록 및 수정할 수 있는 메소드
public void setName(String name) { //String name을 매개변수라고 함. name은 임의로 지정가능.
this.name = name; //받아온 값을 대입
//this는 heap영역의 주소값을 가지고 있음.
//특정 영역 안에서는 해당 영역 안에 있는 지역변수 우선권이 있음.
//this.를 붙이지 않으면 '매개변수 name = 매개변수 name'으로 인식함.
}
- 나이를 기록 및 수정할 수 있는 메소드
public void setAge(int age) { //보편적으로 매개변수는 필드명과 동일한 네임을 사용함.
if(age<0) {
System.out.println("말도안됨");
}else {this.age = age;}
}
- 성별을 기록 및 수정할 수 있는 메소드
public void setGender(char gender) {
this.gender = gender;
}
(2) 데이터를 반환해주는 기능의 메소드: getter 메소드(값을 get할 수 있는 메소드)
① getter메소드는 접근제한자 public을 사용한다.
② get필드명으로 짓되, 낙타봉표기법(camelCase)를 사용한다.
③ 모든 필드에 대해서 반드시 다 작성해줘야 함.
- 이름을 반환해주는 메소드
public String getName() {
//this.name; //나를 부른 곳으로 이것을 반환해주고 싶다. this는 붙여도되고 안붙여도 되나, 명확한 구분을 위해 붙이는게 좋음.
return this.name; //돌아가는데, this.name을 가져감
//return 결과값 => 결과값을 나를 부른 곳으로 돌려줌.
//메소드의 반환형(void자리)과 반환값의 반환형이 동일한 지 확인해야함.
}
- 나이를 반환해주는 메소드
public int getAge() {
return this.age;
}
- 성별을 반환해주는 메소드
public char getGender() {
return this.gender;
}
- setter와 getter메소드 다 만들어줬으면 캡슐화 끝!