본문 바로가기

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

[2024-2 Java 스터디] 이민형 #3주차 (5장)

반응형

자바를 "자바라" (Java "java")

 

 

 

 

 

 

5. 뭐어어?? 자바는 객체 지향 프로그래밍이라고?


 

 

 

객체 지향 프로그래밍이란?

 

객체 지향 프로그래밍이란 단어를 이해하기 위해서 좋은 예시를 하나 갖고 왔다.

 

계산기의 메커니즘을 한 번 생각해보자.

 

계산기에 3을 입력하고 4를 더해주면 기존의 3의 값에다가 4를 더해서 7이 출력된다.

한마디로 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));
        System.out.println(Calculator.add(4));
    }
}

 

 

여기서 내가 만든 add라는 메서드는 num으로 받은 값을 이전에 계산한 결괏값인 result에 더해 리턴하는 메소드이다.

이 코드를 실행하면 3과 7이 차례로 출력된다.

만약 뭔가를 더하는 것 뿐만 아니라 배는 기능도 필요하다면 그에 맞는 메서드를 작성해주면 된다.

 

 

그런데말이다. 만약 계산기가 2대가 필요하다면? 이 기능을 동시에 사용하고 싶다면?

평소 같았으면 클래스를 하나 더 만들었겠지만 우린 이제 하수가 아니다.

만약 2개가 아니라 3개 4개.. 더 늘어난다면 클래스를 추가하는 것은 미련한 짓이다.

 

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));
        System.out.println(cal1.add(4));

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

 

일단 Calculator 클래스로 계산기 메커니즘을 만들고

 

Calculator cal1 = new Calculator();

Calculator cal2 = new Calculator(); 

 

이렇게 Calculator 클래스의 객체를 2개 만든다.

이걸 객체라고 한다.

클래스로 만든 별개의 객체가 각각의 역할을 수행한다.

 

 

 

클래스가 다른 클래스

 

 

 

class Animal {
}

public class Sample {
    public static void main(String[] args) {
        Animal cat = new Animal();
    }
}

 

일단 Animal 클래스를 하나 만든다.

Animal 클래스는 아무런 메소드도 없는 그냥 빈 껍데기 클래스일 뿐이다.

 

하지만 이러한 클래스도 객체는 만들 수 있다.

Sample 클래스를 보면 Animal 클래스의 객체 cat을 만든다.

 

new 키워드는 새로운 객체를 생성할 때 사용한다. 이렇게 하면 Animal 클래스의 인스턴스인 객체 cat이 생성 된다.

cat은 Animal 클래스의 인스턴스이고, Animal 클래스의 인스턴스인 cat은 객체이다.

 

Animal cat = new Animal();
Animal dog = new Animal();
Animal horse = new Animal();
...

 

이렇게 객체를 무한히 생성할 수 있다.

 

class Animal {
    String name;
}

public class Sample {
    public static void main(String[] args) {
        Animal cat = new Animal();
        System.out.println(cat.name); //null 출력
    }
}

 

Animal이라는 클래스 안에 name이라는 객체변수를 하나 만든다. 당연히 name에 할당 된 값은 없다.

이렇게 클래스에 의해 생성된 것은 객체, 클래스 안에 선언된 변수는 객체변수라고 한다.

 

 

객체변수는 객체를 이용하여 접근 할 수 있다.

도트연산자를 이용해 cat 객체의 변수 name에 접근한다.

 

당연하게도 name이라는 문자열 변수에 아무 값도 할당 돼있지 않기 때문에 출력하게 되면 null이 출력된다.

 

 

메소드는 클래스 내에서 구현되는 함수를 말한다. 

class Animal {
    String name;

    public void setName(String name) {
        this.name = name;
    }
}

public class Sample {
    public static void main(String[] args) {
        Animal cat = new Animal();
        cat.setName("boby");  // 메서드 호출
        System.out.println(cat.name);
    }
}

 

Animal 클래스 안에 setName이라는 메소드를 작성했다.

public void setName(String name) {

 

여기서 void는 리턴값이 없음 을 의미한다.

그리고 괄호 안 String name은, 저 메소드, 저 함수의 입력 값을 String name으로 받겠다는 것이다.

 

아까 우린 객체 변수에 접근하기 위해서 도트 연산자를 사용했다.

마찬가지로 이 메서드를 호출하기 위해서는 객체.메서드를 이용해준다.

 

저렇게 하면 cat.name이 출력되기 전에 setName메서드가 먼저 호출된다.

 

 

자 근데 뭔가 처음 보는 게 존재한다....

this.name = name;

하 이건 또 뭘까?

 

 

Sample 클래스의 메인 메서드에서 "boby"를 입력값으로 하여 setName 메서드를 호출했기 때문에

setName의 입력항목 name에는 "boby"라는 문자열이 입력 될 것이다.

 

 

그리고 setName 메서드의 this라는 것은 그 클래스에 의해 생성된 객체를 뜻한다.

setName이라는 메서드는 cat이라는 객체를 통해 호출했기 때문에

setName 메서드 안의 this는 당연 cat을 지칭한다.

 

따라서 this.name = name; 이라는 코드는

cat.name = "boby"; 라고 해석된다.

 

 

class Animal {
    String name;

    public void setName(String name) {
        this.name = name;
    }
}

public class Sample {
    public static void main(String[] args) {
        Animal cat = new Animal();
        cat.setName("boby");  // 메서드 호출

        Animal dog = new Animal();
        dog.setName("happy");

        System.out.println(cat.name);
        System.out.println(dog.name);
    }
}

 

이렇게 cat 뿐만 아니라 dog라는 Animal 클래스의 인스턴스, 즉 새로운 객체를 만들어도

각 객체의 객체 변수는 공유되지 않는다. 

당연하다ㅋ

 

 

객체 변수의 값이 독립적으로 유지된다는 점.

이게 클래스의 존재 이유이자 너무나 중요한 개념이 아닐까 싶다.

 

객체 지향적 프로그래밍이란 말이 조금 와닫기 시작한다.

 

 

static을 사용하면 객체변수가 공유되게 할 수도 있긴하다.

 

 

 

 

메서드는 매thㅓ드?

 

 

 

메서드는 함수라고도 한다.

뭐 자바에서는 그렇다. 파이썬 같은 언어에선 함수와 메서드를 구분하지만 말이다.

클래스 밖의 무언가는 자바에선 있을 수가 없기 때문에 메서드도 당연 클래스 안에 존재한다.

 

 

그럼 함수가 뭘까? 

f(x) 같은 것이다. f(x) 같은 것은 뭘까? 입력값을 넣으면 무언가 출력값이 나온다.

내가 아까 메서드는 함수라고 했다.

그래 그거다 무언가 들어가면 어버버버해서 출력값을 도출하는 그게 바로 메서드(method)이다!

 

그럼 여기서 생각이 딱 들어야한다. 입력값이 여러 개일 때 막 메서드를 여러개 적을 필요가 없다.
과일 주스 여러 잔을 만드는데는 믹서기 하나만 있어도 충분하다 :)

 

 

public class Sample {
    int sum(int a, int b) {  // a, b 는 매개변수
        return a+b;
    }

    public static void main(String[] args) {
        Sample sample = new Sample();
        int c = sample.sum(3, 4);  // 3, 4는 인수

        System.out.println(c);
    }
}

 

Sample이라는 Pubic class에 sum이라는 메서드를 작성한다.

sum 메서드는 int 자료형 인자 2개를 받아 둘을 더한 값을 리턴한다.

 

그리고 main이라는 메서드에서 Sample 클래스의 인스턴스 sample을 만들고

그 객체로 sum이라는 메서드를 호출해서 매개변수 a,b에 저장하고

메서드를 실행해서 a+b의 값을 c로 리턴하게 되는 것이다.

 

인수와 매개변수의 차이에 주의하자.
인수는 메서드를 호출할 때 전달하는 입력값이고, 매개 변수는 그 인수를 저장하는 변수이다.

 

 

자바의 메서드 구조는 다음과 같다.

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

 

리턴자료형은 리턴이 되는 값의 자료형을 의미한다.

메서드는 결과값을 반환하기 위해 return이라는 키워드를 사용한다.

입력값 -----------(메서드)----------->결과값

이 구조니까.

 

method 결과값O 결과값X
입력값 O 가능 가능
입력값 X 가능 가능

 

이러한 형태의 메소드들이 모두 가능하다.

 

public class Sample {
    void sum(int a, int b) {
        System.out.println(a+"과 "+b+"의 합은 "+(a+b)+"입니다.");
    }

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

 

리턴값이 없는 메서드는 앞에 void라고 표기한다.

이 코드를 실행하면 "3과 4의 합은 7입니다."라고 출력된다.

 

근데 여기서 헷갈릴 수도 있는 게 출력되는 값이 있는데 왜 리턴값이 없다는 것인지 의아해할 수도 있다.

출력값과 리턴값은 엄연히 다른 것이다.

"3과 4의 합은 7입니다." 라는 문장은

그냥 메서드 내에서 출력되는 문장이지 절대 함수에서 도출되는 리턴 값이 아니다.

리턴값은 오직 return 명령어로만 반환이 가능하다.

 

 

근데 return 명령어를 다른 방법으로도 사용할 수 있다.

public class Sample {
    void sayNick(String nick) {
        if ("바보".equals(nick)) {
            return;
        }
        System.out.println("나의 별명은 "+nick+" 입니다.");
    }

    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.sayNick("야호");
        sample.sayNick("바보");  // 출력되지 않는다.
    }
}

 

위 코드와 같이 만약 nick이라는 매개변수가 "바보"라면

return 명령어로 아무것도 반환을 하지 않고 그 메서드를 탈출하게 된다.

단 return 명령어로 메서드를 탈출하기 위해서는 메서드의 리턴 자료형이 void이어야만 한다.
만약 리턴 자료형이 void가 아니라면 컴파일 오류가 발생한다.

 

 

 

public class Sample {
    void varTest(int a) {
        a++;
    }

    public static void main(String[] args) {
        int a = 1;
        Sample sample = new Sample();
        sample.varTest(a);
        System.out.println(a);
    }
}

 

이 코드의 출력값이 2라고 생각하는 사람도 있겠지만

사실 이 코드의 출력값은 1이다.

 

점프 투 자바에서는 뭐 메서드 안의 매개변수는 메서드 밖의 변수하고 다르다....라고는 하는데

그냥 리턴값이 없잖냐ㅜ 당연한거다.

 

 

public class Sample {
    int varTest(int a) {
        a++;
        return a;
    }

    public static void main(String[] args) {
        int a = 1;
        Sample sample = new Sample();
        a = sample.varTest(a);
        System.out.println(a);
    }
}

 

저 코드를 수정하려면 이렇게 리턴 자료형을 void가 아닌 int 자료형으로 정해주고

리턴을 확실히 한 다음 main 메서드의 a값에 리턴값을 박아주면 된다.

초간단 ㅎ

 

 

 

public class Sample {

    int a;  // 객체변수 a

    void varTest(Sample sample) {
        sample.a++;
    }

    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.a = 1;
        sample.varTest(sample);
        System.out.println(sample.a);
    }
}

 

어지러울 수도 있는 이 코드를 살펴보자.

일단 Sample클래스에서 객체변수 a를 하나 선언했다.

 

그리고 varTest메서드를 만들고 입력값을 Sample 클래스의 인스턴스로 받는다.

그리고 그 객체의 객체변수에 1을 더해준다.

이처럼 입력값을 원시 자료형이 아닌 객체로도 받을 수 있다.

 

사실 입력값을 객체로 받지 않아도

객체로 메서드를 호출했기 때문에 this 명령어를 사용해주어도 된다.

 

 

 

 

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

 

 

 

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);
    }
}

 

Updater 클래스에서는 Counter 클래스의 객체를 입력 받아

그 객체의 객체변수에 1을 더해준다.

 

음 모르겠다 더 설명할 필요가 있을까?

 

 

 

 

Quiz

 

 

 

 

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

 

답: d)

 

 

 

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

 

답: a)

 

 

 

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

 

답: b)

 

 

 

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

 

답: a)

 

 

 

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

 

답: c)

 

 

 

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

 

답: b)

 

 

 

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

 

답: a)

 

 

 

 

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

 

답: a)

 

 

 

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

 

답: d)

 

 

 

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

 

답: c)

 

 

 

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

 

답: c)

 

 

 

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

 

답: d)

 

 

 

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

 

답: c)

 

 

 

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

 

답: a)

 

 

 

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

 

답: d)

 

 

 

16.return 키워드는 언제 사용되는가? (중요)

 

답: a)

 

 

 

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

 

답: b)

 

 

 

클래스와 객체의 차이점?

-클래스로 객체를 만드는 것임 

 

 

this 키워드를 사용하는 이유?

-가장 근본적인 이유는 객체화를 시킴에 있다

 

 

 

매개변수와 인자의 차이점?

-매개변수는 인자값을 저장하는 거임

 

 

 

필드와 지역 변수의 차이점을 설명하고, this 키워드가 사용되는 이유를 함께 설명하기.

-필드는 클래스 안의 변수, 로컬변수는 메서드 안의 변수임. 근데 이제 this를 이용하여

필드에 영향을 줄 수 있음

 

 

자바에서 call by value와 call by reference의 차이?

-자바는 call by value만을 사용하며, 객체 참조를 전달할 때도 참조 주소의 “값”을 복사해 전달하는 방식이라고 한다.

 

 

 

메서드 내에서 선언된 변수의 효력 범위(scope)란?

-메서드 안에서만 사용 가능

 

 

 

자바에서 생성자(constructor)의 역할?

-일단은 객체를 초기화함

 

 

클래스에서 final 키워드를 사용하는 이유와 그 효과?

-그 값이 변하지 않게 절대 변하지 않게 사용함.

 

 

 

메서드가 return을 사용하는 이유와 반환되는 값을 처리하는 방법?

-값을 반환하려고 사용함. 뭐 출력할수도 있고.. 변수로 사용 가능

 

 

객체를 생성하는 방법과 그 과정에서 new 연산자의 역할?

-새로운 객체를 생성하는 역할을 함

 

 

클래스와 인터페이스의 차이점?

-인터페이스는 메서드의 틀을 정의함

 

 

 

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

-여기서의 this.value는 객체의 객체변수를 지칭함

 

 

 

지역 변수와 전역 변수의 차이점?

-지역 변수는 모든 메서드 접근 가능 그러나 전역 변수는 해당 메서드만 가능

 

 

 

반응형