tuter77

Java : 상속, 배열(로테이션) 본문

JavaStudy

Java : 상속, 배열(로테이션)

tuter77 2023. 1. 29. 20:03

● 객체지향 핵심.(chapter3 시작) 

총 6개의 chapter 중 절반!

 

객체간 상속으로 시작.

 

▷ 클래스 상속

- 새로운 클래스를 정의할 때 이미 구현된 클래스를 상속받아서 속성이나 기능을 확장하여 클래스를 구현한다.

- 이미 구현된 클래스보다 더 구체적인 기능을 가진 클래스를 구현해야할 때 기존클래스를 상속한다.

 

위 다이어그램으로 볼때 상위 클래스(상속하는)는 클래스는 A클래스로 parent class, base class, super class 등으로 부른다.

하위 클래스(상속받는)는 클래스는 B클래스로 child class, derived class, subclass 등으로 부른다.

 

 상속의 문법 

class B extends A{

 

}

extends 키워드 뒤에는 단 하나의 클래스만 올 수 있다. (자바는 단일 상속만을 지원한다.)

이 문법은 스터디그룹에서도 사용했다. 미리 만들어둔 DTO클래스나, Board 클래스를 상속할때도 사용했고 굉장히 객체간의 협업을 위해 굉장히 자주 이용됐다.

 

▷ 상속을 구현하는 경우

- 상위 클래스는 하위 클래스보다 더 일반적인 개념과 기능을 가졌다. - 하위 클래스는 상위 클래스보다 더 구체적인 개념과 기능을 가졌으며, 이는 하위클래스가 상위 클래스의 속성과 기능을 확장(extends)한다는 의미다.

 

▷ [실습]상속을 활용해 멤버십 클래스 구현.

/* 멤버십 시나리오

회사에서 고객 정보를 활용한 맞춤 서비스를 하기 위해 일반고객과 이보다 충성도가 높은 우수고객(VIPCustomer)에 따른 서비스를 제공하고자 함.

물품을 구매할 때 적용되는 할인율과 적립되는 보너스 포인트의 비율이 다름.

여러 멤버십에 대한 각각 다양한 서비스를 제공할 수 있음.

멤버십에 대한 구현을 클래스 상속을 활용하여 구현해보기.

 

- 일반고객(Customer) 구현

고객의 속성 : 고객 아이디, 고객 이름, 고객 등급, 보너스 포인트, 보너스포인트 적립비율

일반 고객의 경우 물품 구매시 1%의 보너스 포인트 적립.

*/

 

예제)

public class Customer {
	
	protected int customerId;
	protected String customerName;
	protected String customerGrage; //private면 상속해도 접근이 불가해서 protected로 선언.
	int bonusPoint;
	double bonusRatio;

	public Customer() {
		
		customerGrage = "SILVER";
		bonusRatio = 0.01;
	}
	
	public int calcPrice(int price) {
		bonusPoint += price * bonusRatio;
		return price;
	
	}
	
	public String showCustomerInfo() {
		return customerName + "님의 등급은 " + customerGrage + "이며, 보너스 포인트는 " + bonusPoint + "입니다.";
	}

}

 

일반 고객은 SILVER로 등급을 고정.

Customer 클래스에서 VIP클래스 까지 구현하면 요구에따라 if > else if 문이 계속 늘어날것.

때문에 extends를 활용해 상속받는 하위클래스인 VIPCustormer를 생성. 

 

public class VIPCustomer extends Customer {

	double salesRatio;
	String agentId;
	
	public VIPCustomer() {
		
		bonusRatio = 0.05;
		salesRatio = 0.1;
		customerGrage = "VIP";
	}
	
}

이 경우 상속받았기 때문에 CustomerId등의 변수들을 따로 생성할 필요가 없음.

그 말은 메모리할당을 따로 하지 않아도, 상위클래스에 이미 생성되어있는 멤버 변수의 메모리로 VIP 인스턴스들이 생성된다는 것이다.

또한 하위 클래스에서 접근이 가능하게 상위 클래스는 private가 아닌 protected로 선언한다.

 

테스트클래스 만들기.

 

public class CustomerTest {

	public static void main(String[] args) {

		Customer customerLee = new Customer();
		customerLee.setCustomerName("이순신");
		customerLee.setCustomerId(10010);
		customerLee.bonusPoint = 1000;
		
		System.out.println(customerLee.showCustomerInfo());
		
		VIPCustomer customerKim = new VIPCustomer();
		customerKim.setCustomerName("김유신");
		customerKim.setCustomerId(10020);
		customerKim.bonusPoint = 10000;
		System.out.println(customerKim.showCustomerInfo());
		
	}

}

 

테스트 클래스를 실행해보면 일반 고객과 VIP고객 모두 값이 잘 입력되고 메서드가 잘 실행되는 것을 알 수 있다.

 

오늘은 상속의 기본개념을 실습으로 알아봤다. 

확실히 몇 번써먹어봐서 개념이해가 수월했다. 

이런부분에서 실시간 강의와 병행하는 것이 아주 유용하다는 걸 느낀다.

 


<java실시간강의>

 

●  [실습]배열 왼쪽 로테이션 

▷ 배열안의 값들을 왼쪽으로 n만큼 이동하는 기능 구현.

    public static void main(String[] args) {
        // 배열 초기화
        int [] arr = new int [] {1, 2, 3, 4, 5};

        // 왼쪽으로 회전할 횟수
        int n = 10;

        // 원본 배열을 먼저 출력하고 회전 처리 후 출력 예
        /*
        원본 배열 : 왼쪽으로 2회전
            <-----
        1	2	3	4	5
        회전 후 배열 :
        3	4	5	1	2
         */
        int[]temp = new int[arr.length];
        int count = Math.abs((arr.length -1) - n); //5-1-2 = 2(3번째자리)
        System.out.println("========count[] 출력 : " + count + "=======" );
        for (int i = 0; i < arr.length; ) {
                if(count>arr.length-1) {
                    count = 0;
                }
                System.out.print(count); // 여기서 출력해보니 count++된 값이었다.
                temp[i] = arr[count];
                i++; count++;
//              System.out.print(count); // 출력해보니 count 시작 값이 3이다.
            }
        for (int j=0; j<arr.length; j++){
            arr[j] = temp[j];
        }
        System.out.println();
        System.out.println("=========arr[] 출력=======");
        //출력문
       for(int j=0; j<arr.length; j++){
           System.out.print(arr[j]);
       }
    }
}

처음 구성한 코드인데 확실히 지저분하다.

간단하게 이 중 for문으로 구현해보려다, 도저히 안되겠어서 이렇게 구현했다.

로직은 이렇다.

임시 배열 temp에 n만큼 회전한 위치의 arr값부터 count로 인덱스를 지정하여 저장하고, 이 temp에 저장된 값을 다시 arr배열에 저장하고 출력해본다.

 

count라는 변수는 기존 array에서 이동할 n만큼의 위치가 빠진 수 인데, 회전 횟수인 n이 얼마나 커지든 음수가 나와 에러가 발생하지 않도록 값에 Math.abs 함수를 붙여 절대값으로 저장하게 했다. 

바로 아래 출력문은 온전히 count가 정상 작동하는지, 회전이 끝난 arr의 index를 정확하게 지정하는지 확인하는 절차다. 

처음엔 count값 출력문을 주석 처리된 출력문의 위치에 자리시켜서 자꾸 1씩 증가되어 나오길래 이상하다고 여겼었다.

알고보니 후위연산자 이후의 값이어서 그랬던 것..

 

처음 for문에서 임시 배열에 회전이후의 값을 저장하는 과정인데, 단순히 (배열의 크기 - 1 )= 인덱스 값 이기때문에 조건을 지정하였고, 내부의 if문은 count값이 증가하다 배열의 length보다 커지는 경우에 다시 처음 인덱스 값으로 복귀하는 구문이다.

 

이후 아래 for문에서 원래 배열인 arr에 temp 배열 값들을 저장하고 한번 출력해보았다.

정상작동함을 알 수 있었다. 

 

이제 이 긴 코드를 어떻게 이중 for문으로 줄일 수 있을지 고민해야하는데.. 

다른사람이 제출한 과제를 보니 제일 처음 내가 이중for문으로 실패했을때의 로직이 잘 구현돼있는것을 볼 수 있었다...(눈물이..)

package homework.ch06;

/**
 * 배열의 element를 왼쪽으로 rotate하는 프로그램
 * 횟수를 지정하면 왼쪽으로 한 인덱스씩 이동하고 배열의 첫번째 요소는 목록의 끝에 추가
 */
public class Chapter6HomeworkNoName {
   public static void main(String[] args){
        int[] arr = new int[]{1,2,3,4,5};

        int n = 2;
        int temp = 0;

        for(int a = 0; a< n;a++) {
            for (int i = 0; i < arr.length - 1; i++) {
                temp = arr[i];
                arr[i] = arr[i + 1];
                arr[i + 1] = temp;
            }
        }

        for(int a : arr){
            System.out.print(a);
        }
    }
}

(코드가 심플하니 너무 이쁘다.) 

처음에 나도 위처럼 이중 for문을 써서 깔끔하게 하려고 했지만, arr[i+1] = arr[i+2]를 이어가다.. 이렇게 하다간 답이 없겠다 싶어서 포기했었다. 

저렇게 단순한걸 이처럼 어렵게 다가가다니.. 역시 알고리즘, 로직공부가 많이 부족한걸 느낀다.

분발해야겠다.

 

위 내용은 2022.12.29에 공부한 내용입니다.

링크 : https://dudwls3278.tistory.com/30