ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TECHIT 앱 스쿨 2기: Android 7일차 (23.05.02)
    [THEC!T] 앱 스쿨2기 : Android 2023. 5. 3. 00:19
    728x90

    자료 출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 내용

     

    시작

    시작은 어제 더 자세히 설명해주시기로 한 오버라이딩과 상속에 대하여 말씀해주셨습니다.

     

    상속이란 클래스를 생성할 때 이미 만들어져 있는 클래스의 메서드 혹은 변수를 가져와서 사용하는 방법입니다.

    상속을 받은 클래스(자식클래스)는 상속을 한 클래스(부모클래스)에서 이미 만들어져 있는 메서드와 변수등을 자기 것처럼 사용을 할 수 있습니다. 

    자바에서는 extends 키워드를 사용하여 상속을 받는 클래스를 만들 수 있습니다. 

     

     

    하기 코드는 상속을 받는 클래스(자식 클래스)를 생성하는 코드 입니다.

    // 부모 클래스를 생성한다.
    class ParentsClass {
    	
    }
    
    // extends를 사용하여 부모클래스에서 상속을 받는 클래스.
    class ChildClass extends ParentsClass{
    	
    }

    하기 코드는 자식 클래스를 이용하여 만든 객체에서 부모 클래스에 있는 변수와 메서드를 사용하는 코드입니다.

    package com.studty.lst;
    
    public class Study2 {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		// 자식 클래스를 이용하여 객체를 생성.
    		ChildClass c1 = new ChildClass();
    		c1.printInfo();
    		
    	}
    
    }
    
    // 부모 클래스를 생성한다.
    class ParentsClass {
    	
    	String me = "부모클래스";
    	
    	public void printInfo() {
    		System.out.print("부모 클래스에서 생성된 메서드\n");
            	System.out.printf("me : %s\n",me);
    	}
    }
    
    // extends를 사용하여 부모클래스에서 상속을 받는 클래스.
    // 아무것도 생성하지 않았음.
    class ChildClass extends ParentsClass{
    
    }

    상기 코드의 출력 결과

    부모 클래스에서 생성된 메서드
    me : 부모클래스

     

    오버라이딩은 부모클래스에서 정의된 메서드 혹은 변수를 자식 클래스에서 동일한 이름의 메서드 및 변수를 작성하여, 다른 기능을 수행하게 만들거나 다른 값을 가지게 만드는 것을 말합니다. 

    상기 코드를 수정하여 작성해 보겠습니다.

    package com.studty.lst;
    
    public class Study2 {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		// 자식 클래스를 이용하여 객체를 생성.
    		ChildClass c1 = new ChildClass();
    		c1.printInfo();
    		
    	}
    
    }
    
    // 부모 클래스를 생성한다.
    class ParentsClass {
    	
    	String me = "부모클래스";
    	
    	public void printInfo() {
    		System.out.print("부모 클래스에서 생성된 메서드");
            	System.out.printf("me : %s\n",me);
    	}
    }
    
    // extends를 사용하여 부모클래스에서 상속을 받는 클래스.
    // 아무것도 생성하지 않았음.
    class ChildClass extends ParentsClass{
    	
    	// 자식 클래스에서 부모클래스에 있는 메서드와 상수를 수정한다.
    	// -> 오버라이딩
    	
    	// 변수 변경
    	String me = "자식클래스";
    	// 메서드 변경
    	public void printInfo() {
    		System.out.print("자식 클래스에서 생성된 메서드\n");
    		System.out.printf("me : %s\n",me);
    	}
    }

    상기 코드의 출력 결과 입니다. 

    자식 클래스에서 생성된 메서드
    me : 자식클래스

    오버라이딩으로 인하여 기존 코드와 출력 결과가 달라짐을 확인할 수 있습니다.

    즉, 작동하는 기능이 변했다~!

     

    그러면 부모클래스를 사용하여 객체를 생성한 후에 메서드나 변수를 확인하면 어떻게 되어있을까요?

    자식클래스에  메서드나 변수를 변경하였으니 부모클래스에 있는  메서드나 변수도 변경 되었을까요? 아니면 부모 클래스에 있는 메서드나 변수는 변하지 않았을까요?

     

    확인해보겠습니다.

    package com.studty.lst;
    
    public class Study2 {
    
    	public void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		// 자식 클래스를 이용하여 객체를 생성.
    		ChildClass c1 = new ChildClass();
    		c1.printInfo();
    		
    		// 부모 클래스를 이용하여 객체를 생성
    		ParentsClass p1 = new ParentsClass();
    		p1.printInfo();
    		
    	}
    
    }
    
    // 부모 클래스를 생성한다.
    class ParentsClass {
    	
    	String me = "부모클래스";
    	
    	public void printInfo() {
    		System.out.print("부모 클래스에서 생성된 메서드");
    	}
    }
    
    // extends를 사용하여 부모클래스에서 상속을 받는 클래스.
    // 아무것도 생성하지 않았음.
    class ChildClass extends ParentsClass{
    	
    	// 자식 클래스에서 부모클래스에 있는 메서드와 상수를 수정한다.
    	// -> 오버라이딩
    	
    	// 변수 변경
    	String me = "자식클래스";
    	// 메서드 변경
    	public void printInfo() {
    		System.out.print("자식 클래스에서 생성된 메서드\n");
    		System.out.printf("me : %s\n",me);
    	}
    }
    자식 클래스에서 생성된 메서드
    me : 자식클래스
    부모 클래스에서 생성된 메서드
    me : 부모클래스

    결론은 부모 클래스에서 변한건 없습니다.

     

    즉, 오버라이딩이란 자식클래스에서 부모클래스에 있는 메서드나 변수를 본 따서 자신에게 필요한 대로 변경하는 것이라고 생각합니다.  

     

    오버라이딩을 했지만 부모클래스에 있는 메서드나 변수를 사용하고 싶을 때는 어떻게 해야 할까요?(유행은 돌고 돈다??)

    이때는 super 이라는 키워드를 사용하여 자식 클래스에서 부모 클래스에 정의된 메서드나 변수에 접근 할 수 있습니다.

    (부모님은 super man...?)

     

    package com.studty.lst;
    
    public class Study2 {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		// 자식 클래스를 이용하여 객체를 생성.
    		ChildClass c1 = new ChildClass();
    		c1.printInfo();
    		
    	}
    
    }
    
    // 부모 클래스를 생성한다.
    class ParentsClass {
    	
    	String me = "부모클래스";
    	
    	public void printInfo() {
    		System.out.print("부모 클래스에서 생성된 메서드\n");
    		System.out.printf("me : %s\n",me);
    	}
    }
    
    // extends를 사용하여 부모클래스에서 상속을 받는 클래스.
    // 아무것도 생성하지 않았음.
    class ChildClass extends ParentsClass{
    	
    	// 자식 클래스에서 부모클래스에 있는 메서드와 상수를 수정한다.
    	// -> 오버라이딩
    	
    	// 변수 변경
    	String me = "자식클래스";
    	// 메서드 변경
    	public void printInfo() {
    		System.out.print("자식 클래스에서 생성된 메서드\n");
    		System.out.printf("me : %s\n",me);
    		System.out.println();
    		
    		System.out.print("자식 클래스에서 부모 클래스에 선언된 메서드 호출~! \n");
    		super.printInfo();
    		System.out.println();
    		
    		System.out.print("자식 클래스에서 부모 클래스에 선언된 변수 호출~! \n");
    		System.out.printf("me : %s\n",super.me);
    	}
    }

    상기 코드의 출력 결과 입니다.

    자식 클래스에서 생성된 메서드
    me : 자식클래스
    
    자식 클래스에서 부모 클래스에 선언된 메서드 호출~! 
    부모 클래스에서 생성된 메서드
    me : 부모클래스
    
    자식 클래스에서 부모 클래스에 선언된 변수 호출~! 
    me : 부모클래스

     

    상속에 대한 설명과 오버라이딩에 대한 설명이 끝난 후 강사님께서 조원들끼리 코드를 작성해보라고 하시며, 문제를 내주셨습니다.

    내주신 문제는 하기와 같습니다.

    * 최종 문제는 조금 변경 되었으나, 처음에 내주신 문제는 하기와 같습니다.

    동물원
    모든 클래스는 com.test.zoo 라는 패키지에 만들어준다.
    동물들의 특징은 다음과 같다.
    코끼리
    다리 : 4개, 코 : 길다, 몸 : 크다, 식사방법 : 코를 이용해 먹는다.
    사막여우
    다리 : 4개, 코 : 짧다, 몸 : 작다, 식사방법 : 손을 이용해 먹는다.
    캥거루
    다리 : 2개, 코 : 짧다, 몸 : 크다, 식사방법 : 나뭇잎을 뜯어 먹는다.
    다리, 코, 몸은 변수로 정의한다.
    식사 방법은 변수로 정의한다.  ************** 해당부분 추후 바뀜.
    각 동물은 자신의 정보를 출력하는 메서드를 가지고 있다.

    출력 예시
    동물의 종류를 입력해주세요
    1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 : 1
    동물의 이름을 입력해주세요 : 맘모스
    위의 입력을 0을 입력할 때 까지 반복한다....
    0을 눌러 입력이 끝나면 모든 동물의 정보를 출력한다.
    타입 : 코끼리
    이름 : 맘모스
    다리 : 4개
    코 : 길다
    몸 : 크다
    식사방법 : 손을 이용해 먹는다.
    .......

     

    처음에는 문제를 보고 들었던 생각은 일단은 지금까지 상속을 배웠으니 상속을 이용하여 동물들의 클래스를 만들면 되겠구나라고 생각이 들었었습니다.

    그리고 조원들과 같이 상의를 하면서 처음에는 주석을 이용하여 어떠한 기능을 작성할지 정하였었습니다.

    동물원 객체를 생성한다, 동물의 타입을 입력받는다. 0인지 확인한다... 등등 그리고 해당 기능에 맞는 코드를 작성하였습니다. 

    시작은 문제 없이 화면 공유를 통하여 코드를 작성 하였었습니다.

    상속에 관련하여 클래스 설계하는 것은 문제를 받기 전에 상속에 관하여 설명을 들었던지라 큰 문제는 없었습니다.

    그러다가  코드를 작성하는데 벽(?)을 만났던 부분이 0을 입력할 때 까지 반복한다..... 였습니다.

    문제를 보면 배열이라는 단어가 전혀 없습니다. 그래서 그런가 조원들끼리 이야기를 할때 while문 이야기는 나왔지만 저장을 어떻게 해야되냐...라는 벽을 만났었고, 여기에서 문제만 보다가 시간을 많이 허비 했던 것 같습니다.

    그리고 점심시간이 되었습니다.....

    하지만 제 나쁜 버릇이라면 나쁜 버릇이고 좋은 버릇이라면 좋은 버릇인데, 제가 꽂히면 계속 보는 버릇이 있습니다.

    그러다가 "문제 이거 그냥 배열써서 만들어 보자" 라는 생각이 들었고, 점심시간이라 조원분들도 식사를 하러 가셔서 그냥 

    생각나는 대로 코드를 작성하여 출력 예시와 똑같이 나오도록 작성은 하였었습니다. 이 때 개인적인 성취감은 있었지만,

    반쪽짜리 성취감이라고 느꼈었습니다. 왜냐하면 조원끼리 같이 상의하여 코드를 완성한 것이 아니였기 때문입니다.

    정말 현업에 계신 개발자 분들이 소통을 강조하는 이유를 알 것만 같았습니다.

    어떻게 보자면 간단한 코드도 소통을 통하여 작성을 못하는데....나중에 코드가 매우 많이 나올 프로젝트 같은 것들은 어떻게 해야할지 걱정도 되었습니다.

     

    하기는 제가 작성한 코드입니다.

    package com.test.zoo.study;
    
    import java.util.Scanner;
    
    //예시
    //동물의 종류를 입력해주세요
    //1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 : 1
    //동물의 이름을 입력해주세요 : 맘모스
    //위의 입력을 0을 입력할 때 까지 반복한다....
    //0을 눌러 입력이 끝나면 모든 동물의 정보를 출력한다.
    //타입 : 코끼리
    //이름 : 맘모스
    //다리 : 4개
    //코 : 길다
    //몸 : 크다
    //식사방법 : 손을 이용해 먹는다.
    //.......
    
    public class MainClass {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		// 동물원
    		// 모든 클래스는 com.test.zoo 라는 패키지에 만들어 준다
    		// 동물들의 특징은 다음과 같다.
    		// 코끼리
    		// 다리 : 4개, 코 : 길다, 몸 : 크다, 식사방법 : 코를 이용해 먹는다
    		// 사막여우
    		// 다리 : 4개, 코 : 짧다, 몸 : 작다, 식사방법 : 손을 이용해 먹는다
    		// 캥거루
    		// 다리 : 2개, 코 : 짧다, 몸 : 크다, 식사방법 : 나뭇잎을 뜯어 먹는다.
    		// 다리, 코, 몸, 식사방법은 변수로 정의한다.
    		// 각 동물은 자신의 정보를 출력하는 메서드를 가지고 있다.
    		
    		// 예시
    		// 동물의 종류를 입력해주세요
    		// 1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 : 1
    		// 동물의 이름을 입력해주세요 : 맘모스
    		// 위의 입력을 0을 입력할 때 까지 반복한다....
    		// 0을 눌러 입력이 끝나면 모든 동물의 정보를 출력한다.
    		// 타입 : 코끼리
    		// 이름 : 맘모스
    		// 다리 : 4개
    		// 코 : 길다
    		// 몸 : 크다
    		// 식사방법 : 손을 이용해 먹는다.
    		// .............
    		
    		Scanner scan = new Scanner(System.in);
    		// 객체를 저장할 배열 임시크기 100 
    		Zoo [] animal = new Zoo[100];
    		
    		// 하기 내용을 반복한다.
    		
    		for(int i = 0; i < 100; i++) {
    			// 질문 출력
    			System.out.println("동물의 종류를 입력해주세요. ");
    			System.out.println("1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 ");
    			// 종류 입력 받음
    			int inputkind = scan.nextInt();
    			if(inputkind == 0)
    				break;
    			else {
    				System.out.println("동물의 이름을 입력해주세요 ");
    				// 이름 입력받음
    				String inputname = scan.next();
    				if(inputkind == 1) {
    					animal[i] = new Elephant();
    					animal[i].name = inputname;
    				} else if(inputkind == 2) {
    					animal[i] = new DesertFox();
    					animal[i].name = inputname;
    				} else { // 3
    					animal[i] = new Kangaroo();
    					animal[i].name = inputname;
    				}
    			}
    		}
    		
    		for(int i = 0; i < animal.length; i++) {
    			if(animal[i] != null) {
    				animal[i].printInfo();
    				System.out.println();
    			}
    			else break;
    		}
    		
    		scan.close();
    	}
    }
    
    class Zoo {
    	String kind; // 종류
    	String name; // 이름
    	int leg; // 다리개수
    	String nose; // 코
    	String bodySize; // 몸크기
    	String howEat; // 식사 방법
    
    	//출력을 담당하는 메서드 -> 상속예정
    	public void printInfo(){
    		System.out.printf("타입 : %s\n", kind);
    		System.out.printf("이름 : %s\n", name);
    		System.out.printf("다리 : %d\n", leg);
    		System.out.printf("코 : %s\n", nose);
    		System.out.printf("몸 : %s\n", bodySize);
    		System.out.printf("식사방법 : %s\n", howEat);
    	}
    }
    
    class Elephant extends Zoo{
    	public Elephant() {
    		this.kind = "코끼리"; // 종류
    		this.name = "이름없음"; // 이름
    		this.leg = 4; // 다리개수
    		this.nose = "길다"; // 코
    		this.bodySize = "크다"; // 몸크기
    		this.howEat = "코를 이용해 먹는다.";// 식사 방법
    	}
    }
    
    class DesertFox extends Zoo{
    	public DesertFox() {
    		this.kind = "사막여우"; // 종류
    		this.name = "이름없음"; // 이름
    		this.leg = 4; // 다리개수
    		this.nose = "짧다"; // 코
    		this.bodySize = "작다"; // 몸크기
    		this.howEat = "손을 이용해 먹는다.";// 식사 방법
    	}
    }
    
    class Kangaroo extends Zoo{
    	public Kangaroo() {
    		this.kind = "캥거루"; // 종류
    		this.name = "이름없음"; // 이름
    		this.leg = 2; // 다리개수
    		this.nose = "짧다"; // 코
    		this.bodySize = "크다"; // 몸크기
    		this.howEat = "나뭇잎을 뜯어 먹는다.";// 식사 방법
    	}
    }

    출력 결과 입니다.

    동물의 종류를 입력해주세요. 
    1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 
    1
    동물의 이름을 입력해주세요 
    zhzhzhz
    동물의 종류를 입력해주세요. 
    1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 
    2
    동물의 이름을 입력해주세요 
    tktktk
    동물의 종류를 입력해주세요. 
    1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 
    3
    동물의 이름을 입력해주세요 
    zodzodzod
    동물의 종류를 입력해주세요. 
    1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 
    0
    타입 : 코끼리
    이름 : zhzhzhz
    다리 : 4
    코 : 길다
    몸 : 크다
    식사방법 : 코를 이용해 먹는다.
    
    타입 : 사막여우
    이름 : tktktk
    다리 : 4
    코 : 짧다
    몸 : 작다
    식사방법 : 손을 이용해 먹는다.
    
    타입 : 캥거루
    이름 : zodzodzod
    다리 : 2
    코 : 짧다
    몸 : 크다
    식사방법 : 나뭇잎을 뜯어 먹는다.

    지금 생각해보니 이렇게 작성하면 안됬던게 문제 조건에

    모든 클래스는 com.test.zoo 라는 패키지에 만들어 준다

     라는 문구가 있기에 새로 만들어서 했어야 됬을 거 같은데... 혼자 막하다보니 상기와 같은 코드가 나왔습니다.

     

    하기는 강사님께서 설명하면서 작성해주신 코드 입니다.

    그리고 문제를 설명해주시면서 식사방법을 변수로 관리 하는 것이 아닌 메서드로 관리하는 것으로 문제 조건을 변경하여 작성해주셨습니다.

     

    시작은 사진과 같이 zoo패기지에 동물 관련 클래스를 만드셨습니다.

     

     MainClass 입니다.

    package com.test.main;
    
    import java.util.Scanner;
    
    import com.test.zoo.AnimalClass;
    import com.test.zoo.DesertFoxClass;
    import com.test.zoo.ElephantClass;
    import com.test.zoo.KangarooClass;
    import com.test.zoo.ZooClass;
    
    public class MainClass {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		// 동물원
    		// 모든 클래스는 com.test.zoo 라는 패키지에 만들어준다.
    		// 동물들의 특징은 다음과 같다.
    		// 코끼리
    		// 다리 : 4개, 코 : 길다, 몸 : 크다, 식사방법 : 코를 이용해 먹는다.
    		// 사막여우
    		// 다리 : 4개, 코 : 짧다, 몸 : 작다, 식사방법 : 손을 이용해 먹는다.
    		// 캥거루
    		// 다리 : 2개, 코 : 짧다, 몸 : 크다, 식사방법 : 나뭇잎을 뜯어 먹는다.
    		// 다리, 코, 몸은 변수로 정의한다.
    		// 식사 방법은 메서드로 정의한다.
    		// 각 동물은 자신의 정보를 출력하는 메서드를 가지고 있다.
    		
    		// 예시
    		// 동물의 종류를 입력해주세요
    		// 1. 코끼리, 2. 사막여우, 3. 캥거루, 0. 입력끝 : 1
    		// 동물의 이름을 입력해주세요 : 맘모스
    		// 위의 입력을 0을 입력할 때 까지 반복한다....
    		// 0을 눌러 입력이 끝나면 모든 동물의 정보를 출력한다.
    		// 타입 : 코끼리
    		// 이름 : 맘모스
    		// 다리 : 4개
    		// 코 : 길다
    		// 몸 : 크다
    		// 식사방법 : 손을 이용해 먹는다.
    		// .......
    		
    		Scanner scanner = new Scanner(System.in);
    		
    		// 동물원 객체를 생성한다.
    		ZooClass zooClass = new ZooClass(scanner);
    		
    		// 입력받은 동물의 타입 번호
    		int typeNumber = 0;
    		
    		// 입력 받는 동물 번호가 0이 아닌 동안 반복한다.
    		do {
    			// 동물 타입 번호를 입력받는다.
    			System.out.println("동물의 타입을 입력해주세요");
    			System.out.print("1.코끼리, 2.사막여우, 3.캥거루, 0.종료 : ");
    			typeNumber = scanner.nextInt();
    			
    			// 동물 타입 번호가 0이 아니라면...
    			if(typeNumber != 0) {
    			
    				// 동물의 이름을 입력받는다.
    				System.out.print("동물의 이름을 입력해주세요 : ");
    				String name = scanner.next();
    				// 동물 객체를 생성한다.
    				AnimalClass animal = null;
    				
    				switch(typeNumber) {
    				case 1 :
    					animal = new ElephantClass(name);
    					break;
    				case 2 :
    					animal = new DesertFoxClass(name);
    					break;
    				case 3 :
    					animal = new KangarooClass(name);
    					break;
    				}
    			
    				// 동물 객체를 담아준다.
    				zooClass.addAnimal(animal);
    			}
    		} while(typeNumber != 0);
    		
    		// 입력한 동물들의 정보를 출력한다.
    		zooClass.printAnimalInfo();
    		
    		
    		scanner.close();
    	}
    }

    ZooClass 입니다.

    package com.test.zoo;
    import java.util.Scanner;
    
    public class ZooClass {
    	
    	Scanner scanner;
    	
    	// 동물객체들을 담을 배열
    	public AnimalClass [] animalArray;
    	// 동물의 수
    	public int animalCount;
    	
    	public ZooClass(Scanner scanner) {
    		this.scanner = scanner;
    		animalArray = new AnimalClass [1000];
    		animalCount = 0;
    	}
    	
    	 // 동물을 추가하는 메서드
        public void addAnimal(AnimalClass animal) {
            animalArray[animalCount] = animal;
            animalCount++;
        }
        
        // 입력한 동물들의 정보를 출력하는 메서드
        public void printAnimalInfo() {
        	// 동물의 수 만큼 반복한다.
        	for(int i =0; i < animalCount; i++) {
        		 AnimalClass animal = animalArray[i];
                 animal.printInfo();
                 animal.howEat();
                 System.out.println();
        	}
        }
    	
    }

     

    AnimalClass 입니다.

    package com.test.zoo;
    
    public class AnimalClass {
    	// 다리
    	int numberLegs;
    	// 코의 길이
    	String lengthNose;
    	// 몸의 크기
    	String bodySize;
    	// 이름
    	String name;
    	// 동물 타입
    	String type;
    	// 식사 방법
    	public void howEat() {
    		
    	}
    	
    	// 출력 
    	public void printInfo() {
    		System.out.printf("동물 타입 : %s\n", type);
    		System.out.printf("이름 : %s\n", name);
    		System.out.printf("다리 개수 : %d\n", numberLegs);
    		System.out.printf("코의 길이 : %s\n", lengthNose);
    		System.out.printf("몸의 크기 : %s\n", bodySize);
    	}
    }

    DesertFoxClass 입니다.

    package com.test.zoo;
    
    public class DesertFoxClass extends AnimalClass{
    
    	@Override
    	public void howEat() {
    		System.out.println("손을 이용해 먹습니다.");
    	}
    	
    	public DesertFoxClass(String name) {
    		this.type = "사막여우";
    		this.name = name;
    		this.numberLegs = 4;
    		this.lengthNose = "짧다";
    		this.bodySize = "작다";
    	}
    	
    }

    ElephantClass 입니다.

    package com.test.zoo;
    
    public class ElephantClass extends AnimalClass{
    	
    	public ElephantClass(String name) {
    		this.type = "코끼리";
    		this.name = name;
    		this.numberLegs = 4;
    		this.lengthNose = "길다";
    		this.bodySize = "크다";
    	}
    
    	@Override
    	public void howEat() {
    		System.out.println("코를 이용해 먹습니다");
    	}
    }

    KangarooClass 입니다.

    package com.test.zoo;
    
    
    public class KangarooClass extends AnimalClass{
    
    	public KangarooClass(String name) {
    		this.type = "캥거루";
    		this.name = name;
    		this.numberLegs = 2;
    		this.lengthNose = "짧다";
    		this.bodySize = "크다";
    	}
    	
    	@Override
    	public void howEat() {
    		System.out.println("나뭇잎을 뜯어 먹습니다.");
    	}
    	
    }

     

    강사님의 코드를 보면서 느낀 점은 패키지는 이렇게 쓰는 것이구나 라고 다시금 생각하게 되었습니다.

    지금이야 하나의 파일 안에 클래스를 여러개 생성한다고 하더라도 관리하기 쉽지만 추후 클래스가 엄청 많아질 경우 관리하기 어려울 뿐더러 가독성 또한 매우 떨어질 것이라고 생각이 들어 패키지를 통한 클래스 파일 관리를 습관화 해야 겠다고 다시금 생각하게 되었습니다.

     

    그리고 접근 제한자에 대해서 설명해 주셨습니다.

    접근 제한자에 대해 설명을 시작하시면서 접근 제한자는 변수에 대한 직접 접근을 차단 하여 데이터 무결성을 위해 사용한다고 말씀하셨습니다. (해당 문구는 다를 수 있습니다.)

     

    데이터 무결성이란 데이터가 정확하고 일관성이 있어야 한다는 원칙 입니다. 

    즉, 전화번호라면 010-1234-1234 라는 형태라던가, 이메일일 경우 test@naver.com 같은 형태를 말합니다.

     

    다시 접근제한자에 대해 설명하자면

     

    default 는 앞에 아무것도 적지 않았을 경우를 뜻함.

     

    클래스는 public , default 를 가지고 있다.

     

    생성자는 public, default, protected, private 를 가지고 있다.

     

    맴버 변수는 public, default, protected, private 를 가지고 있다.

     

    멤버 메서드는 public, default, protected, private 를 가지고 있다.

     

    지역변수는 접근 제한자가 불가하다. 

    ex) for문에서 사용하는 i 같은 존재

     

    그리고 자바 파일에 여러 개의 클래스를 만들 경우 파일 명으로는 public 이 있는 클래스의 이름으로 정해지며,

    public 는 단 1개의 클래스에만 붙힐 수 있습니다.

     

    접근 제한자의 조건은 다음과 같습니다.

     

    public : 조건 없이 접근 가능
    protected : 패키지가 다르고 참조하는 경우에만 접근이 불가능.
    default : 패키지가 다르면 접근이 불가능.
    private : 어떠한 상황에서도 접근 불가능.

     

    그리고 코드 작성을 통해 예시를 설명해주셨었습니다.

    아래 사진과 같이 패키지 및 클래스를 구성하였습니다.

    하기 코드들의 순서는 main패키지에 있는 파일들부터 pkg1에 있는 파일들 순 입니다.

    사진과 동일 순서입니다.

    MainClass 에서 붉은색 밑줄이 보여야 하지만 여기서는 보이지 않아 주석으로 "//오류" 라고 기재 하였습니다.

     

    MainClass 입니다.

    package com.test.main;
    
    import com.test.pkg1.TestClass3;
    import com.test.pkg1.TestClass6;
    import com.test.pkg1.TestClass8;
    
    public class MainClass {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		// 접근 제한자
    		// 외부에서의 접근 허용 여부를 설정하기 위해 사용한다.
    		// 데이터의 무결성이나 공개하고 싶지 않은 메서드 등을 만들 때 사용한다.
    		// public : 제한 없음
    		// private : 접근 불가
    		// protected : 패키지가 같으면 제한이 없고 패키지가 다를 경우 상속관계에서만
    		// 접근이 가능하다.
    		// default : 같은 패키지 내부에서만 접근이 가능하다.
    		
    		// 같은 패키지에 있는 public 클래스의 객체를 생성한다.
    		TestClass1 t1 = new TestClass1();
    		// 같은 패키지에 있는 default 클래스의 객체를 생성한다.
    		TestClass2 t2 = new TestClass2();
    		// 다른 패키지에 있는 public 클래스의 객체를 생성한다.
    		TestClass3 t3 = new TestClass3();
    		// 다른 패키지에 있는 default 클래스의 객체를 생성한다.
    		TestClass4 t4 = new TestClass4(); // 오류
    		
    		// 같은 패키지에 있는 객체를 생성한다(생성자 접근제한자 테스트)
    		// public
    		TestClass5 t50 = new TestClass5();
    		// default
    		TestClass5 t51 = new TestClass5(10);
    		// protected
    		TestClass5 t52 = new TestClass5(10, 20);
    		// private
    		TestClass5 t53 = new TestClass5(10, 20, 30); // 오류
    		
    		// 다른 패키지의 클래스를 통해 객체를 생성한다(생성자 테스트)
    		// public
    		TestClass6 t60 = new TestClass6();
    		// default
    		TestClass6 t61 = new TestClass6(10); // 오류
    		// protected
    		TestClass6 t62 = new TestClass6(10, 20); // 오류
    		// private
    		TestClass6 t63 = new TestClass6(10, 20, 30); // 오류
    		
    		// 같은 패키지의 클래스의 객체를 생성한다(변수, 메서드 테스트)
    		TestClass7 t7 = new TestClass7();
    		// public
    		System.out.printf("t7.memberA : %d\n", t7.memberA);
    		// default
    		System.out.printf("t7.memberB : %d\n", t7.memberB);
    		// protected
    		System.out.printf("t7.memberC : %d\n", t7.memberC);
    		// private
    		System.out.printf("t7.memberD : %d\n", t7.memberD); // 오류
    		
    		// public
    		t7.method1();
    		// default
    		t7.method2();
    		// protected
    		t7.method3();
    		// private
    		t7.method4(); // 오류
    		
    		// 다른 패키지의 클래스를 통해 객체를 생성한다(변수, 메서드 테스트)
    		TestClass8 t8 = new TestClass8();
    		// public
    		System.out.printf("t8.memberA : %d\n", t8.memberA);
    		// default
    		System.out.printf("t8.memberB : %d\n", t8.memberB); // 오류
    		// protected
    		System.out.printf("t8.memberC : %d\n", t8.memberC); // 오류
    		// private
    		System.out.printf("t8.memberD : %d\n", t8.memberD); // 오류
    		
    		// public
    		t8.method1();
    		// default
    		t8.method2(); // 오류
    		// protected
    		t8.method3(); // 오류
    		// private
    		t8.method4(); // 오류
    	}
    }
    
    // 같은 패키지에 있는 public 클래스를 상속받은 클래스
    class SubClass1 extends TestClass1{
    	
    }
    // 같은 패키지에 있는 default 클래스를 상속받은 클래스
    class SubClass2 extends TestClass2{
    	
    }
    // 다른 패키지에 있는 public 클래스를 상속받은 클래스
    class SubClass3 extends TestClass3{
    	
    }
    // 다른 패키지에 있는 default 클래스를 상속
    class SubClass4 extends TestClass4{ // 오류
    	
    }
    // 같든 패키지에 있는 클래스를 상속 받는다.(접근제한자 테스트)
    class SubClass5 extends TestClass5{
    	// 기본적으로 부모클래스의 생성자중 매개변수가 없는 생성자를
    	// 호출한다.
    	// TestClass5의 기본생성자가 public 이므로 문제가 발생하지 않는다.
    	public SubClass5() {
    		// 부모의 public 생성자 호출
    		super();
    	}
    	public SubClass5(int a1) {
    		// 부모의 default 생성자 호출
    		super(10);
    	}
    	public SubClass5(int a1, int a2) {
    		// 부모의 protected 생성자 호출
    		super(10, 20);
    	}
    	public SubClass5(int a1, int a2, int a3) {
    		// 부모의 private 생성자 호출
    		super(10, 20, 30); // 오류
    	}
    }
    // 다른 패키지의 클래스를 상속받는다(생성자 테스트)
    class SubClass6 extends TestClass6{
    	// public
    	public SubClass6() {
    		super();
    	}
    	// default
    	public SubClass6(int a1) {
    		super(10); // 오류
    	}
    	// protected
    	public SubClass6(int a1, int a2) {
    		super(10, 20);
    	}
    	// private
    	public SubClass6(int a1, int a2, int a3) { 
    		super(10, 20, 30); // 오류
    	}
    }
    
    // 같은 패키지의 클래스를 상속 받은 클래스(변수, 메서드 테스트)
    class SubCclass7 extends TestClass7{
    	
    	public void testMethod() {
    		// 변수
    		// public
    		System.out.printf("memberA : %d\n", memberA);
    		// default
    		System.out.printf("memberB : %d\n", memberB);
    		// protected
    		System.out.printf("memberC : %d\n", memberC);
    		// private
    		System.out.printf("memberD : %d\n", memberD); // 오류
    		
    		// 메서드
    		// public
    		method1();
    		// default
    		method2();
    		// protected
    		method3();
    		// private
    		method4(); // 오류
    	}
    }
    
    // 다른 패키지의 클래스를 상속 받은 클래스(변수, 메서드 테스트)
    class SubClass8 extends TestClass8{
    	
    	public void testMethod() {
    		// 변수
    		// public
    		System.out.printf("memberA : %d\n", memberA);
    		// default
    		System.out.printf("memberB : %d\n", memberB); // 오류
    		// protected
    		System.out.printf("memberC : %d\n", memberC);
    		// private
    		System.out.printf("memberD : %d\n", memberD); // 오류
    		// 메서드
    		// public
    		method1();
    		// default
    		method2(); // 오류
    		// protected
    		method3();
    		// private
    		method4(); // 오류
    	}
    }

    TestClass1 입니다.

    package com.test.main;
    
    //클래스의 접근 제한자
    //클래스는 default와 public을 사용할 수 있다.
    //패키지가 다를 경우 클래스를 사용할 수 있는지를 결정한다.
    //public class는 java 파일 당 하나만 작성할 수 있다.
    
    // public class : 다른 패키지에서 사용 가능
    // Java 파일의 이름은 public 클래스의 이름이어야 한다.
    public class TestClass1 {
    
    }
    
    // default class : 다른 패키지에서 사용 불가
    class TestClass2 {
    	
    }

     

    TestClass5 입니다.

    package com.test.main;
    
    
    public class TestClass5 {
    	// public 생성자
    	public TestClass5() {
    		
    	}
    	// default 생성자
    	TestClass5(int a1){
    		
    	}
    	// protected 생성자
    	protected TestClass5(int a1, int a2) {
    		
    	}
    	// private 생성자
    	private TestClass5(int a1, int a2, int a3) {
    		
    	}
    }

     

    TestClass7 입니다.

    package com.test.main;
    
    public class TestClass7 {
    	// 멤버변수
    	public int memberA = 100;
    	int memberB = 200;
    	protected int memberC = 300;
    	private int memberD = 400;
    	
    	// 멤버 메서드
    	public void method1() {
    		System.out.println("public method");
    	}
    	void method2() {
    		System.out.println("default method");
    	}
    	protected void method3() {
    		System.out.println("protected method");
    	}
    	private void method4() {
    		System.out.println("private method");
    	}
    }

     

    -----------------------------------------------------------------------------------------------------------------------------------------------------------------

    여기서 부터는 다른 패키지 입니다.

    pkg1 

     

    TestClass3 입니다.

    package com.test.pkg1;
    
    // com.test.main과 다른 패키지에 있는 public 클래스
    public class TestClass3 {
    
    }
    
    // com.test.main과 다른 패키지에 있는 default 클래스
    class TestClass4{
    	
    }

     

    TestClass6 입니다.

    package com.test.pkg1;
    
    public class TestClass6 {
    	// public 생성자
    	public TestClass6() {
    		
    	}
    	// default 생성자
    	TestClass6(int a1) {
    		
    	}
    	// protected 생성자
    	protected TestClass6(int a1, int a2) {
    		
    	}
    	// private 생성자
    	private TestClass6(int a1, int a2, int a3) {
    		
    	}
    }

     

    TestClass8 입니다. 

    package com.test.pkg1;
    
    public class TestClass8 {
    	// 멤버변수
    	public int memberA = 100;
    	int memberB = 200;
    	protected int memberC = 300;
    	private int memberD = 400;
    	
    	// 멤버 메서드
    	public void method1() {
    		System.out.println("public method");
    	}
    	void method2() {
    		System.out.println("default method");
    	}
    	protected void method3() {
    		System.out.println("protected method");
    	}
    	private void method4() {
    		System.out.println("private method");
    	}
    }

     

    접근 제한자에 대하여 예제를 통하여 확인을 마치고

    마지막으로 캡슐화에 대해서 설명해주셨습니다.

     

    캡슐화

    변수에 대한 직접 접근을 막음으로써  데이터의무결성을 보장할 수 잇도록 개발하는 방식을 의미합니다.

    변수의 직접 접근을 막기 위해 private 접근 제한자를 붙혀줍니다.

    변수에 값을 저장하는 것을 객체 생성 시 딱 한 번만 허용하겠다면, 생성자를 통해 할 수 있도록 제공합니다.

    만약 변수에  값을 저장하는 것을 원하는 만큼 할 수 있도록 하게 해주겠다면,  setter 를 만들어 제공합니다.

     

    변수의 값을 가져다 사용할 수 있는 것을 할 수 있도록 하게 해주겠다면 getter 를 만들어 제공합니다.

     

    settergetter 의 이름을 짓는 것은 국룰를 넘어서 전세계룰이라고 생각하시면 됩니다.

    setter의 이름짓는 규칙 : set변수명


    getter의 이름짓는 규칙 : get변수명,  만약 boolean형 일 경우 is변수명

     

    하기는 캡슐화에 대한 예제 입니다.

    package com.test.main;
    
    public class MainClass {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
            
    		TestClass1 t1 = new TestClass1(200);
    		t1.printValue();
    		
    		t1.setMemberC(300);
    		System.out.printf("t1 memberC : %d\n", t1.getMemberC());
    		
    		t1.setMemberC(-300);
    		System.out.printf("t1 memberC : %d\n", t1.getMemberC());
    	}
    }
    
    
    class TestClass1{
    	// 변수들은 모두 private로 정의한다.
    	private int memberA = 100;
    	private int memberB;
    	private int memberC;
    	
    	// 만약 변수의 값을 객체 생성시 딱 한번만 저장할 수 있도록 하겠다면
    	// 생성자를 통해 처리한다.
    	public TestClass1(int memberB) {
    		this.memberB = memberB;
    	}
    	
    	public void printValue() {
    		System.out.printf("memberA : %d\n", memberA);
    		System.out.printf("memberB : %d\n", memberB);
    	}
    	
    	// memberC에 대한 setter
    	public void setMemberC(int memberC) {
    		// 값 저장에 대한 제한이 있다면 if문으로 구현해준다.
    		if(memberC > 0) {
    			this.memberC = memberC;
    		}
    	}
    	// memberC에 대한 getter
    	public int getMemberC() {
    		return this.memberC;
    	}
    }
    
    // setter getter 자동완성
    // 이클립스에서 Source > Generate Getters and Setters
    class TestClass2{
    	private int memberA;
    	private double memberB;
    	private boolean memberC;
    	private String memberD;
    	
    	public int getMemberA() {
    		return memberA;
    	}
    	public void setMemberA(int memberA) {
    		this.memberA = memberA;
    	}
    	public double getMemberB() {
    		return memberB;
    	}
    	public void setMemberB(double memberB) {
    		this.memberB = memberB;
    	}
    	public boolean isMemberC() {
    		return memberC;
    	}
    	public void setMemberC(boolean memberC) {
    		this.memberC = memberC;
    	}
    	public String getMemberD() {
    		return memberD;
    	}
    	public void setMemberD(String memberD) {
    		this.memberD = memberD;
    	}
    	
    }

     

    마무리

    지금 생각했을 때 오전에 내주신 과제를 실패한 원인을 생각해보자면

    첫번째. 분명히 강사님도 말씀해주셨지만 코드에는 정답이 없다라는 말에도 정답을 찾으려 했기 때문이라고 생각합니다.

     

    두번째. 객체지향언어스러운 문법에 익숙하지 않아서라고 생각합니다.

     

    세번째. 소통을 원활히 하지 못하였다라는 느낌이 있었습니다.

     

    네번재. 각 자 역할을 나누지 않았다 입니다. 

     

    물론 다른 조원분들은 어떻게 생각할 지 모르겠습니다.

    제 개인적인 생각입니다.

     

    개인적으로는 저 포함 조원분들 모두 위에서 말한 첫번째 원인이 생각을 하는데 방해를 했던 것 같습니다. 구현을 한 뒤 틀을 고쳐가도 될텐데... 그게 무서워서 좀 꼬였었던 것 같습니다. 

     

    두번째 원인은 첫번째 원인과 중복인 듯 하지만 결이 좀 다른 느낌이 있습니다.

    명확한 해결 방법이 있기 때문입니다.

    저에게 있어서는 반복숙달이라고 생각합니다. 왜냐하면 간단한 코드라도 계속 작성해야 실력이 늘어나기 때문입니다.

    (개인피셜)

     

    그리고 세번째와 네번째원인도 첫번째 원인 때문에 추가적으로 생긴 문제였던 것 같습니다.

    정답을 찾는데 정답이 안보이니 의견을 말했다가 괜히 안좋을 것 같으니까.... 그렇게 말이 적어지고.... 소통이 줄어들고....소통이 줄어드니....역할을 못나누고.... 저 또한 말을 끊임 없이 했던 것이 아니였기 때문입니다.

     

     

    그래서 저는 내일 부터는 조원끼리 상의를 하는 시간이 되면 계속 물어볼 생각입니다.  한명이라도 계속 물어본다면 상기 원인 4개중 2개를 없앨 수 있고 나머지 2개는 간단한 코드라도 반복숙달하여 익숙해지면 해결될 수 있는 문제라고 생각하기 때문입니다.

     

    그리고 강의를 들으면 들을수록 제가 알고리즘 문제만을 작성할 때는 반쪽짜리 같은 코드를 작성하며, 반쪽짜리 공부를 하고 있었구나 라고 생각이 들었었습니다. 분명 코틀린을 처음 공부할 때 봤던 내용이 있긴 하지만, 어느 순간 잊어버려 생각조차 하지 않았던 내용을 다시 세세하게 배우고 있으니 스스로 창피하기도 했습니다.

    하지만 다시 생각해보면 부족했던 반쪽을 채워가면서 점점 기초가 튼튼한 주니어 개발자로 성장하고 있다라고 생각 할 수 있는 부분도 있기에 스스로 나름 소소한 위로를 받기도 한 것 같습니다.

     

    일단 현재 정한 최종 목표 : 기초가 튼튼한 주니어 개발자

     

     

     

     

     

Designed by Tistory.