점프투자바

SUADI·2022년 5월 11일

6. 객체지향 프로그래밍

연습문제

1. 클래스 상속

class Calculator {
	int value;
    
    Calculator() {
    	this.value = 0;
    }
    
    void add(int val) {
    	this.value += val;
    }
    
    int getValue() {
    	return this.value;
    }
}

public class Sample {
	public static void main(String[] args) {
    	Calculator cal = new Calculator();
        cal.add(10);
        System.out.println(cal.getValue()); // 10 출력
    } 
}

UpgradeCalculator 클래스 만들고 minus 메소드 추가

class UpgradeCalculator extends Calculator {
	void minus(int val) {
    	this.value -= val;
    }
}

public class Sample {
	public static void main(String[] args) {
    	UpgradeCalculator cal = new UpgradeCalculator();
        cal.add(10);
        cal.minus(3);
        System.out.println(cal.getValue()); // 7 출력
    } 
}
  • UpgradeCalculator 클래스를 만들고 Calculator 클래스를 상속하여 클래스 내의 기능을 사용할 수 있도록 한다.

  • minus 메소드를 생성하여 계산기에 빼기 기능을 추가한다. add 메소드와 내용이 거의 유사하다. UpgradeCalculator에 저장되어 있는 값(this.value)에 입력값(val)을 뺀 후 값을 저장한다.

  • UpgradeCalculator 클래스의 객체를 생성한 후 원하는 값을 cal.add, cal.minus를 이용하여 계산한다.

2. 100 이상 수 제한

...

class MaxLimitCalculator extends UpgradeCalculator {
	int getValue() {
    	if (this.value >= 100) {this.value = 100;}
    
    	return this.value;
    }
}

public class Sample {
	public static void main(String[] args) {
    	MaxLimitCalculator cal = new MaxLimitCalculator();
        
        cal.add(10);
        cal.minus(3); // 7 출력
        cal.add(100); // 계산값은 107이지만 100 출력
    }
}
  • UpgradeCalculator를 상속한 MaxLimitCalculator 클래스를 만든다. MaxLimitCalculator 클래스는 Calculator 클래스의 자식의 자식 클래스이므로 getValue 메소드를 사용할 수 있다. 메소드 오버라이딩을 이용해서 이 기능을 수정한다. 조건문을 사용해서 getValue의 리턴값이 100 이상이면 100을 출력하도록 내용을 작성한다.

3. 홀짝 판별 계산기

class Calculator {
	...
    
    void isOdd() {
    	if (this.value % 2 == 0) {
        	System.out.printf("%d는 짝수이다.",this.value);
        } else {System.out.printf("%d는 홀수이다.",this.value);}
    }
}

public class Sample {
	...
    	cal.isOdd(); // 홀짝 출력
}
  • isOdd 메소드를 생성한다. 조건문을 이용하여 값이 2로 나누어 떨어지면 짝수를 출력하도록 내용을 작성한다. 해설은 풀이를 달리했다.
class Calculator {
	...
    
    boolean isOdd(int num) {
    	return num % 2 == 0;
    }
}

public class Sample {
	...
    
    	System.out.println(cal.isOdd(cal.getValue()));
}
  • boolean 자료형을 이용하여 짝수이면 true, 홀수이면 false를 리턴하도록 했고, main 메소드에서 cal.isOdd(cal.getValue())를 출력하도록 했다.

4. 배열, 리스트 내의 값 평균구하는 계산기

import java.util.ArrayList;
import java.util.Arrays;

class Calculator {
	...
    
    int avg(int[] data) {
    	int sum = 0;
    	for (int i=0; i<data.length; i++) {
        	sum += data[i];
        }
        
        return sum / data.length;
    }
    
    int avg(ArrayList<Integer> data) {
    	int sum = 0;
    	for (int i=0; i<data.size(); i++) {
        	sum += data.get(i);
        }
        
        return sum / data.size();        
    }
}

public class Sample {
	...
    	int[] data = {1,3,5,7,9};
    	System.out.println(cal.avg(data)); // 5 출력
        
        ArrayList<Integer> data2 = new ArrayList<>(Arrays.asList(1,3,5,7,9,11));
        System.out.println(cal.avg(data2)); // 6 출력
} 

ㄱ) 배열

  • avg 메소드를 만든다. return 값은 평균값이 될 것이므로 avg메소드의 자료형은 int로 한다. 입력인자는 배열 내의 값들이 될 것이므로 int[] 자료형을 사용한다.

  • avg의 내용을 채운다. 먼저 배열 내의 값들의 총합을 저장할 변수를 선언한다.

  • 반복문을 사용하여 0부터 배열크기까지 sum 변수에 차례로 값들을 더한다.

  • 총합에 배열 크기를 나누어 평균값을 리턴한다.

ㄴ) ArrayList

  • ArrayList를 까먹어서 중간중간 너무 오래 쉬었다는걸 새삼 느끼게 되었다. 전에 포스팅 했던 것들을 다시 훑어보았는데 ArrayList에 대한 개념 이외에도 ArrayList 자료형이 List 인터페이스를 상속했다는 글이 적혀 있었는데 이제 조금이나마 무슨 말인지 알 것 같아서 놀라웠다. 포스팅할 당시에는 내가 이 내용을 이해하는지 못했는지도 모르고 포스팅했던 것 같은데 지금 다시 보니 새롭다. 앞으로도 이런 경우가 자주 일어났음 좋겠다.

  • 복습을 조금만 하자면 ArrayList 자료형의 객체를 생성할 때엔
    ArrayList 내의 값들에 대한 자료형을 꺽쉬 안에 명시해야 한다. 기존에 배열이 아닌 변수를 선언할 때엔 primitive 자료형(int, boolean...)을 사용했다면 지금은 wrapper 자료형(Integer, Boolean)을 사용한다. 오른쪽 꺽쇠에는 자료형을 적지 않아도 된다.

ArrayList<Integer> data = new ArrayList<>();
  • ArrayList의 크기는 size()를 사용, 값을 추출할 때는 get()을 사용한다.

  • 위의 배열에 대한 avg메소드와 입력인자만 바뀌고 기능은 유사하다. 이를 메소드 오버로딩이라고 한다.

5. 객체

import java.util.ArrayList;
import java.util.Arrays;

public class Sample {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<>(Arrays.asList(1, 2, 3));
        ArrayList<Integer> b = a;
        a.add(4);
        System.out.println(b); // [1,2,3,4]
        System.out.println(a); // [1,2,3,4]
        
    }
}
  • a와 b는 동일한 객체를 가리킨다. 따라서 a 리스트에 4를 추가하면 a=b=[1,2,3,4]로 size는 4이다.
import java.util.ArrayList;
import java.util.Arrays;

public class Sample {
    public static void main(String[] args) {
        ArrayList<Integer> a = new ArrayList<>(Arrays.asList(1, 2, 3));
        ArrayList<Integer> b = ArrayList<>(a); // 변경
        a.add(4);
        System.out.println(b); // [1,2,3]
        System.out.println(a); // [1,2,3,4]       
    }
}
  • b 객체와 a 객체가 동일한 값을 가지지만 이후에 값을 수정했을 시 독립적인 b 객체를 가지기 위해서는 위의 코드처럼 작성해야한다.

6. NullPointerException 오류

class Calculator {
    Integer value;
    void add(int val) {
        this.value += val;
    }

    public Integer getValue() {
        return this.value;
    }
}

public class Sample {
    public static void main(String[] args) {
        Calculator cal = new Calculator();
        cal.add(3);  // 여기서 NullPointerException 이 발생한다.
        System.out.println(cal.getValue());
    }
}
  • 오류가 나는 이유는 객체변수 value의 초기값이 선언되어 있지 않기 때문에 NullPointerException 오류가 나는 것이다.
class Calculator {
	Integer value;
    
    Calculator() {
    	this.value = 0;
    }
    ...
}
...
  • 생성자를 만들고 value의 초기값을 0으로 선언해주면 오류가 해결된다.

  • 생성자에 대해 복습해 보면 생성자는 메소드명이 클래스명과 동일하고 리턴값을 정의하지 않은 메소드이다. 생성자는 객체를 생성할 때 생성자 내의 내용을 강제하도록 하는 용도이다.

7. 인터페이스

class Gold {
}

class Silver {
}

class Bronze {
}

class MineralCalculator {
    int value = 0;

    public void add(Gold gold) {
        this.value += 100;
    }

    public void add(Silver silver) {
        this.value += 90;
    }

    public void add(Bronze bronze) {
        this.value += 80;
    }

    public int getValue() {
        return this.value;
    }
}

public class Sample {
    public static void main(String[] args) {
        MineralCalculator cal = new MineralCalculator();
        cal.add(new Gold());
        cal.add(new Silver());
        cal.add(new Bronze());
        System.out.println(cal.getValue());  // 270 출력
    }
}

광물 별로 가치를 매겨 광물의 가치 총합을 구하는 코드이다. 이 코드는 광물이 추가될 때 마다 MineralCalculator 클래스에 add 메소드를 추가해야 한다는 단점이 있다. 인터페이스를 사용하여 add 메소드가 독립적으로 사용될 수 있게끔 코드를 바꿔보자.

interface Mineral {
    int MineralValue();
}

class Gold implements Mineral {
    public int MineralValue() {
        return 100;
    }
}

class Silver implements Mineral {
    public int MineralValue() {
        return 90;
    }
}

class Bronze implements Mineral {
    public int MineralValue() {
        return 80;
    }
}

class MineralCalculator {
    int value = 0;

    public void add(Mineral mineral) {
        this.value += mineral.MineralValue();
    }

    public int getValue() {
        return this.value;
    }
}

public class Sample {
    public static void main(String[] args) {
        MineralCalculator cal = new MineralCalculator();

        cal.add(new Gold()); // 100
        cal.add(new Silver()); // 190
        cal.add(new Bronze()); // 270

        System.out.println(cal.getValue()); // 270 출력
    }
}
  • Mineral 인터페이스를 생성하고 MineralValue 메소드를 선언한다. 인터페이스에서는 메소드를 선언만 하고 내용은 상속받는 클래스에서 작성한다.

  • Gold, Silver, Bronze 클래스에 Mineral을 implements하고 MineralValue 메소드의 내용을 채운다. 내용은 각 광물의 가치를 리턴값으로 한다.

  • MineralCalculator 내의 add 메소드의 입력 자료형을 Mineral로 해서 어떤 광물이 입력인자로 와도 독립적으로 사용할 수 있게끔 한다. 어떤 광물이든 자식 클래스이므로 부모 인터페이스를 입력자료형으로 사용할 수 있다. 그리고 내용은 현재의 값(this.value)에 각 광물이 가치를 리턴하는 MineralValue 메소드를 더하도록 한다.

8. IS - A 관계

interface Predator {
}

class Animal {
}

class Dog extends Animal {
}

class Lion extends Animal implements Predator {
}

public class Sample {
    public static void main(String[] args) {
        Animal a = new Animal();  // 1번 
        Animal b = new Dog();  // 2번
        Animal c = new Lion();  // 3번
        Dog d = new Animal();  // 4번
        Predator e = new Lion();  // 5번
    }
}

오류나는 문장 찾기
1. Animal은 Animal이다. (o)
2. Dog는 Animal이다. (o)
3. Lions은 Animal이다. (o)
4. Animal은 Dog이다. (x)
5. Lion은 Predator이다. (o)

9. 객체

interface Predator {
    String bark();
}

abstract class Animal {
    public String hello() {
        return "hello";
    }
}

class Dog extends Animal {
}

class Lion extends Animal implements Predator {
    public String bark() {
        return "Bark bark!!";
    }
}

public class Sample {
    public static void main(String[] args) {
        Animal a = new Lion();
        Lion b = new Lion();
        Predator c = new Lion();

        System.out.println(a.hello());  // 1번
        System.out.println(a.bark());   // 2번
        System.out.println(b.hello());  // 3번
        System.out.println(b.bark());   // 4번
        System.out.println(c.hello());  // 5번
        System.out.println(c.bark());   // 6번
    }
}

오류나는 문장 찾기

  • a 객체의 자료형은 Animal이므로 hello 메소드만 사용 가능
  • b 객체의 자료형은 Lion이므로 bark 메소드와 Animal 클래스로부터 상속받은 hello 메소드를 모두 사용 가능
  • c 객체의 자료형은 Predator이므로 bark 메소드만 사용 가능

0개의 댓글