22/10/30 TIL

김민우·2022년 10월 30일
0

TIL

목록 보기
8/10

Java

- print, println 차이?

갑자기 궁금해졌다. 다음과 같다.

  • print : 괄호안 내용을 단순히 출력. 개행문자(=줄바꿈문자=\n) 포함안됨.

  • printf : C에서의 printf와 동일. %d, %s 등을 쓰기위해 사용. 개행문자 포함X

  • println : 괄호안 내용을 출력한 후 마지막에 개행문자가 포함되어 있어 출력후 한 줄 띄워짐.

생성자

'생성자' 라는 것을 이용하면 메소드를 정의하지 않아도 인스턴스의 초기화를 진행할 수도 있다. 즉, 객체가 생성되는 시점부터 인스턴스(초기값)를 설정하기 위해 사용한다.

코드로 보면 다음과 같다.

package org.opentutorials.javatutorials.constructor;

class Calculator {
    int left, right;

    /* 생성자 (Contructor)
     * 생성자를 생성할 때는 클래스 이름과 똑같아야 한다. 이름이 똑같다는 것이 중요하다.
     */
    public Calculator(int left, int right) {
        this.left = left;
        this.right = right;
    }

    public void sum() {
        System.out.println(this.left + this.right);
    }

    public void avg() {
        System.out.println(this.left + this.right / 2);

    }
}

public class contructor {
    public static void main(String[] args) {
//        여기서 Calculator는 클래스가 아닌 생성자임을 나타낸다.
        Calculator c1 = new Calculator(10, 20);
        c1.sum();
        c1.avg();
    }
}

주석에도 달아놓았지만, 생성자를 만들때는 클래스의 이름과 동일해야 한다는 것이다.


상속

객체지향에서 아주 중요한 개념이다. 이는 재활용성과도 이어지는데, 상속은 객체지향의 재활용성을 극대화시킨 프로그래밍 기법이라고 볼 수 있다.

상속이란 어떤 객체가 있을 때 그 객체의 필드(변수)와 메소드를 다른 객체가 물려 받을 수 있는 기능을 상속이라고 한다.
코드를 통해 살펴보자

class Calculator {
    int left, right;

    public void setOperands(int left, int right) {
        this.left = left;
        this.right = right;
    }

    public void sum() {
        System.out.println(this.left + this.right);
    }

    public void avg() {
        System.out.println(this.left + this.right / 2);

    }
}

덧셈과 평균을 구하는 Calculator 클래스가 있다.
이 클래스에 빼기(Substract)기능을 추가하고 싶다. 물론, Substract 메소드를 직접 추가하여 사용할 수도 있지만. 상속을 이용하여 더 쉽게 구현할 수 있다.

우선, 아래와 같은 경우에 속한다면 객체에 메소드를 추가하는 것을 어려울 것이다.

  • 객체를 자신이 만들지 않았을 경우. 즉, 소스를 스스로 변경할 수 없을 경우이다.
  • 객체가 다양한 곳에서 활용되고 있는데 메소드를 추가하면 다른 곳에는 불필요한 기능이 포함될 수 있다.

상속을 이용하면 기존의 객체를 수정하지 않으면서 새로운 객체가 기존 객체를 기반으로 만들어진다. 이 때, 기존 객체를 부모 클래스, 새로 만들어진 객체를 자식 클래스라고 부른다.
실제 코드로 확인해보자.

package org.opentutorials.javatutorials.inheritance;

class Calculator {
    int left, right;

    public void setOperands(int left, int right) {
        this.left = left;
        this.right = right;
    }

    public void sum() {
        System.out.println(this.left + this.right);
    }

    public void avg() {
        System.out.println(this.left + this.right / 2);

    }
}

class SubstractionableCalculator extends Calculator {
    public void substract() {
        System.out.println(this.left - this.right);
    }
}

public class inheritance {
    public static void main(String[] args) {
        SubstractionableCalculator c1 = new SubstractionableCalculator();
        c1.setOperands(10, 20);
        c1.sum();
        c1.avg();
        c1.substract();
    }
}

전체 코드이다. 아래 부분을 다시 살펴보자.

class SubstractionableCalculator extends Calculator {
    public void substract() {
        System.out.println(this.left - this.right);
    }
}

extends를 이용하여 부모 클래스(super class)에서 선언, 정의된 것들을 그대로 가져오며, 자식 클래스(sub class)는 오버라이딩 할 필요 없이 부모의 메소드나 변수를 그대로 사용할 수 있다.
즉, 부모 클래스가 가진 것들 + 연장선이다.
부모의 sum, avg를 가져왔으며, 추가적으로 substraction을 구현한 것이다.


클래스 다이어그램으로 표현하면 위와 같다.

갑자기 implements 와 차이점이 궁금해진다.

다양한 종류의 상속

복습 개념으로, 이번엔 곱하기 기능이 있는 계산기를 만들어보자.

package org.opentutorials.javatutorials.inheritance;

class Calculator {
    int left, right;

    public void setOperands(int left, int right) {
        this.left = left;
        this.right = right;
    }

    public void sum() {
        System.out.println(this.left + this.right);
    }

    public void avg() {
        System.out.println(this.left + this.right / 2);

    }
}

class SubstractionableCalculator extends Calculator {
    public void substract() {
        System.out.println(this.left - this.right);
    }
}

class MultiplicationableCalculator extends Calculator {
    public void multiplication() {
        System.out.println(this.left * this.right);
    }
}

public class inheritance {
    public static void main(String[] args) {
//        SubstractionableCalculator c1 = new SubstractionableCalculator();
//        c1.setOperands(10, 20);
//        c1.sum();
//        c1.avg();
//        c1.substract();
        MultiplicationableCalculator c2 = new MultiplicationableCalculator();
        c2.setOperands(10, 20);
        c2.sum();
        c2.avg();
        c2.multiplication();
    }
}

그렇다면, MC를 상속하고 있는 또 다른 클래스를 만들 수 있을까?
당연히 만들 수 있다.

코드를 보면 다음과 같다.

package org.opentutorials.javatutorials.inheritance;

class Calculator {
    int left, right;

    public void setOperands(int left, int right) {
        this.left = left;
        this.right = right;
    }

    public void sum() {
        System.out.println(this.left + this.right);
    }

    public void avg() {
        System.out.println(this.left + this.right / 2);

    }
}


class MultiplicationableCalculator extends Calculator {
    public void multiplication() {
        System.out.println(this.left * this.right);
    }
}

class DivisionableCalculator extends MultiplicationableCalculator {
    public void division() {
        System.out.println(this.left / this.right);
    }
}

public class inheritance {
    public static void main(String[] args) {
        DivisionableCalculator c1 = new DivisionableCalculator();
        c1.setOperands(10, 20);
        c1.sum();
        c1.avg();
        c1.multiplication();
        c1.division();
    }
}

상속의 상속이 가능해진다.
이처럼 상속은 코드의 중복을 제거하거나, 부모가 가진 메소드를 자식이 활용가능하다는 점에서 재활용성도 좋아보인다.
그러나, 객체지향만의 강력한 특징처럼 보이긴 하나 굉장히 복잡해보인다.

상속과 생성자

생성자는 객체를 생성한다. 그 과정에서 해야 할 일들은 생성자 메소드에 지정해서 초기화 작업을 할 수 있다.

super, super()

super는 부모 클래스를 의미한다. 즉, 부모 클래스로부터 상속받은 필드나 메소드를 자식 클래스에서 참조하는 데 사용하는 참조 변수이다.

인스턴스 변수의 이름과 지역 변수의 이름이 같을 경우 인스턴스 변수 앞에 this 키워드를 사용하여 구분할 수 있다.
이와 마찬가지로, 부모 클래스의 멤버와 자식 클래스의 멤버 이름이 같을 경우 super 키워드를 사용하여 구별할 수 있습니다.
이렇게 자바에서는 super 참조 변수를 사용하여 부모 클래스의 멤버에 접근할 수 있다.
this와 마찬가지로 super 참조 변수를 사용할 수 있는 대상도 인스턴스 메소드뿐이며, 클래스 메소드에서는 사용할 수 없다.

자식 클래스의 생성자에서 super 메서드(super())를 사용할 때 주의할 점은 super가 가장 먼저 나타나야 한다는 점이다. 부모가 초기화되기 전에 자식이 초기화되는 일을 방지하기 위한 정책이다.

super와 super()의 차이가 있다. 후에 다시 정리하자. 참고 자료

profile
Pay it forward.

0개의 댓글