본문 바로가기

WINK-(Web & App)/JAVA 스터디

[2024-2 Java 스터디] 강보경 #3주차

반응형

객체 지향 프로그래밍

자바로 계산기를 구현해보자

class Calculator {
    static int result = 0;

    static int add(int num) {
        result += num;
        return result;
    }
}

public class Sample {
    public static void main(String[] args) {
        System.out.println(Calculator.add(3));  // 3
        System.out.println(Calculator.add(4));  // 7
    }
}

 

음? 계산기 2대가 필요해짐

class Calculator1 {
    static int result = 0;

    static int add(int num) {
        result += num;
        return result;
    }
}

class Calculator2 {
    static int result = 0;

    static int add(int num) {
        result += num;
        return result;
    }
}

public class Sample {
    public static void main(String[] args) {
        System.out.println(Calculator1.add(3));  // 3
        System.out.println(Calculator1.add(4));  // 7

        System.out.println(Calculator2.add(3));  // 3
        System.out.println(Calculator2.add(7));  // 10
    }
}
// Calculator1과 Calculator2는 서로 영향 X

 

필요한 계산기가 많아질 때 클래스를 계속 추가하면 너무 복잡해짐... 그러면 어떻게 헤야할까?

class Calculator {
    int result = 0;

    int add(int num) {
        result += num;
        return result;
    }
}

public class Sample {
    public static void main(String[] args) {
        Calculator cal1 = new Calculator();  // 계산기1 객체를 생성한다.
        Calculator cal2 = new Calculator();  // 계산기2 객체를 생성한다.

        System.out.println(cal1.add(3));  // 3
        System.out.println(cal1.add(4));  // 7

        System.out.println(cal2.add(3));  // 3
        System.out.println(cal2.add(7));  //10
    }
}

 

Caculator 클래스로 cal1, cal2라는 객체를 만들었다! 필요한 계산기가 추가될 때마다 객체만 늘리면 되니 아주 간편하고 좋군! Calculator 클래스에 더하기 말고 다른 연산 메서드도 추가할 수 있음 bb

이게 바로 객체 지향 프로그램의 장점이다!!


클래스

그렇다면 클래스란 과연 무엇인지...

클래스는 객체를 만드는 기능을 가진다

class Animal {
}

public class Sample {
    public static void main(String[] args) {
        Animal cat = new Animal();
        Animal dog = new Animal();
        Animal duck = new Animal();  // 객체를 영원히 추가할 수 잇삼
    }
}

 

Animal 클래스의 인스턴스인 cat이 만들어졌다! (인스턴스: 클래스에 의해 만들어진 객체; cat은 객체 & Animal의 인스턴스)

Animal 클래스로 무수히 많은 객체를 만들 수 있다 bb

 

 

class Animal {
    String name;  // Animal 클래스에 name이라는 String 변수를 추가
}

public class Sample {
    public static void main(String[] args) {
        Animal cat = new Animal();
        System.out.println(duck.name);  // null, 왜냐하면 아무런 값도 대입하지 않앗삼
    }
}

 

name이라는  String 변수처럼클래스에 선언된 변수를 객체 변수라고 한다 (클래스에 의해 생성되는 변수: 객체, 클래스에 선언된 변수: 객체 변수)

객체 변수는 객체.객체변수 와 같이 도트 연산자를 이용하여 접근하고, 값을 대입할 수 있다 (duck.name으로 접근)

 

 

그러면은 이제 객체 변수에 값을 대입해보자메서드를 이용하는 방법이 있음 (여기서 메서드란? 클래스 내에 구현된 함수!)

class Animal {
    String name;

    public void setName(String name) {  // setName이라는 메서드 추가햇삼
        this.name = name;
    }
}

public class Sample {
    public static void main(String[] args) {
        Animal cat = new Animal();
        duck.setName("donald");
        System.out.println(duck.name);  // 이제 donald 출력
    }
}

 

setName 메서드는 입력으로 name이라는 문자열을 받고 출력은 없는 형태의 메서드

객체.메서드 로 호출한당 (duck.setName("donald");) >> 메서드 입력 항목(name)으로 문자열("donald") 전달

이때 setName 메서드 내부에 선언된 this는 바로 duck 객체를 지칭 (만약 Animal cat = new Animal(); > cat.setName("tom"); > 이러면 this는 cat 객체를 지칭)

따라서 이때 this.name = name;  ==  this.name = "donald";  ==  duck.name = "donald"; 임!그리고 객체 변수는 공유되지 않음 주의 완전히 독립적


메서드

메서드는 입력값을 가지고 어떤 일을 하고 결과값을 내어놓는 일을 함

같은 내용을 반복하는 일을 할 때 메서드를 이용해서 한 번에 해결할 수 있도록 하자

public class Sample {
    int sum(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        int a = 3;
        int b = 4;

        Sample sample = new Sample();
        int c = sample.sum(a, b);

        System.out.println(c);  // 7
    }
}

 

이런 식으로 말이당

또, 메서드에 전달된 입력값을 저장하는 변수를 매개 변수, 메서드를 호출할 때 전달하는 입력값을 인수 라고 함

위 코드에서 a와 b는 매개변수, c는 인수가 되는 것이다

 

 

메서드의 입력값과 리턴값

입력값 ---> 메서드(블랙박스와 같은 역할을 한다.) ----> 리턴값

메서드는 이런 구조를 가짐!

리턴자료형 메서드명(입력자료형1 매개변수1, 입력자료형2 매개변수2, ...) {
    ...    
    return 리턴값;  // 리턴자료형이 void 인 경우에는 return 문이 필요X
}

그리고 메서드는 입출력 유무에 따라 4가지로 분류됨

1. 입력값O 리턴값O : 리턴값_받을_변수 = 객체.메서드명(입력인수1, 입력인수2, ...)

int sum(int a, int b) {  // 입력값: int 자료형 a, b
    return a+b;  // 리턴값: int 자료형
}

Sample sample = new Sample();
int result = sample.sum(3, 4);  // 7

 

2. 입력값X 리턴값O : 리턴값_받을_변수 = 객체.메서드명()

public class Sample {
    String say() {  // 입력값 X
        return "Hi";  // 리턴값: String 자료형
    }

    public static void main(String[] args) {
        Sample sample = new Sample();
        String a = sample.say();
        System.out.println(a);  // "Hi"
    }
}

 

3. 입력값O 리턴값X : 객체.메서드명(입력인수1, 입력인수2, ...)

public class Sample {
    void sum(int a, int b) {  // 입력값: int 자료형 a, int 자료형 b
        System.out.println(a+"과 "+b+"의 합은 "+(a+b)+"입니다.");  // return 명령어X -> 리턴값X
    }

    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.sum(3, 4);  // 7
    }
}

 

4. 입력값X 리턴값X : 객체.메서드명()

public class Sample {
    void say() {
        System.out.println("Hi");
    }

    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.say();  // "Hi"
    }
}

 

 

cf) 메서드를 빠져나가고 싶을 때 return을 단독으로 사용해도 됨!


값에 의한 호출과 객체에 의한 호출

메서드에 값을 전달하는 것 vs 객체를 전달하는 것 << 너무 다름!

class Updater {
    void update(int count) {
        count++;
    }
}

class Counter {
    int count = 0;  // 객체변수
}

public class Sample {
    public static void main(String[] args) {
        Counter myCounter = new Counter();
        System.out.println("before update:"+myCounter.count);
        Updater myUpdater = new Updater();
        myUpdater.update(myCounter.count);  // update 메서드는 값(int 자료형)을 전달받앗삼
        System.out.println("after update:"+myCounter.count);
    }
}

before update:0
after update:0

 

Counter 클래스에 의해 생성된 myCounter 객체의 객체 변수인 count 값을 Updater클래스를 이용해 증가시키려 했지만 실패했다... update 메서드가 값을 전달받았기 때문이다...

class Updater {
    void update(Counter counter) {
        counter.count++;
    }
}

class Counter {
    int count = 0;  // 객체변수
}

public class Sample {
    public static void main(String[] args) {
        Counter myCounter = new Counter();
        System.out.println("before update:"+myCounter.count);
        Updater myUpdater = new Updater();
        myUpdater.update(myCounter);  // 고쳣삼
        System.out.println("after update:"+myCounter.count);
    }
}

before update:0
after update:1

 

그래서 이렇게 고쳐보았다! int count 처럼 값을 전달받는 게 아닌 Counter counter 처럼 객체를 전달받도록 말이당


QUIZ

1. 객체 지향 프로그래밍의 4대 특징이 아닌 것은?

- a 복사

 

2. 클래스에서 필드와 메서드의 차이점은 무엇인가?

- d 필드는 객체의 상태를 나타내고, 메서드는 동작을 정의한다

 

3. 다음 중 this 키워드의 역할은 무엇인가?

- b 현재 객체를 참조한다

 

4. 클래스에서 this 키워드를 사용하는 이유는 무엇인가?

- a 같은 이름의 지역 변수와 필드를 구분하기 위해

 

5. 메서드의 리턴 타입이 void인 경우, 메서드가 반환하는 값은?

- c 아무 값도 반환하지 않는다

 

6. 아래 코드에서 출력값은?

public class Example {
    int a = 5;
    public void setA(int a) {
        this.a = a;
    }
    public static void main(String[] args) {
        Example ex = new Example();
        ex.setA(10);
        System.out.println(ex.a);
    }
}

- 10

 

7. 매개변수와 인자의 차이는 무엇인가?

- a 매개변수는 메서드 정의 시 사용되고, 인자는 메서드 호출 시 전달된다

 

8. 메서드가 값을 반환하는 데 사용하는 키워드는?

- return

 

9. 메서드 내에서 선언된 변수의 효력 범위는?

- d 메서드 내에서만 유효하다

 

10. 자바에서 call by value의 의미는?

- c 값의 복사본을 전달한다

 

11. 객체를 생성할 때 사용하는 키워드는?

- c new

 

12. 다음 중 클래스 멤버에 해당하지 않는 것은?

- d 지역 변수

 

13. 다음 중 지역 변수와 필드를 구분하는 올바른 방법은?

- c 지역 변수는 메서드 내에서만 사용된다

 

14. 자바에서 기본 데이터 타입을 객체로 감싸는 클래스는?

- c Wrapper 클래스

 

15. 객체의 생성자를 호출하는 역할을 하는 것은?

- d new 연산자

 

16. return 키워드는 언제 사용되는가?

- a 메서드의 실행을 종료하고 값을 반활할 때

 

17. call by reference는 무엇을 의미하는가?

- b 객체의 참조를 전달한다

 

서술형1. 클래스와 객체의 차이점?- 클래스는 객체를 만드는 기능을 가졌다. 객체는 클래스를 기반으로 생성된 인스턴스이다. 

 

서술형2. this 키워드를 사용하는 이유?- 현재 객체의 인스턴스를 참조하여 메서드 내부에서 해당 객체의 메서드에 접근할 때 사용한다. 또, 메서드의 매개변수와 클래스의 필드 이름이 동일한 경우 this를 이용하여 구분한다.

 

서술형3. 매개변수와 인자의 차이점?- 매개변수는 메서드에 전달된 입력값을 저장하는 변수이고, 인자는 메서드를 호출할 때 전달하는 입력값이다.

 

서술형4. 필드와 지역 변수의 차이점을 설명하고, this 키워드가 사용되는 이유를 함께 설명하기- 필드는 클래스의 속성을 나타내는 변수이고 클래스 내부에서 선언되어 클래스의 모든 메서드에 접근할 수 있다. 지역 변수는 메서드나 생성자, 블록 내부에 선언된 변수이고 해당 블록 내에서만 유효하여 메서드가 종료되면 사라진다. this 키워드는 현재 객체를 참조하거나 매개변수와 클래스 필드의 이름이 같을 때 이름의 충돌을 해결하기 위해 사용된다.

 

서술형5. 자바에서 call by value와 call by reference의 차이?- call by value의 경우 메서드에 매개변수를 전달할 때 실제 값의 복사본이 전달된다. 따라서 메서드 내에서 매개변수의 값을 변경해도 원래 변수에 영향을 주지 않는다. 반면 call by reference는 메서드에 매개변수를 전달할 때 객체의 참조가 전달되어 메서드 내에서 매개변수의 값을 변경하면 원래 변수에도 영향을 준다.

 

서술형6. 메서드 내에서 선언된 변수의 효력 범위란?- 메서드 내에서 선언된 변수는 지역 변수로, 해당 메서드 내에서만 유효하다. 메서드가 종료되면 지역 변수도 사용할 수 없어 사라진다.

 

서술형7. 자바에서 생성자의 역할?

- 생성자는 객체가 생성될 때 호출되어 해당 객체의 초기 상태를 설정해 초기화하는 역할을 한다.

 

서술형8. 클래스에서 final 키워드를 사용하는 이유와 그 효과?- final 키워드는 한 번 설정된 것을 변경할 수 없어 클래스, 메서드, 필드를 고정시키는 데 사용되며 안정성을 높인다.

 

서술형9. 메서드가 return을 사용하는 이유와 반환되는 값을 처리하는 방법?- return 키워드는 메서드가 더 이상 실행되지 않도록 하고, 메서드가 처리한 결과를 호출한 곳으로 반환할 때에도 사용하여 다른 메서드에 인자로 전달하는 등의 방식으로 처리한다. 반환값을 출력하거나 계산에 직접 사용하기도 한다.

 

서술형10. 객체를 생성하는 방법과 그 과정에서 new 연산자의 역할?- 객체를 생성할 클래스를 정의하고 new 연산자를 사용하여 클래스의 인스턴스를 생성한다. new 연산자는 객체를 위한 메모리를 할당해주며 생성자를 호출하여 초기화시켜준다.

 

서술형11. 클래스와 인터페이스의 차이점?- 클래스는 객체의 필드와 메서드을 정의하여 인스턴스를 생성하고 구현한다. 반면 인터페이스는 객체가 수행해야 하는 메서드의 집합으로 메서드의 구현 내용은 포함하지 않는다.

 

서술형12. 다음코드에서 this 키워드가 어떻게 동작하는지 설명하기

public class Test {
    int value;
    public Test(int value) {
        this.value = value;
    }
}

 

- 현재 객체를 참조하고 필드와 매개변수를 구분한다. 생성자 매개변수 value와 클래스 필드 value가 같은 이름이라 this.value는 클래스 필드를, value는 생성자 매개변수를 가리킨다.

 

서술형 13. 지역 변수와 전역 변수의 차이점- 지역 변수는 메서드 내에서 선언된 변수로 해당 메서드 안에서만 사용가능하고, 전역 변수(필드)는 클래스 내에서 선언된 변수로 모든 메서드에 접근할 수 있다.

 

코딩테스트

1.

 

2.

import java.util.*;

class NumberFilter {
    private List<Integer> numbers;

    public NumberFilter(int[] numbers) {
        this.numbers = new ArrayList<>();
        for (int number : numbers) {
            this.numbers.add(number);  
        }
    }
    
    public List<Integer> removeConsecutiveDuplicates() {
        List<Integer> result = new ArrayList<>();  

        for (int i = 0; i < numbers.size(); i++) {
            if (i == 0 || !numbers.get(i).equals(numbers.get(i - 1))) {
                result.add(numbers.get(i));
            }
        }
        return result; 
    }
}

public class Main {
    public static void main(String[] args) {
        int[] arr = {1, 1, 3, 3, 0, 1, 1};

        NumberFilter numberFilter = new NumberFilter(arr);
        List<Integer> filteredNumbers = numberFilter.removeConsecutiveDuplicates();
        System.out.println(filteredNumbers);  // [1, 3, 0, 1]
    }
}
반응형