ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • JAVA - 상속, 생성자
    CS/JAVA 2024. 6. 4. 00:38

    상속

    상속이란, 말그대로 클래스를 상속받아 부모의 메서드나 변수를 사용할 수 있게 하는 것이다.

    '백문이불여일코'라고, 직접 코드를 짜보자.

     

    자동차에는 기아차, 현대차 등등 종류가 많다. 자동차에 대한 정보를 담은 클래스를 만들어보자. 

    public class Hyundai extends Car{
        void hyundaiOnly(){
            System.out.println("현대만의 기술, 특징");
        }
    }
    public class Hyundai {
        String name;
        String type;
        void accel(){
            System.out.println("엑셀");
        }
        void brake(){
            System.out.println("브레이크");
        }
        void hyundaiOnly(){
            System.out.println("현대만의 기술, 특징");
        }
    }
    public class Kia {
        String name;
        String type;
        void accel(){
            System.out.println("엑셀");
        }
        void brake(){
            System.out.println("브레이크");
        }
        void kiaOnly(){
            System.out.println("기아만의 기술, 특징");
        }
    }

     

    Hyundai 클래스와 Kia 클래스는 각각 자동차의 공통 정보, 기능과 각 자동차만의 특징을 나타내고 있다.

    만약 이 두개의 자동차뿐만 아니라 우리나라의 모든 자동차에대한 클래스를 만들어야된다면?  또는 공통된 기능을 수정하거나 추가하게될 경우는 어떨까?

    물론 일일히 다 만들고 수정할 수 있겠지만, 조금 비효율적으로 보인다.

    그렇다면 공통된 정보나 기능들은 하나의 정보로 모을 수는 없을까?

     

    이럴 경우에 상속을 사용할 수 있다.

    자동차라는 부모 클래스를 만들고, 각 자식 클래스가 자동차 클래스를 상속받으면 자동차의 공통 특징들을 일일히 적지 않아도 부모의 변수나 메서드를 갖게된다.

     

    public class Car {
        String name;
        String type;
        void accel(){
            System.out.println("엑셀");
        }
        void brake(){
            System.out.println("브레이크");
        }
    }
    public class Hyundai extends Car{ // 상속할 때는 extends를 사용한다.
        void hyundaiOnly(){
            System.out.println("현대만의 기술, 특징");
        }
    }
    public class Kia extends Car{
        void kiaOnly(){
            System.out.println("기아만의 기술, 특징");
        }
    }
    public class Main {
        public static void main(String[] args) {
            Hyundai hyundai = new Hyundai();
            hyundai.accel();
            hyundai.brake();
            Kia kia = new Kia();
            kia.accel();
            kia.brake();
        }
    }
    
    //출력 결과 : 
    //엑셀
    //브레이크
    //엑셀
    //브레이크

     

    위 코드처럼 extends를 사용하면 상속을 받을 있다.

    이렇게 공통된 특성을 상속받아 사용할 경우, 수정이 필요할 경우 부모 클래스만 수정하면되기때문에 코드의 재사용성이 높아진다. 

     

    생성자 

    생성자에 대한 정의는 다음과 같다.

    "생성자는 객체 지향 프로그래밍에서 객체의 초기화를 담당하는 서브루틴을 가리킨다." 

    정의만 보면 무슨 소리인지 모르겠지만, 쉽게 말해 생성자는 클래스와 같은 이름을 가진 메서드이다.반드시 초기화 용으로 사용해야하는 것은 아니지만, 보통 초기화하기 위해 많이 사용하는 것을 지향한다.

     

    우선, 생성자를 사용하지 않고 Student 클래스를 만들어 값을 초기화하는 코드를 짜보자.

    public class Student {
        String name;
        Integer age;
    }
    public class StudentMain {
        public static void main(String[] args) {
            Student student01 = new Student();
            student01.name = "철수";
            student01.age = 20;
    
            Student student02 = new Student();
            student02.name = "영수";
            student02.age = 25;
        }
    }

     

    학생 이름과 나이를 포함하는 클래스로부터 student01, student02 객체를 만들어 초기화했다.

    이제 이 코드를 좀 더효율적으로 만들어보자.

    public class Student {
        String name;
        Integer age;
        
        // 값을 초기화 하는 메서드를 추가
        public void setStudent(String name, Integer age){
            this.name = name;
            this.age = age;
        }
    }
    public class StudentMain {
        public static void main(String[] args) {
            Student student01 = new Student();
            student01.setStudent("철수",20);
    
            Student student02 = new Student();
            student01.setStudent("영수",25);
        }
    }

     

    Student 클래스 안에 초기화 하는 함수를 만들었더니 코드가 훨씬 깔끔해졌다. (물론 지금은 2줄밖에 안줄었지만, 학생이 100명이 되는 경우 100줄이 줄어드는 것이다!)

     

    하지만! 조금 더 효율적으로 만들 수는 없을까?

    이때 생성자를 사용해 코드를 효율적으로 작성해 볼 것이다. 

    public class Student {
        String name;
        Integer age;
        
        // 생성자 : 클래스와 같은 이름을 가진 객체 초기화 메서드
        public Student(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    }
    public class StudentMain {
        public static void main(String[] args) {
            Student student01 = new Student("철수",20);
    
            Student student02 = new Student("영수",25);
        }
    }

     

    실은 메서드 이름이 달라진 것 말고는 앞에서 만든 setStudent 메서드와 크게 다를 것이 없다.

    하지만, 객체를 생성 후에 함수를 호출해 초기화했던 방법과는 다르게 객체를 생성하는 동시에 초기화가 가능해졌다. 

    이렇게 생성자를 사용하므로써 처음 코드에 비해 4줄이 줄어들었다. (100명의 학생이면 200줄 줄어드는 것이다. 심지어 멤버변수가 더 늘어난다면 엄청난 코드 수를 줄일 수 있을 것이다.)

     

    실은 그동안 우리는 자연스럽게 생성자를 사용하고 있었다 (두둥)

    Student 클래스를 예를들면 Student 객체를 생성할 때  new Student() 라는 명령어를 사용했는데,

    여기서 Student()가 생성자이다. 

    생성자를 직접 만들지 않을 경우, 아래 코드와 같이 아무것도 하지 않는 기본 생성자가 존재한다. 

    void Student(){
    }
    💡사실 아무것도 하지 않는 것은 아니다!
    c언어에서 포인터를 사용하거나 구조체를 사용하는 등 동적할당이 필요할 때, 아래 코드와 같은 코드가 필요하다.
    이 코드는 두개의 int형 변수가 있는 Student 구조체를 담을 수 있는 만큼의 메모리 공간을 확보하는 과정이다. 
    // 구조체
    typedef struct Student{
        int studentId;
        int age;
    }student;
    
    void main(){
    	//student구조체만큼 메모리 공간 확보
    	student *s1 = (student *)malloc(sizeof(student));
    }


    JAVA에서는 기본 생성자가 이런 과정을 자동으로 해준다. 

    기본 생성자 외의 생성자를 구현할 경우, 메모리를 할당해주는 역할 + 추가로 구현한 기능을 같이 해주는 것이다.
Designed by Tistory.