프로그래밍/JAVA

[JAVA] 클래스

daykim 2023. 1. 14. 22:43
이것이 자바다(개정판) 기반 정리

목차

  • 객체 지향 프로그래밍
  • 객체와 클래스
  • 클래스 선언
  • 객체 생성과 클래스 변수
  • 클래스 구성 멤버
  • 필드 선언과 사용
  • 생성자 선언과 호출
  • 메소드 선언과 호출
  • 인스턴스 멤버
  • 정적 멤버
  • final 필드와 상수
  • 패키지
  • 접근 제한자
  • Getter와 Setter
  • 싱글톤 패턴

 

객체 지향 프로그래밍 (Object Oriented Programming, OOP)


개발할 때 부품에 해당하는 객체들을 먼저 만들고, 이 객체들을 하나씩 조립해 완성된 프로그램을 만드는 기법

객체 (Object)

물리적으로 존재하거나 개념적인 것 중, 다른것과 식별 가능한 것

  • 객체는 속성과 동작으로 구성된다.
    ex) 사람의 속성은 이름, 나이등이 있고, 동작으론 걷기, 뛰기 등이 있다.
  • 자바에선 이를 필드와 메소드라고 한다.

 

객체의 상호작용

객체 지향 프로그램에서 객체들은 다른 객체와 서로 상호작용하며 동작한다.
객체들 사이의 상호작용 수단은 메소드다.

 

객체 간의 관계

  • 집합 관계 : 완성품과 부품의 관계
  • 사용 관계 : 다른 객체의 필드를 읽고 변경, 메소드를 호출하는 관계
  • 상속 관계 : 부모와 자식 관계

 

객체 지향 프로그래밍 특징

  • 캡슐화 (Encapsulation)
    • 객체의 데이터, 동작을 하나로 묶고, 실제 구현 내용을 외부에 감추는 것이다.
    • 외부 객체는 내부 구조를 알지 못하고 제공되는 필드와 메소드만 사용할 수 있다.
  • 상속 (Inheritance)
    • 부모 역할의 상위 객체와 자식 역할의 하위 객체가 있다.
      부모 객체는 자기가 가지고 있는 필드와 메소드를 자식 객체에게 물려주어 자식 객체가 사용할 수 있도록 하는 것이다.
    • 코드의 재사용성을 높여준다.
    • 유지 보수 시간을 최소화 시켜준다.
  • 다형성 (Polymorphism)
    • 같은 타입이지만 실행 결과가 다양하게 나오는 성질을 말한다.
    • 참고

 

객체와 클래스


클래스

객체를 생성하기 위한 설계도

인스턴스

클래스로부터 생성된 객체를 해당 클래스의 인스턴스라고 한다.

인스턴스화

클래스로부터 객체를 만드는 과정

 

클래스 선언


  • 생성자 : 객체 생성
  • 필드 : 객체가 가져야 할 데이터
  • 메소드 : 객체의 동작
public class 클래스명 {
}
  • 클래스명은 첫 문자를 대문자로 하고, 캐멀 스타일로 작성
  • 숫자 포함 가능하지만 첫 문자로는 할 수 없다.
  • 특수문자 $ _ 가능
  • 하나의 소스파일에 여러개의 클래스 선언 포함 가능
    해당 소스파일을 컴파일하면, 클래스 선언 수만큼 바이트 코드 파일(.class)가 생긴다.
  • 여러 개의 클래스 선언 시, 소스 파일명과 동일한 클래스만 public class로 선언 가능

 

객체 생성과 클래스 변수


Class 객체 생성

클래스명 변수명 = new 클래스명();
  • 변수명과 객체의 주소는 stack 영역에 저장
  • 객체는 heap 영역에 저장

클래스의 두 가지 용도

  • 라이브러리(library) 클래스 : 실행할 수 없고, 다른 클래스에서 이용하는 클래스
  • 실행 클래스 : main() 메소드를 가지고 있는 실행 가능한 클래스

 

클래스의 구성 멤버


  • 생성자  : 객체 생성 시 초기화 역할 담당
  • 필드  : 객체 생성시 데이터가 저장되는 곳
  • 메소드 : 객체의 동작으로 호출 시 실행하는 블록

 

필드 선언과 사용


필드 선언

타입 필드명 [ = 초기값];
// [] 있을수도 없을수도
  • 기본타입, 참조타입 모두 가능
  • 필드명 첫 문자는 소문자로하고, 캐멀 스타일로 작성하는 것이 관례
  • 초기값 제공하지 않으면, 자동으로 기본값으로 초기화 된다.

필드 사용

필드값을 읽고 변경하는 것

필드는 객체의 데이터이므로, 객체가 존재하지 않으면 필드도 존재하지 않는다.
따라서 클래스로부터 객체가 생성된 후에 필드를 사용할 수 있다.

필드는 객체 내부의 생성자, 메소드 내부, 객체 외부에서 접근해 사용 가능하다.

public class Car{
    int speed;
}

public class CarExample{
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.speed = 0;
    }
}
  • . (도트) : 객체 접근 연산자
  • 객체 외부에서는 도트로 접근해야한다.

 

생성자 선언과 호출


new 연산자

객체 생성 후 생성자를 호출해 객체를 초기화 한다.
필드 초기화를 하거나 메소드를 호출해 객체를 사용할 준비를 하는 것이다.
생성자가 성공적으로 실행이 끝나면 new 연산자는 객체의 주소를 리턴한다.
리턴된 주소는 클래스 변수에 대입돼 객체의 필드나 메소드에 접근할 때 이용한다.

 

기본 생성자

  • 모든 클래스에 생성자가 존재한다.
  • 클래스에 생성자 선언이 없으면 컴파일러는 기본 생성자를 바이트코드 파일에 자동으로 추가시킨다.
  • 클래스가 public으로 선언되면, 생성자도 public이 붙는다.

 

생성자 선언

클래스명(매개변수, ...){
    객체의 초기화 코드
}

 

this

현재 객체를 말한다.

  • ex) 생성자에서 매개변수와 필드의 이름이 같을 때 사용한다.
  • this.필드 = 매개변수

 

생성자 오버로딩

매개변수를 달리하는 생성자를 여러 개 선언하는 것이다.
new 연산자로 생성자를 호출할 때 제공되는 매개값의 타입과 수에 따라 실행될 생성자가 결정된다.

 

다른 생성자 호출

생성자에서 this(...)를 생성해 다른 생성자를 호출하는 방법이다.

Car(String model){
    this(model, "은색", 250);
}

Car(String model, String color, int speed)
    this.model = model;
    this.color = color;
    this.speed = speed;
}
  • 생성자 오버로딩이 많아질 때, 생성자 간의 공통 코드를 가진 생성자를 호출해
    중복된 코드가 발생하는 것을 막을 수 있다.
  • this(...)는 생성자의 첫 줄에 작성된다.

 

메소드 선언과 호출


메소드는 객체 내부에서도 호출되지만, 다른 객체에서도 호출될 수 있기 때문에 객체간의 상호작용하는 방법을 정의하는 것이다.

메소드 선언

객체의 동작을 실행 블록으로 정의하는 것이다.

메소드 호출

실행 블록을 실제로 실행하는 것이다.

메소드는 객체의 동작이므로 객체가 존재하지 않으면, 메소드를 호출할 수 없다.
메소드는 생성자와 다른 메소드 내부에서 호출될 수 있고, 객체 외부에서도 호출될 수 있다.
객체 내부에서는 메소드 명으로만 실행 가능하지만, 외부에선 참조 변수와 도트 연산자를 이용해 호출한다.

 

가변길이 매개변수

메소드가 가변길이 매개변수를 가진다면, 매개변수 개수와 상관없이 매개값을 줄 수 있다.
메소드 호출 시 매개값을 쉽표로 구분해 개수 상관없이 제공 가능하다.

// 가변길이 매개변수 선언
int sum(int ... values) {
}

int result = sum(1, 2, 3);

int answer = sum(new int[] {1, 2, 3});

int values = {1, 2, 3};
int ans = sum(values);

 

메소드 오버로딩

메소드 이름은 같되 매개변수 타입, 개수, 순서가 다른 메소드를 여러개 선언하는 것이다.

다양한 매개값을 처리하기 위해 사용한다.

Class 클래스 {
    void println() {...}
    
    void println(int x) {...}
    
    void println(int x, string s) {...}
}

 

인스턴스 멤버


객체에 소속된 멤버

객체를 생성해야 사용 가능한 멤버다.

public class Car {
    // 인스턴스 필드 선언
    int gas;
    
    // 인스턴스 메소드 선언
    void setSpeed(int speed);
}

 

정적 멤버


자바는 클래스 로더를 이용해 클래스를 메소드 영역에 저장하고 사용한다.
정적 멤버란 메소드 영역의 클래스에 고정적으로 위치하는 멤버다.
따라서 정적 멤버는 객체를 생성할 필요 없이 클래스를 통해 바로 사용이 가능하다.

메소드 영역정적 필드정적 메소드가 저장된다.

정적 멤버 선언

public class 클래스 {
    // 정적 필드 선언
    static 타입 필드 [= 초기값];
    
    // 정적 메소드
    static 리턴타입 메소드(매개변수, ...) {}
}
  • 객체마다 가지고 있을 필요성 없이, 공용적인 필드는 정적 필드로 선언하는게 좋다.
  • 인스턴스 필드를 사용하지 않는 메소드는 정적 메소드로 선언하는 것이 좋다.

 

정적 멤버 사용

클래스 이름과 도트 연산자로 접근하면 된다.

public sclass Calculator {
    static int plus(int x, int y) {...}
}

int result = Calculator.plus(10, 5);
  • 인스턴스로도 접근 가능하지만, 클래스 이름으로 접근하는 것이 정석이다. -> 경고 표시 나온데
    객체 자신의 참조인 this도 사용 불가다.

 

정적 블록

정적 필드가 복잡한 초기화 작업이 필요할 때 이용한다.

static {
    ....
}

// ex
public class TV {
    static String name = "day";
    static String last = "kim";
    static String full;
    
    static {
        full = name + "-" + last;
    }
}
  • 정적 블록은 클래스가 메모리로 로딩될 때 자동으로 실행된다.
  • 정적 블록이 클래스 내부에 여러개가 선언되어 있으면, 순서대로 실행한다.
  • 정적 필드는 객체 생성 없이 사용 가능하기 때문에, 생성자에서 직접 초기화 작업을 하지 않는다.
    생성자는 객체 생성 후 실행되기 때문이다.

 

final 필드와 상수


final 필드는 초기값이 저장되면 이것이 최종적인 값이 되어, 프로그램 실행 도중에 수정할 수 없다.

final 타입 필드이름 [=초기값];

 

final 필드에 초기값 주는 방법

  1. 필드 선언시 초기값 대입
  2. 생성자에서 초기값 대입

 

상수

불변의 값을 저장하는 필드
ex) 원주율 파이

static final 타입 상수이름 [= 초기값];
  • 객체마다 저장할 필요가 없고, 여러 개의 값을 가져도 안 되기 때문에 static 이면서 final이다.
  • 초기값은 선언시 주는 것이 일반적이다.
  • 복잡한 초기화가 필요하다면 정적 블록에서 초기화 가능하다.
  • 정적 필드이므로 클래스로 접근해 읽을 수 있다.

 

패키지


클래스의 일부분이며, 클래스를 식별하는 용도로 사용된다.

상위패키지와 하위 패키지를 도트(.)로 구분한다.
물리적으로 하위 패키지다.

패키지에 속한 바이트코드 파일(~.class)은 다른 디렉토리로 이동할 수 없다.
com.my 패키지에 소속된 바이트 코드 파일을 다른 디렉토리에 옮겨 저장할 경우 사용할 수 없다.

 

import 문

다른 패키지에 있는 클래스를 사용하려면 import 문을 이용해 어떤 패키지의 클래스를 사용하는지 명시해야 한다.

  • import 문은 하위 패키지를 포함하지 않기 때문에 모두 작성하던가 *을 사용한다.
  • 만약 서로 다른 패키지에 같은 클래스 이름이 존재한다면, 클래스 전체이름을 정확히 명시해 사용해야 한다.
    p.259

 

접근 제한자 (Access Modifier)


경우에 따라 객체의 필드를 외부에서 변경하거나 메소드를 호출할 수 없도록 막는 기능이다.
중요한 필드와 메소드가 노출되지 않도록, 객체의 무결성을 유지하기 위해서다.

접근 제한자 제한 대상 제한 범위
public 클래스, 필드, 생성자, 메소드 없다.
protected 필드, 생성자, 메소드 같은 패키지
자식 객체
default 클래스, 필드, 생성자, 메소드 같은 패키지
private 필드, 생성자, 메소드 객체 내부

 

Getter와 Setter


객체의 필드를 외부에서 마음대로 읽고 변경할 경우, 객체의 무결성이 깨질 수 있다.
이러한 문제점 때문에 객체 지향 프로그래밍에서는 직접적인 외부에서의 필드 접근을 막는다.
대신 메소드를 통해 필드에 접근하는 것을 선호한다.

  • Setter : 메소드를 통해 필드에 접근하는 역할의 메소드
  • Getter : 외부에서 객체의 필드를 읽을 때 사용하는 메소드

 

싱글톤 패턴


애플리케이션 전체에서 단 한개의 객체만 생성해 사용할 때 적용하는 패턴이다.

  • 생성자를 private 접근 제한해 외부에서 new 연산자로 생성자를 호출할 수 없도록 막는 것이다.
  • 대신 싱글톤 패턴이 제공하는 정적 메소드를 통해 간접적으로 객체를 얻을 수 있다.

ex)

public class 클래스 {
    private static 클래스 singleton = new 클래스();
    
    private 클래스() {}
    
    public static 클래스 getInstance() {
        return singleton;
    }
}


클래스 변수1 = 클래스.getInsctance();
클래스 변수2 = 클래스.getInsctance();
  • 클래스 내부에 자신의 타입으로 정적필드를 선언하고, 미리 객체 생성해 초기화 시킨다.
    private으로 외부에서 정적 필드값을 변경하지 못하도록 막는다.
  • 정적 필드값을 반환하는 getInstance() 정적 메소드를 public으로 선언했다.
    외부에서 객체를 얻는 유일한 방법은 이메소드를 호출하는 것이다.
  • 맨 아래 변수1, 변수2는 같은 객체를 참조하고 있다.

'프로그래밍 > JAVA' 카테고리의 다른 글

[Java] 상속  (0) 2023.09.12
[Java] Static  (0) 2023.06.30
[JAVA] 참조 타입  (2) 2022.11.08
[JAVA] 조건문과 반복문  (0) 2022.10.12
[JAVA] 연산자  (1) 2022.10.11