Back-End (Web)/JAVA

[JAVA] 인스턴스 멤버와 클래스 멤버

JABHACK 2024. 11. 12. 12:36
public class Car {
    // 인스턴스 멤버 (각 객체마다 고유)
    String company; // 자동차 회사
    String model;   // 자동차 모델
    String color;   // 자동차 색상
    double price;   // 자동차 가격
    double speed;   // 자동차 속도, km/h 단위
    char gear;      // 기어 상태, P (주차), R (후진), N (중립), D (주행)
    boolean lights; // 자동차 조명 상태, 켜짐(true) 또는 꺼짐(false)

    // ★클래스 멤버 (모든 객체가 공유하는 값)★
    static int carCount = 0; // 생성된 자동차 객체 수

    // 기본 생성자: 매개변수 없이 Car 객체를 생성
    public Car(String company, String model, String color, double price) {
        this.company = company;
        this.model = model;
        this.color = color;
        this.price = price;
        this.speed = 0;  // 기본 속도 0
        this.gear = 'P'; // 기본 기어 P (주차)
        this.lights = false; // 기본적으로 조명은 꺼짐
        carCount++;  // 객체 생성 시 carCount 증가
    }

    // gasPedal 메서드: 속도를 설정하는 메서드로 kmh 값을 speed 필드에 저장하고 반환
    public double gasPedal(double kmh) {
        speed = kmh; // 자동차의 현재 속도를 kmh 값으로 설정
        return speed; // 설정된 속도 반환
    }

    // brakePedal 메서드: 속도를 0으로 설정하는 메서드로, speed 필드를 0으로 설정하고 반환
    public double brakePedal() {
        speed = 0; // 속도를 0으로 설정하여 정지 상태로 만듦
        return speed; // 속도 0을 반환
    }

    // changeGear 메서드: 기어 상태를 변경하는 메서드로, type 값을 gear 필드에 저장하고 반환
    public char changeGear(char type) {
        gear = type; // 기어를 매개변수 type의 값으로 설정
        return gear; // 설정된 기어 상태 반환
    }

    // onOffLights 메서드: 조명 상태를 반전시키는 메서드로, 현재 lights 값을 반전시키고 반환
    public boolean onOffLights() {
        lights = !lights; // 현재 조명 상태를 반전(true -> false, false -> true)
        return lights; // 변경된 조명 상태 반환
    }

    // horn 메서드: 경적을 울리는 메서드로, 호출 시 "빵빵" 소리를 콘솔에 출력
    public void horn() {
        System.out.println("빵빵"); // 경적 소리 출력
    }

    // ★클래스 메서드 (static): carCount를 출력하는 메서드로, 모든 객체에서 공유★
    public static void showCarCount() {
        System.out.println("총 자동차 객체 수: " + carCount);
    }
}

public class Main {
    public static void main(String[] args) {
        // Car 객체 생성
        Car car1 = new Car("Hyundai", "Sonata", "Red", 25000);
        Car car2 = new Car("Tesla", "Model S", "Black", 80000);
        Car car3 = new Car("Toyota", "Corolla", "Blue", 22000);

        // 각 자동차 객체에서 메서드 호출
        System.out.println("Car1 Speed: " + car1.gasPedal(100));  // Car1의 속도 설정
        System.out.println("Car2 Speed after braking: " + car2.brakePedal()); // Car2의 속도 정지
        System.out.println("Car3 Gear: " + car3.changeGear('D'));  // Car3의 기어 변경

        // 클래스 메서드 호출
        Car.showCarCount();  // 총 자동차 객체 수 출력 (클래스 변수 carCount 사용)

        // 각 자동차의 경적 울리기
        car1.horn();  // "빵빵" 출력
        car2.horn();  // "빵빵" 출력
        car3.horn();  // "빵빵" 출력
    }
}

 

기본적으로 지금까지 사용한 필드와 메서드 전부 인스턴스 맴버였다. 보통 클래스 맴버는 static이라는 메서드를 포함하는데, 이는 특정 인스턴트가 아닌 클래스 자체에 고정적으로 위치시킨다는 의미이다.(위의 ★로 된 코드가 클래스 맴버이다.)

 

간단히 말하면, Static은 전역변수와 유사한 역활을 한다고 생각하면 편하다. 모든 클래스 내의 객체가 공통적으로 가져야하는 값들에 Static을 사용한다. 위의 예시 처럼 '생성된 자동차 수'는 클래스 내에서 한개만 존재하고 이를 모두가 공유하면 됨으로 클래스 맴버에 속한다.

 

 

인스턴스 맴버

  • 인스턴스 멤버는 객체를 생성해야 사용할 수 있다고 했습니다.
  • 또한 객체의 인스턴스 필드는 각각의 인스턴스마다 고유하게 값을 가질 수 있습니다.
  • 그렇다면 객체가 인스턴스화할 때마다 객체의 메서드들은 인스턴스에 포함되어 매번 생성이 될까요?
    • 그렇지 않습니다. 매번 저장한다면 중복 저장으로 인해 메모리 효율이 매우 떨어지기 때문에 메서드는 메서드 영역에 두고서 모든 인스턴스들이 공유해서 사용합니다.
    • 대신 무조건 객체를 생성 즉, 인스턴스를 통해서만 메서드가 사용될 수 있도록 제한을 걸어둔 것입니다.

 

클래스 멤버

클래스는 Java의 클래스 로더에 의해 메서드 영역에 저장되고 사용됩니다.

  • 이때 클래스 멤버란 메서드 영역의 클래스와 같은 위치에 고정적으로 위치하고 있는 멤버를 의미합니다.
  • 따라서 클래스 멤버는 객체의 생성 필요 없이 바로 사용이 가능합니다. 

여기서 중요한게

1. 인스턴스 맴버는 클래스 맴버를 사용 가능하다

2. 클래스 맴버는 인스턴스 맴버를 사용 불가능하다. 

 

이유는 단순히, 인스턴스 맴버는 각 개체마다 값이 달라질 수 있다보니, static으로 전 클래스에 고정되는 전역변수 형태의 클래스 맴버에는 사용 불가능, 간단히, 클래스 맴버는 어떠한 객체든 공통으로 값이 같아야하니 객체마다 값이 다를 수 있는 인스턴스 맴버는 사용이 불가능하다.


<예시>

static String company = "GENESIS"; // 자동차 회사 : GENESIS

String getCompany() {
    return "(주)" + company;
}

 

  • Car 클래스를 통해 제품을 만들 때 만들어지는 자동차들의 회사가 “GENESIS”로 고정되어 있다고 가정해 보겠습니다.
    • 그렇다면 모든 Car 클래스의 객체마다 company 인스턴스 필드를 가지고 있을 필요 없이 클래스 필드로 만들어 공유하게 만든다면 메모리를 효율적으로 사용할 수 있습니다.
    • 또한 인스턴스 메서드인 getCompany()는 클래스 필드인 company를 사용할 수 있습니다.
static String setCompany(String companyName) {
    // System.out.println("자동차 모델 확인: " + model); // 인스턴스 사용 불가
    company = companyName;
    return company;
}
  • 자동차 회사를 변경할 수 있는 setCompany(String companyName)를 클래스 메서드로 만들어서 사용할 수 있습니다.
    • 이때 인스턴스 필드인 model을 사용하려고 하면 오류가 발생합니다.

클래스 맴버 사용


 

Car car = new Car(); // 객체 생성

car.company = "Ferrari";
String companyName2 = car.setCompany("Lamborghini");
  • 참조형 변수를 사용하여 클래스 멤버에 접근은 가능하지만 추천하지 않습니다.
    • 클래스 이름으로 접근하는 것이 좋습니다.

+ car.company에서 .(닷)은 참조 연산자입니다. 이 연산자는 객체의 필드메서드에 접근할 때 사용됩니다. 다시 말해, .은 객체를 통해 해당 객체의 속성이나 메서드에 접근하는 역할을 합니다. = . 은 '참조할게요' 라는 의미( 그렇다고 해서 .이 붙으면 다 참조형 변수라는건 아니다..  )

 

public class Car {

    static String company = "GENESIS"; // 자동차 회사 : GENESIS
    String model; // 자동차 모델
    String color; // 자동차 색상
    double price; // 자동차 가격

    double speed;  // 자동차 속도 , km/h
    char gear; // 기어의 상태, P,R,N,D
    boolean lights; // 자동차 조명의 상태


    public Car() {} // 기본 생성자

    double gasPedal(double kmh, char type) {
        changeGear(type);
        speed = kmh;
        return speed;
    }

    double brakePedal() {
        speed = 0;
        return speed;
    }

    char changeGear(char type) {
        gear = type;
        return gear;
    }

    boolean onOffLights() {
        lights = !lights;
        return lights;
    }

    void horn() {
        System.out.println("빵빵");
    }

    String getCompany() {
        return "(주)" + company;
    }

    static String setCompany(String companyName) {
        // System.out.println("자동차 모델 확인: " + model); // 인스턴스 필드 사용 불가
        company = companyName;
        return company;
    }
}


public class Main {
    public static void main(String[] args) {
        // 클래스 필드 company 확인
        System.out.println(Car.company + "\n");
        // 클래스 필드 변경 및 확인
        Car.company = "Audi";
        System.out.println(Car.company + "\n");

        // 클래스 메서드 호출
        String companyName = Car.setCompany("Benz");
        System.out.println("companyName = " + companyName);

        System.out.println();
        // 참조형 변수 사용
        Car car = new Car(); // 객체 생성

        car.company = "Ferrari";
        System.out.println(car.company + "\n");

        String companyName2 = car.setCompany("Lamborghini");
        System.out.println("companyName2 = " + companyName2);
    }
}

 

 + 이거 헷갈릴 수 있는데, Car.company는 클래스 이름을 사용하여 클래스의 company 이름을 수정한거고, car.company가 Car 객체를 만들고 car가 참조형 변수로서 Car객체의 company 이름을 변경한거다.

 

+ 그러니까 클래스의 내용을 수정한건 Audi고 ferrari는 클래스라는 설계도를 기반으로한 객체 Car의 내용을 수정한거다


지역 변수


  • 메서드 내부에 선언한 변수를 의미합니다.
  • 메서드가 실행될 때마다 독립적인 값을 저장하고 관리하게 됩니다.
  • 지역 변수는 메서드 내부에서 정의될 때 생성되어 메서드가 종료될 때까지만 유지됩니다.
public class Main {
    public static void main(String[] args) {
        Main main = new Main();

        // 메서드 호출 : main.getClass()
        System.out.println("main.getClass() = " + main.getNumber());
        System.out.println("main.getClass() = " + main.getNumber());
        System.out.println("main.getClass() = " + main.getNumber());
    }

    public int getNumber() {
        int number = 1; // 지역 변수
        number += 1;
        return number; // 메서드 종료되면 지역변수 제거됨
    }
}

// 출력
//main.getNumber() = 2
//main.getNumber() = 2
//main.getNumber() = 2

final 필드와 상수


final은 ‘최종적’ 이라는 의미입니다.

  • final 필드는 초기값이 저장되면 해당값을 프로그램이 실행하는 도중에는 절대로 수정할 수 없습니다.
  • 또한 final 필드는 반드시 초기값을 지정해야 합니다. 
  • 말 그대로 변경 불가 필드
final String company = "GENESIS";

...

Car car = new Car();
System.out.println(car.company);
  • 필드 타입 앞에 final 키워드를 추가하여 final 필드를 선언할 수 있습니다.
  • 사용방법은 일반적인 인스턴스 필드와 동일합니다. 다만 수정이 불가능합니다.
    • car.company = "Benz"; 이렇게 수정하려 하면 오류가 발생합니다.

상수

  • 상수의 특징은 값이 반드시 한 개이며 불변의 값을 의미합니다.
  • 따라서 인스턴스마다 상수를 저장할 필요가 없습니다.
  • 그냥 final이 붙은 변수는 상수가 된다.
static final String COMPANY = "GENESIS";

...

System.out.println(Car.COMPANY);
  • final 앞에 static 키워드를 추가하여 모든 인스턴스가 공유할 수 있는 값이 한 개이며 불변인 상수를 선언할 수 있습니다.
  • 사용방법은 일반적인 클래스 필드와 동일합니다. 다만 수정이 불가능합니다.
    • Car.COMPANY = "Benz"; 이렇게 수정하려 하면 오류가 발생합니다.
  • 일반적으로 상수는 대문자로 작성하는 것이 관례입니다.

+ static도 변수로 만들면 바꿀 수 있고 상수로 만들면 못 변경하기도 한다.

'Back-End (Web) > JAVA' 카테고리의 다른 글

[JAVA] This와 This()  (0) 2024.11.12
[JAVA] 생성자  (1) 2024.11.12
[JAVA] 객체의 필드와 메서드  (0) 2024.11.12
[JAVA] 클래스 설계와 객체 생성  (0) 2024.11.12
[JAVA] 객체지향 프로그래밍  (1) 2024.11.12