본문 바로가기

WhiteShip Java Study : 자바 처음부터 멀리까지

클래스

선장님과 함께하는 자바 스터디입니다.

자바 스터디 Github

github.com/whiteship/live-study

 

whiteship/live-study

온라인 스터디. Contribute to whiteship/live-study development by creating an account on GitHub.

github.com

나의 Github

github.com/cmg1411/whiteShip_live_study

 

cmg1411/whiteShip_live_study

✍ 자바 스터디할래. Contribute to cmg1411/whiteShip_live_study development by creating an account on GitHub.

github.com

 

  • 클래스 정의하는 방법
  • 객체 만드는 방법 (new 키워드 이해하기)
  • 메소드 정의하는 방법
  • 생성자 정의하는 방법
  • this 키워드 이해하기

 

 

클래스

클래스란 인스턴스를 만들기 위한 틀 같은 존재다. 인스턴스를 만들기 위한 설계도이다.

 OOP 에서 객체를 만들어 쓰기 위해 객체를 어떻게 만들 것인지를 정의한다.

생성자, 필드, 메서드를 포함하고 이것들이 객체의 존재를 정의한다.

 

 

인스턴스 vs 객체

  • 객체 : 클래스라는 틀로 만들 대상.
  • 인스턴스 : 소프트웨어 상에서 실제로 메모리에 올려져 만들어진 객체

 

클래스의 구성요소

  • 생성자
  • 필드
  • 메서드
  • 초기화블럭

이번 글에서 하나하나 다뤄본다.

 

 

클래스 정의 방법

(클래스 접근지정자) class (클래스이름) {
...
}
public class Car {

}
  • 접근 지정자는 public, default(package-private) 만 가능하다.
  • implements, extends 키워드를 이용하여 상속, 구현으로 확장할 수 있다.
  • abstract 키워드를 class 앞에 붙이면 추상클래스로 활용할 수 있다. (추상 클래스는 인스턴스 생성이 불가)
  • final 키워드를 class 앞에 붙이면 상속불가 클래스로 만들 수 있다. (불변 클래스를 만드는 단계중 하나)

 

 

객체 생성 방법 (new)

(클래스이름) (객체이름) = new (클래스이름)();
Car car = new Car();

 

  • 클래스로 객체를 생성할 떄에는 new 키워드를 사용한다.
  • new 키워드의 역할은 아래와 같다.
  • 힙 영역에 데이터를 저장할 공간을 할당받게 한다.
  • 할당받은 공간의 참조값을 객체에게 반환한다.
  • 생성자를 호출한다.

 

객체생성 예제

public class ClassExample {
    public static void main(String[] args) {
        Car car = new Car("Genesis", 10);  <-- lineNumber 5
    }
}
public class Car {
    private String name;
    private int position;

    public Car(String name, int position) {
        this.name = name;
        this.position = position;
    }
}

간단한 예제 이다.

 

이 코드의 바이트 코드를 보자.

인텔리J 를 사용한다면 코드를 컴파일한 후 Shift 를 두번 눌러서 show byteCode 를 하면 class 파일을 볼 수 있다.

(컴파일을 하지 않으면 class 파일이 없으니 당연히 볼 수 없다.)

cmd 환경에서는 javap - c  명령을 사용하면 볼 수 있다.

 

  public <init>()V
   L0
    LINENUMBER 3 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/whiteship/white_ship_study/classExample/ClassExample; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
    // parameter  args
   L0
    LINENUMBER 5 L0
    NEW com/whiteship/white_ship_study/classExample/Car
    DUP
    LDC "Genesis"
    BIPUSH 10
    INVOKESPECIAL com/whiteship/white_ship_study/classExample/Car.<init> (Ljava/lang/String;I)V
    ASTORE 1
   L1
    LINENUMBER 6 L1
    RETURN
   L2
    LOCALVARIABLE args [Ljava/lang/String; L0 L2 0
    LOCALVARIABLE car Lcom/whiteship/white_ship_study/classExample/Car; L1 L2 1
    MAXSTACK = 4
    MAXLOCALS = 2
}

LINENUMBER 5 L0 부터가 객체를 생성한다.

new 키워드가 하는 일이라 볼 수 있다.

 

1. NEW ~ 

  • 새로운 Car 인스턴스가 car 이라는 이름으로 heap 영역에 생성된다.
  • stack 영역의 Operation Stack 에 위에서 생성한 인스턴스의 참조자가 쌓인다.

 

 

2. DUP

  • Operation Stack 에 방금 쌓은 참조자를 복사해서 쌓는다.
  • 이후 생성자를 호출했을 때 객체의 참조자가 스택에서 제거되기 때문이다.

 

 

3. LDC "Genesis"

  • LoaD Constant 의 약자이다.
  • 힙 영역의 상수풀에 "Genesis" 를 생성하고 참조값을 가져온다.
  • 참조값을 Operation Stack 에 쌓는다.

alkhwa-113.tistory.com/entry/String%EA%B3%BC-StringBuilder 스트링 상수 풀

 

 

 

 

4. BIPUSH 10

  • 생성자 인수로 사용할 10 을 Operation Stack 에 쌓는다.

 

 

5, INVOKESPECIAL

  • 직역하면 특별한 것을 호출(?) 한다는 것이다.
  • 위에서 쌓인 인스턴스의 참조값, String 의 참조값, 10 을 가지고 일을 할 것이다. 무슨 일을 하느냐 하면
  • 생성자를 호출한다. 뒤의 <init> 을 보면 알 수 있다.
  • 생성자에서 객체 값들을 초기화시킨다.
  • 이후 Operation Stack 에서 생성자 호출에 사용한 값들을 pop() 한다.

 

 

6. ASTORE 1

  • LVA(Local Variable Array) 에 car 라는 이름의 공간을 할당하고, 
  • Operation Stack 에 마지막으로 남아있던 car 인스턴스의 참조값을 넣는다.

이렇게 되면 객체를 생성하는 것이다.

 

참고

ahnyezi.github.io/java/javastudy-5/#6-astore_1--%EC%A7%80%EC%97%AD%EB%B3%80%EC%88%98%EC%97%90-%EC%98%A4%ED%8D%BC%EB%9E%9C%EB%93%9C-%EC%8A%A4%ED%83%9D%EC%97%90-%EC%9E%88%EB%8A%94-%EC%B0%B8%EC%A1%B0%EA%B0%92%EC%9D%84-%EB%84%A3%EB%8A%94%EB%8B%A4

 

 

생성자

  • 생성자는 클래스로 인스턴스를 생성할 때 자동으로 실행되어 객체를 초기화한다.
  • 초기화를 위해 사용하므로 별도의 리턴타입이 없고, 선언부에 리턴타입을 명시하지 않는다.
  • 생성자를 오버로딩하여 시그니처별로 생성할 수 있다.
  • 하지만 같은 시그니쳐로 여러 생성자를 생성할 수 는 없다.
  • 생성자를 명시적으로 선언하지 않으면 빈 기본생성자를 컴파일할 때 생성한다.
  • 생성자도 내부적으로 메서드처럼 동작하지만 메서드는 아니다.
public Car() {
}

public Car(String name, int position) {
	this.name = name;
	this.position = position;
}


// 같은 시그니쳐는 두개 생성 불가.
// 오류 발생. (정적 팩토리 메서드 방식을 사용하면 해결 가능)
public Car(String name, int price) {
	this.name = name;
	this.price = price;
}

 

하나의 팁으로는, private 접근 지정자를 생성자에 적용할 수 있는데,

모든 생성자가 private 이면 외부에서 접근이 불가하므로, 

객체생성이 불가하고 상속을 막을 수 있다. (상속 파트에서 봅시다)

 

 

 

필드

  • 필드는 클래스 클래스 내부에 선언된 변수 로 이해하면 쉽다.
  • 필드는 클래스의 속성을 나타낸다.
  • 인스턴스 변수 : 클래스가 만든 인스턴스의 라이프사이클 동안 사용되는 변수
  • 클래스 변수 : static 키워드가 붙어있어 정적으로 생성되어 사용되는 변수
public class Car {
    private static final NAME = "Sonata"; // 클래스 변수. 상수
    
    private final int price; // 인스턴스 변수
}

 

 

 

메서드

  • 클래스에 포함된 함수를 메서드라한다.
  • 클래스함수 라고도 한다.
  • 메서드는 클래스의 행위(동작)를 정의한다.
(접근지정자) (반환타입) (메서드이름)((매개변수)) {
 ~구현~
}
public void print(String name) {
	System.out.println(name);
}

 

 

 

초기화 블럭

  • 클래스 내부에서 초기화 블럭을 이용하여 인스턴스를 생성할 때 초기화를 할 수 있다.

일반 초기화 블럭 (대괄호)

public class Car {
   private String name;
   
   {
       name = "RR";
   }

	public Car() {
    }
}

일반 초기화 블럭에서 하는 일은 보통 생성자에서도 할 수 있다.

아직까지는 왜 사용하는지 깨닫지 못했다,

 

정적 초기화 블럭 (static 대괄호)

public class Car {
   private String name;
   
   static {
       ~
   }

	public Car() {
    }
}

자바 어플리케이션을 실행 시 정적으로 수행된다.

정적 블록이므로 객체가 생성되지 않은 시점에서 실행된다.

따라서 인스턴스 변수에 초기화를 시키는 그런 행동은 못한다.

 

 

 

this()

  • this() 는 생성자에서 쓰이는 메서드이다.
  • this 와는 다르다. this 는 인스턴스 자신을 가리키는 참조 변수이다.
  • this() 는 자기자신의 생성자를 뜻한다.
  • 매개변수에 따라 같은 시그니쳐의 생성자를 실행한다.
  • 생성자들이 많을 때, 중복코드를 줄일 수 있다.
public class Car {
	private String name;
    private int price;
    
    public Car() {
    }
    
    public Car(String name) { // 밑의 this(name) 에 의해 호출된다.
    	this.name = name;
    }
    
    public Car(String name, int price) {
    	this(name); // 위의 생성자를 호출한다.
        this.price = price;
    }
}

 

 

 

 

 

과제 (Optional)

  • int 값을 가지고 있는 이진 트리를 나타내는 Node 라는 클래스를 정의하세요.
  • int value, Node left, right를 가지고 있어야 합니다.
  • BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요.
  • DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.

추후 완성예정

 

참고

blog.naver.com/swoh1227/222175350122

'WhiteShip Java Study : 자바 처음부터 멀리까지' 카테고리의 다른 글

디스패치, 다이나믹 디스패치, 더블 디스패치  (2) 2021.02.01
상속  (0) 2021.02.01
4주차) 과제  (0) 2021.01.30
제어문  (0) 2021.01.28
연산자  (0) 2021.01.28