[백기선님_자바_스터디] 5주차 - 클래스

시나브로·2021년 7월 16일
0
post-thumbnail

1. 클래스 정의하는 방법



클래스는 객체지향 프로그래밍(Object-oriented programming)에서 객체를 생성하기 위해 상태(state)와 행동(behavior)을 정의하는 일종의 설계도다.

여기서 객체란 어플리케이션의 기능을 구현하기 위해 서로 협력하는 개별적인 실체로써 물리적일 수도 있고 개념적일 수도 있다.

객체의 상태와 행동이 정의된 하나의 클래스로 비슷한 구조를 갖되 상태는 서로 다른 여러 객체를 만들 수 있다.


1.1 구조

class Class {               // 클래스
    String constructor;
    String instanceVar;     // 인스턴스 변수
    static String classVar; // 클래스 변수

    static {                // 클래스 초기화 블록
        classVar = "Class Variable";
    }

    {                       // 인스턴스 초기화 블록
        instanceVar = "Instance Variable";
    }

    Class() {                // 생성자
        constructor = "Constructor";
    }

    void instanceMethod() {       // 인스턴스 메서드
        System.out.println(instanceVar);
    }

    static void classMethod() {   // 클래스 메서드
        System.out.println(classVar);
    }
}
  • 필드(field)

    • 필드는 해당 클래스 객체의 상태 속성을 나타내며, 멤버 변수라고도 불린다.
    • 여기서 초기화하는 것을 필드 초기화 또는 명시적 초기화라고 한다.
  • 인스턴스 변수

    • 이름에서 알 수 있듯이 인스턴스가 갖는 변수이다.
    • 그렇기에 인스턴스를 생성할 때 만들어진다.
    • 서로 독립적인 값을 갖으므로 heap 영역에 할당되고 gc에 의해 관리된다.
  • 클래스 변수

    • 정적을 의미하는 static키워드가 인스턴스 변수 앞에 붙으면 클래스 변수이다.
    • 해당 클래스에서 파생된 모든 인스턴스는 이 변수를 공유한다.
    • 그렇기 때문에 heap 영역이 아닌 static 영역에 할당되고 gc의 관리를 받지 않는다.
      • JDK8 부터 변경. static이 저장되는 공간 변경 및 gc 관리 받는다
    • public 키워드까지 앞에 붙이면 전역 변수라 볼 수 있다.
  • 메서드(method)

    • 메서드는 해당 객체의 행동을 나타내며, 보통 필드의 값을 조정하는데 쓰인다.
  • 인스턴스 메서드

    • 인스턴스 변수와 연관된 작업을 하는 메서드이다.
    • 인스턴스를 통해 호출할 수 있으므로 반드시 먼저 인스턴스를 생성해야 한다.
  • 클래스 메서드

    • 정적 메서드라고도 한다.
    • 일반적으로 인스턴스와 관계없는 메서드를 클래스 메서드로 정의한다.
  • 생성자(constructor)

    • 생성자는 객체가 생성된 직후에 클래스의 객체를 초기화하는 데 사용되는 코드 블록이다.
    • 메서드와 달리 리턴 타입이 없으며, 클래스엔 최소 한 개 이상의 생성자가 존재한다.
  • 초기화 블록(initializer)

    • 초기화 블록 내에서는 조건문, 반복문 등을 사용해 명시적 초기화에선 불가능한 초기화를 수행할 수 있다.
      • 클래스 초기화 블록 - 클래스 변수 초기화에 쓰인다.
      • 인스턴스 초기화 블록 - 인스턴스 변수 초기화에 쓰인다.
      • 클래스 변수 초기화: 기본값 → 명시적 초기화 → 클래스 초기화 블록
      • 인스턴스 변수 초기화: 기본값 → 명시적 초기화 → 인스턴스 초기화 블록 → 생성자
  • 접근 제어자
    • public, protected, default, private
  • 그 외
    • static
      • 변수, 메서드는 객체가 아닌 클래스에 속한다.
    • final
      • 클래스 앞에 붙으면 해당 클래스는 상속될 수 없다.
      • 변수 또는 메서드 앞에 붙으면 수정되거나 오버라이딩 될 수 없다.
    • abstract
      • 클래스 앞에 붙으면 추상 클래스가 되어 객체 생성이 불가하고, 접근을 위해선 상속받아야 한다.
      • 변수 앞에 지정할 수 없다.
      • 메서드 앞에 붙는 경우는 오직 추상 클래스 내에서의 메서드밖에 없으며 해당 메서드는 선언부만 존재하고 구현부는 상속한 클래스 내 메서드에 의해 구현되어야 한다.
    • transient
      • 변수 또는 메서드가 포함된 객체를 직렬화할 때 해당 내용은 무시된다.
    • synchronized
      • 메서드는 한 번에 하나의 쓰레드에 의해서만 접근 가능하다.
    • volatile
      • 해당 변수의 조작에 CPU 캐시가 쓰이지 않고 항상 메인 메모리로부터 읽힌다.



1.2 내부 클래스 (Inner Class)


내부 클래스는 일반적으로, 상위 클래스와 밀접환 연관이 있을 때 사용한다.
public class ListNodeStack { // 일반적인 클래스, 외부 클래스
    Node topNode; // 내부클래스 Node 객체를 생성

    @Getter
    class Node{ // 내부 클래스
        int data;
        Node next;

        public Node (int data){
            this.data = data;
        }
    }
}

1.3 익명 클래스


익명 클래스는 이름이 지정되어 있지 않은 클래스를 의미한다.


1.3.1 인터페이스 implements 사용법

public interface Monster{
    String getName();
} 
public static void main(String args[]){
    Monster monster = new Monster(){
        String name;
        public String getName(){
            return name;
        }
    };
    System.out.println(monster.getName());
}

1.3.2 익명 클래스 상속 사용법

public class Pet{
    String name = "돼지";
    public String getName(){
            return name;
    }
}
public static void main(String[] args){
    Pet pet = new Pet(){
            String name = "익명 돼지";
            @Override
            public String getName(){
                return name;
            }
    };
    System.out.println(pet.getName()); // 결과 : 익명 돼지
}



2. 인스턴스 생성 과정



Pocketmon이라는 클래스의 인스턴스를 생성하는 간단한 코드를 작성해본다.

/*
class Pocketmon {  
    String name;      
    int hp;   
    Pocketmon(String name, int hp) {  
      	  this.name = name;  
 	  this.hp = hp;  
    }
 */
public static void main(String[] args) {
	Pocketmon pikachu = new Pocketmon("pikachu",10);
}

바이트 코드

Compiled from "Test.java"
  public static void main(java.lang.String[]);
    Code:
       0: new           #7                  // class javabasic/week5/Pocketmon
       3: dup
       4: ldc           #9 (상수 풀의 인덱스)                  // String Pikachu
       6: bipush        10
       8: invokespecial #11                 // Method javabasic/week5/Pocketmon."<init>":(Ljava/lang/String;I)V
      11: astore_1
      12: return

2.1 new : Pocketmon 클래스의 인스턴스를 생성

  • Pocketmon 클래스에 대한 새로운 인스턴스가 heap에 생성
  • 해당 heap으로의 참조(@100)가 오퍼랜드 스택(operand stack)에 push된다.

2.2 dup : 앞에서 생성한 인스턴스의 참조자를 복사(duplicate)

  • 생성자를 호출하면 해당 객체의 참조자가 스택에서 제거된다.
  • 따라서 new 키워드를 사용해 객체를 생성한 뒤
  • 생성자를 호출하기 전에 dup 명령어를 사용해 참조자(@100)를 복사한다.

2.3 ldc : 리터럴형태로 “Pikachu” 문자열 생성

  • 런타임 상수풀(run-time constant pool)에 push
  • 오퍼랜드 스택(operand stack)에도 String 참조값 push

2.4 bipush 10 : 생성자에 전달할 인자(10)를 스택에 추가


2.5 invokespecial <init> (Ljava/lang/String;I)V : String과 int를 매개변수로 가지는 생성자 호출

  • 매개변수 값으로 인스턴스 변수를 초기화
  • Pocketmon(), int 10, @500, @100를 오퍼랜드 스택에서 pop시켜, 인스턴스 변수를 초기화한다.

2.6 astore_1 : 지역변수에 오퍼랜드 스택에 있는 참조값을 넣는다

  • 지역변수 pikachu에 초기화가 완료된 인스턴스의 참조값(@100)을 넣는다.

2.7 작업완료



3. 메서드



메서드는 객체의 행동을 정의한다.
메서드도 변수처럼 클래스 메서드와 인스턴스 메서드를 사용할 수 있다.
메서드명은 변수명과 마찬가지로 Lower Camel case를 사용하며, 기본적인 메서드의 형식은 다음과 같습니다.

<접근제어자> <반환 타입> 메서드명(파라미터) {
    내용
    return 반환값 //없을 시 생략 가능
}

3.1 인스턴스 메서드

인스턴스 메서드는 인스턴스가 생성된 후 사용할 수 있는 메서드다.
메서드 내부에서 인스턴스 변수와 클래스 변수 모두 사용이 가능하다.

class Person {
    public String name;
    public static int age;

    public Person(String name) {
        this.name = name;
        age++;
    }

    public void sayHello() {
        System.out.println(this.name + "님 현재 인원은" + age + "명 입니다.");
    }
}

   public static void main(String[] args) {
        Person person = new Person("sam");

        person.sayHello(); //sam님 현재 인원은 1명입니다.
    }


3.2 클래스 메서드

클래스 메서드는 인스턴스가 아닌 클래스에 종속되는 메서드다.
클래스 변수와 마찬가지로 인스턴스 메서드 처럼 선언한 후 static 키워드를 붙여 사용하며 클래스 메서드 내부에서는 클래스 변수만 사용 가능하다.

class Person {
    //..

    public static void printTotalCount() {
        System.out.println(count);
        // System.out.println(this.name); //error
    }
}

   public static void main(String[] args) {
       Person.printTotalCount(); //1

       Person person = new Person("sam");
       person.printTotalCount(); //1
    }










참조


profile
Be More!

0개의 댓글