간단 지식/Java

07. 클래스 - 필드, 생성자, 메소드

납작한돌맹이 2020. 5. 29. 23:37
반응형

클래스 이름을 Test로 하고싶다면 우선 Test.java 파일을 생성해야한다. 그리고 public class Test{ } 라는 형태로 클래스를 선언해야한다. 한 파일에는 일반적으로 하나의 클래스를 선언해서 사용하지만, 추가로 클래스를 선언하는 것이 에러라는 건 아니다. 다만 추가로 선언할 클래스에는 public 키워드가 붙어서는 안된다. 어쨋건 java 파일을 컴파일하면 byte code file은 클래스의 개수만큼 생성된다. 클래스의 용도는 라이브러리용, 실행용으로 구분되는데 main 메소드가 있는 클래스를 실행용이라고 생각하면 된다.

 

new 연산자를 이용하면 클래스로부터 객체를 생성할 수 있다. 

ex) Test test = new Test();

이렇게 생성되는 객체는 Test클래스의 instance라고 부르며 이 과정을 instance화라고 한다. 생성된 객체의 주소는 참조변수 test에 저장된다.

또한 객체는 다른 객체와 구별되는 존재이기 때문에 아래 예시처럼 동일한 클래스에서 두 번 객체를 생성하면 두 객체는 서로다른 주소를 갖는다. 

ex) Test var1 = new Test();

    Test var2 = new Test();

 

그렇다면 클래스의 객체를 생성해서 언제 활용하는가?

위 이미지처럼, A 클래스에 있는 필드와 메소드를 B 클래스에서 사용하고 싶다면 A 클래스의 객체를 생성하고 참조변수를 활용해야한다.


클래스 내부에는 필드, 생성자, 메소드가 들어간다. 간단히 정의하면 필드는 객체의 내부 데이터가 저장되는 곳이다. 생성자는 객체 생성 시 초기화를, 메소드는 객체의 동작을 담당한다.

public class Student{
    public static void main(String[] args){
    	int age;			-----필드
        String name;			-----필드
        int num;			-----필드
        
        Student(){}			-----생성자
        
        int add(int x, int y){		-----메소드
            int result = x + y;
            return result;
        }
    }
}    

엄밀히 따지면 필드≠변수 이다. 변수는 생성자와 메소드 내에서만 존재할 수 있으며, 생성자, 메소드가 종료되면 자동 소멸된다. 반면에 필드는 객체가 소멸하지 않는 한 계속 존재한다. 즉, 위 코드에서 add메소드의 result는 필드가 아니라 변수이다. 따라서 필드는 생성자와 메소드 블록을 제외한다면 클래스 블록 내 어디서든지 선언가능하다. 선언 시 초기값을 지정할 수도 있고 하지 않을 수도 있다. 

 

필드를 초기화하는 방법을 내가 생각하는 방식으로 4가지로 구분해보았다.

1. 기본 초기값

2. 필드 선언시 초기값

3. 생성자 호출시 초기값

4. 그 외

이 중에서 3번에 대해 이해를 하고 넘어가겠다. 소규모의 프로그램이라도 필요한 필드는 수없이 많다. 하나하나 그 값을 초기화하는건 효율적이지 않다. 그래서 사용하는게 3번인데, 생성자를 호출해서 초기화하려면 생성자에 매개변수가 필요하다.

일단 생성자는 기본생성자와 그 외로 구분된다. 기본 생성자는 위 코드의 생성자처럼 클래스이름(){} 으로, 굳이 코드에 적지 않아도 컴파일러가 알아서 기본 생성자를 byte code에 추가한다. 그렇다면 매개변수를 추가한 생성자는 어떨까. 위에 있는 Student 클래스의 연장선으로 생각해보자.

Student(int age, String name){

    this.age = age;

    this name = name;

}

이렇게 매개변수를 갖는 생성자를 선언했다고 가정하자. 그리고 다른 클래스인 Test에서 Student클래스의 필드인 age와 String을 써야한다고 생각해보자. Student에서 기본생성자만 선언했다면 Test클래스의 코드 일부는 다음과 같을 것이다.

Student std = new Student();

std.age = 23;

std.name = "ksh";

반면에 Student에서 위에서 언급한 일반생성자를 선언했다면 Test클래스의 코드 일부는 다음과 같을 것이다.

Student std = new Student(23, "ksh");

어떤 방식이 더 간편한지 눈에 보일 것이다. 필드가 더 많고, 생성자도 여럿 선언한다면 그 효과는 더욱 극대화 될 것이다. 그렇다고 모든 필드를 생성자의 매개변수로 넣으라는 소리는 아니다. 중요하게 다루는 필드를 위한 방식이라고 생각하면 된다. 어쨋든 이런 방식으로 객체 생성 시점에 다양한 값으로 필드를 초기화할 수 있다.


매개변수를 갖는 생성자를 여러개 선언하는 것을 생성자 오버로딩이라고 부른다. 이때 헷갈리지 말아야 할 점은 매개변수의 타입, 개수, 순서가 똑같고 이름만 다르다면 그것은 생성자 오버로딩이라고 할 수 없다.

ex) Student(int age, int num){ ... }

    Student(int name, int age){ ... }

 

생성자 오버로딩이 많아지면 생성자 간의 중복된 코드가 발생할 수 있다. 이는 this()를 이용해서 생성자에서 다른 생성자를 호출함으로써 해결할 수 있다. 

ex) Student(int age){ 

        this(age, "ksh", 1);

     }

    Student(int age, String name){

        this(age, name, 1);

     }

    Student(int age, String name, int num){

        this.age = age;

        this.name = name;

        this.num = num;

    }

이때 this()는 생성자 내부에서 첫 line에만 올 수 있다. 그리고 생성자 호출이 끝나면 다시 원래 생성자로 돌아와 this() 이후의 실행문을 진행해야한다.


메소드의 형태는 다음과 같다.

리턴타입 메소드이름(매개변수){ ... }

 

메소드 리턴을 할 필요가 없다면 타입을 void로 하면 된다. 그렇다고 void형 메소드에서 return을 사용할 수 없는건 아니다. 리턴할 값이 없더라도 메소드 종료를 위해 사용할 수 있다. 메소드의 진행코드에 따라 return 또는 break를 적절하게 사용하면 된다.

 

한 클래스 내에서 같은 이름의 메소드를 여러개 선언하는 것을 메소드 오버로딩이라고 한다. 단, 매개변수의 타입, 개수, 순서가 같으면 메소드 오버로딩이라고 할 수 없다. 셋 중 적어도 한 가지가 달라야 한다. 메소드 오버로딩에 메소드의 리턴타입의 일치/불일치는 전혀 영향을 주지 않는다. 메소드 오버로딩의 예시 중 하나가 System.out.println() 이다.

 

 

(이 글이 도움이 됐다면 광고 한번씩만 클릭 해주시면 감사드립니다, 더 좋은 정보글 작성하도록 노력하겠습니다 :) )

반응형

'간단 지식 > Java' 카테고리의 다른 글

09. Package와 import  (0) 2020.06.21
08. 정적멤버(static)와 final필드와 상수  (0) 2020.06.20
06. OOP(Object Oriented Programming)의 특징  (0) 2020.05.28
알아두면 편한 클래스  (0) 2020.05.26
알아두면 편한 메소드  (0) 2020.05.26