자바 클래스

U_U0_0·2022년 5월 4일
0
post-thumbnail

TCP SCHOOL - 자바 정리 #4

클래스

객체 지향 프로그래밍(OOP, Object-Oriented Programming)에서는 모든 데이터를 객체(object)로 취급한다. 객체의 상태(state)와 행동(behavior)을 구체화하는 형태의 프로그래밍이 객체 지향 프로그래밍이다. 이 때 객체를 만들어 내기 위한 설계도와 같은 개념을 클래스(class)라고 한다.

클래스(class)

객체를 정의하는 틀 또는 설계도와 같은 의미. 자바에서는 이러한 설계도인 클래스를 가지고, 여러 객체를 생성하여 사용한다.
클래스는 객체의 상태를 나타내는 필드(field)와 객체의 행동을 나타내는 메소드(method)로 구성된다.
필드란 클래스에 포함된 변수(variable)를 의미하고, 메소드란 어떠한 특정 작업을 수행하기 위한 명령문의 집합이다.

인스턴스(instance)

자바에서 클래스를 사용하기 위해서는 우선 해당 클래스 타입의 객체를 선언해야 한다. 이렇게 클래스로부터 객체를 선언하는 과정을 클래스의 인스턴스 화라고 하며, 이렇게 선언된 해당 클래스 타입의 객체가 바로 인스턴스이다.
즉, 인스턴스란 메모리에 할당된 객체를 의미한다.

자바에서는 하나의 클래스로부터 여러 개의 인스턴스를 생성할 수 있고, 이렇게 생성된 인스턴스는 독립된 메모리 공간에 저장된 자신만의 필드를 가질 수 있다.
해당 클래스에서 생성된 모든 인스턴스는 해당 클래스의 모든 메소드를 공유한다.

클래스의 구성

class Car {                    // 클래스 이름
    private String modelName;  // 필드
    private int modelYear;     // 필드

    Car(String modelName, int modelYear) { // 생성자
        this.modelName = modelName;
        this.modelYear = modelYear;
    }

    public String getModel() { // 메소드
        return this.modelYear + "년식 " + this.modelName + " " + this.color;
    }
}

자바에서 생성자(constructor)의 이름은 해당 클래스의 이름과 같아야 한다.

즉, Car 클래스의 생성자는 Car()

인스턴스 생성

객체를 참조하기 위한 참조 변수 선언 후, new 키워드를 사용해 인스턴스를 생성하고 해당 인스턴스의 주소를 미리 선언한 참조 변수에 저장하여 사용.
또는 참조 변수의 선언과 인스턴스의 생성을 동시에 진행

Car myCar;
myCar = new Car();

//

Car myCar = new Car();

메소드

class Car {
    private int currentSpeed;
    private int accelerationTime;

    public void accelerate(int speed, int second) {
        System.out.println(second + "초간 속도를 시속 " + speed + "(으)로 가속함!!");
    }
}

public class Method01 {
    public static void main(String[] args) {
        Car myCar = new Car();   // 객체 생성
        myCar.accelerate(60, 3); // 메소드 호출
    }
}

// 3초간 속도를 시속 60(으)로 가속함!!

생성자

Car(String modelName, int modelYear, String color, int maxSpeeds) {
    this.modelName = modelName;
    this.modelYear = modelYear;
    this.color = color;
    this.maxSpeed = maxSpeed;
    this.currentSpeed = 0;
}

자바에서는 new 키워드를 사용하여 객체를 생성할 때 자동으로 생성자가 호출된다.

public class Method02 {
    public static void main(String[] args) {
        Car myCar = new Car("아반떼", 2016, "흰색", 200); // 생성자의 호출
        System.out.println(myCar.getModel()); // 생성자에 의해 초기화되었는지를 확인함.
    }
}

// 2016년식 아반떼 흰색

this, this()

this 참조 변수

this 참조 변수는 인스턴스가 바로 자기 자신을 참조하는 데 사용하는 변수이며, 해당 인스턴스의 주소를 가리킨다.

자바에서는 this 참조 변수를 사용하여 인스턴스 변수에 접근할 수 있다. this 참조 변수를 사용할 수 있는 영역은 인스턴스 메소드뿐이며, 클래스 메소드에서는 사용할 수 없다.
모든 인스턴스 메소드에는 this 참조 변수가 숨겨진 지역 변수로 존재하고 있다.

this() 메소드

this() 메소드는 생성자 내부에서만 사용할 수 있으며, 같은 클래스의 다른 생성자를 호출할 때 사용한다. this() 메소드에 인수를 전달하면 생성자 중에서 메소드 시그니처가 일치하는 다른 생성자를 찾아 호출한다.

class Car {
    private String modelName;
    private int modelYear;
    private String color;
    private int maxSpeed;
    private int currentSpeed;

    Car(String modelName, int modelYear, String color, int maxSpeed) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.color = color;
        this.maxSpeed = maxSpeed;
        this.currentSpeed = 0;
    }

    Car() {
        this("소나타", 2012, "검정색", 160); // 다른 생성자를 호출함.
    }
    
    public String getModel() {
        return this.modelYear + "년식 " + this.modelName + " " + this.color;
    }
}

public class Method05 {
    public static void main(String[] args) {
        Car tcpCar = new Car(); System.out.println(tcpCar.getModel());
    }
}

// 2012년식 소나타 검정색

내부적으로 다른 생성자를 호출하여 인스턴스 변수를 초기화할 수 있다.

메소드 오버로딩

같은 이름의 메소드를 중복하여 정의하는 것.
자바에서는 원래 한 클래스 내에 같은 이름의 메소드를 둘 이상 가질 수 없으나, 매개변수의 개수나 타입을 다르게 하면, 하나의 이름으로 메소드를 작성할 수 있다. 즉, 메소드 오버로딩은 서로 다른 시그니처를 갖는 여러 메소드를 같은 이름으로 정의하는 것이다.

메소드 시그니처란 메소드의 선언부에 명시되는 매개변수의 리스트를 가리키며, 두 메소드의 매개변수 개수와 타입, 그 순서까지 모두 같다면 이 두 메소드의 시그니처는 같다고 할 수 있다.

메소드 오버로딩은 객체 지향 프로그래밍의 특징 중 하나인 다형성(polymorphism)을 구현하는 방법 중 하나이다.

메소드 오버로딩은 반환 타입과는 관계가 없다. 메소드의 시그니처는 같은데 반환 타입만 다른 경우에는 오버로딩이 성립하지 않는다.

자바에서 char형 데이터는 int형 뿐만 아니라 double형으로도 타입 변환될 수 있기 때문에 어느 시그니처의 메소드를 호출해야 할지 불명확하다.
이런 경우 더 작은 표현 범위를 가지는 int형으로 자동 타입 변환하게 된다.
class Test {
    static void display(int num1) { System.out.println(num1); }static void display(int num1, int num2) { System.out.println(num1 * num2); }
    static void display(int num1, double num2) { System.out.println(num1 + num2); }
}

public class Method06 {
    public static void main(String[] args) {
        Test myfunc = new Test();

        myfunc.display(10);
        myfunc.display(10, 20);
        myfunc.display(10, 3.14);
②      myfunc.display(10, 'a');
    }
}

// 10
// 200
// 13.14
// 970 (영문 소문자 'a'의 아스키 코드값 97)

접근 제어자

접근 제어자같은 클래스 멤버같은 패키지 멤버자식 클래스 멤버그 외 영역
public
protectedX
defaultXX
privateXXX

기타 제어자

final 제어자

자바에서 final 제어자는 '변경할 수 없다'는 의미로 사용된다.
즉, 필드나 지역 변수에 사용하면 값을 변경할 수 없는 상수(constant)가 된다.
또한, 클래스에 사용하면 해당 클래스는 다른 클래스가 상속받을 수 없게 되며, 메소드에 사용하면 해당 메소드는 오버라이딩(overriding)을 통한 재정의를 할 수 없게 된다.

static 제어자

자바에서 static 제어자는 '공통적인'이라는 의미로 사용된다.
즉, static 제어자를 변수에 사용하면 해당 변수를 클래스 변수로 만들어준다.

static 제어자를 가지는 멤버는 다음과 같은 특징을 가진다.

  1. 프로그램 시작시 최초에 단 한 번만 생성되고 초기화된다.
  2. 인스턴스를 생성하지 않고도 바로 사용할 수 있다.
  3. 해당 클래스의 모든 인스턴스가 공유한다.

abstract 제어자

자바에서 abstract 제어자는 '추상적인'이라는 의미로 사용된다.
선언부만 있고 구현부가 없는 메소드를 추상 메소드라고 하며, 반드시 abstract 제어자를 붙여야 한다. 또한, 하나 이상의 추상 메소드를 포함하는 추상 클래스도 반드시 abstract 제어자를 붙여야 한다.

함께 사용할 수 없는 제어자들

  1. 클래스에 final과 abstract는 함께 사용할 수 없다.
    : final 제어자를 가지는 클래스는 다른 클래스가 상속받을 수 없게 되며, abstract 제어자를 가지는 클래스는 다른 클래스가 상속해서 오버라이딩해야만 사용할 수 있으므로, 이 두 제어자는 클래스에 함께 사용할 수 없다.

  2. 메소드에 static과 abstract는 함께 사용할 수 없다.
    : abstract 제어자를 가지는 메소드는 선언부만 있고 구현부가 없는 메소드인데, static 제어자를 가지는 메소드는 인스턴스를 생성하지 않고도 바로 사용할 수 있어야 하므로, 이 두 제어자는 메소드에 함께 사용할 수 없다.

  3. 메소드에 private과 abstract는 함께 사용할 수 없다.
    : abstract 제어자를 가지는 메소드는 다른 클래스가 상속하여 오버라이딩해야만 사용할 수 있는데, private 제어자를 가지는 메소드는 자식 클래스에서 접근할 수 없게 되므로, 이 두 제어자는 메소드에 함께 사용할 수 없다.

  4. 메소드에 private과 final은 함께 사용할 필요가 없다.
    : 메소드에 사용된 final 제어자와 private 제어자는 모두 해당 메소드가 오버라이딩을 통한 재정의를 할 수 없다는 의미를 가지므로, 둘 중에 하나만 사용해도 의미가 충분히 전달될 수 있다.

클래스의 멤버

필드

클래스 내에서 필드는 선언된 위치에 따라 3가지로 구분된다.

  1. 클래스 변수(static variable)
  2. 인스턴스 변수(instance variable)
  3. 지역 변수(local variable)
class Car {
    static int modelOutput; // 클래스 변수
    String modelName;       // 인스턴스 변수

    void method() {
        int something = 10; // 지역 변수
    }
}

클래스 변수와 인스턴스 변수는 초기화 하지 않아도 변수의 타입에 맞게 자동으로 초기화 되지만, 지역 변수는 사용하기 전에 초기화하지 않으면 자바 컴파일러가 오류를 발생시킨다.

클래스 영역에 위치한 변수 중 static 키워드를 가지는 변수가 클래스 변수, 가지지 않는 변수가 인스턴스 변수이다.
또한, 메소드나 생성자, 초기화 블록 내에 위치한 변수는 지역 변수이다.

클래스 변수는 해당 클래스의 모든 인스턴스가 공유해야 하는 값을 유지하기 위해 사용되고, 인스턴스 변수는 인스턴스마다 가져야 하는 고유한 값을 유지하기 위해 사용된다.

class Field {

    static int classVar = 10; // 클래스 변수 선언

    int instanceVar = 20;     // 인스턴스 변수 선언

}

 

public class Member01 {
    public static void main(String[] args) {
        int var = 30;                   // 지역 변수 선언
        
        System.out.println(var + "\n"); // 지역 변수 참조

        Field myField1 = new Field();   // 인스턴스 생성
        Field myField2 = new Field();   // 인스턴스 생성

        System.out.println(Field.classVar); // 클래스 변수 참조
        System.out.println(myField1.classVar);
        System.out.println(myField2.classVar + "\n");

        myField1.classVar = 100;            // 클래스 변수의 값을 변경

        System.out.println(Field.classVar); // 클래스 변수 참조
        System.out.println(myField1.classVar);
        System.out.println(myField2.classVar + "\n");

        System.out.println(myField1.instanceVar); // 인스턴스 변수 참조
        System.out.println(myField2.instanceVar + "\n");

        myField1.instanceVar = 200;               // 인스턴스 변수의 값을 변경

        System.out.println(myField1.instanceVar); // 인스턴스 변수 참조
        System.out.println(myField2.instanceVar);
    }
}

// 30

// 10
// 10
// 10

// 100
// 100
// 100

// 20
// 20

// 200
// 20

메소드

클래스 내에서 메소드는 static 키워드의 여부에 따라 2가지로 구분된다.

  1. 클래스 메소드(static method)
  2. 인스턴스 메소드(instance method)
class Car {
    boolean door;                       // 인스턴스 변수

    void openDoor() {                   // 인스턴스 메소드
        door = true;
    }

    static void toggleDoor(boolean d) { // 클래스 메소드
        return !d;
    }
}

클래스 메소드는 메소드 내부에서 인스턴스 변수를 사용할 수 없다.
메소드 내부에서 인스턴스 변수나 인스턴스 메소드를 사용하지 않는 메소드를 클래스 메소드로 정의하는 것이 일반적이다. 클래스 메소드는 전달된 매개변수만으로 동작한다.

class Method {
    int a = 10, b = 20;                            // 인스턴스 변수

    int add() { return a + b; }                    // 인스턴스 메소드

    static int add(int x, int y) { return x + y; } // 클래스 메소드

}

public class Member02 {
    public static void main(String[] args) {
        System.out.println(Method.add(20, 30)); // 클래스 메소드의 호출
        Method myMethod = new Method();         // 인스턴스 생성
        System.out.println(myMethod.add());     // 인스턴스 메소드의 호출
    }
}

// 50
// 30

필드의 초기화

필드의 초기화 순서

  1. 클래스 변수 : 기본값 → 명시적 초기화 → 클래스 초기화 블록
  2. 인스턴스 변수 : 기본값 → 명시적 초기화 → 인스턴스 초기화 블록 → 생성자
class InitBlock {
    static int classVar = 10;         // 클래스 변수의 명시적 초기화
    int instanceVar = 10;             // 인스턴스 변수의 명시적 초기화

    static { classVar = 20; }         // 클래스 초기화 블록을 이용한 초기화
    
    { instanceVar = 20; }             // 인스턴스 초기화 블록을 이용한 초기화
    
    InitBlock() { instanceVar = 30; } // 생성자를 이용한 초기화
}

public class Member05 {
    public static void main(String[] args) {
        System.out.println(InitBlock.classVar);
        InitBlock myInit = new InitBlock();
        System.out.println(myInit.instanceVar);
    }
}

// 20
// 30
profile
u0u0u0

0개의 댓글

관련 채용 정보