생성자, 변수와 변수의 초기화, 메서드, JVM 메모리 구조

서지우·2023년 7월 6일
0

JAVA

목록 보기
11/28

생성자란

- 인스턴스가 생성될 때마다 호출되는 '인스턴스 초기화 메서드'
- 인스턴스 변수의 초기화 또는 인스턴스 생성시 수행할 작업에 사용
- 몇가지 조건을 제외하고는 메서드와 같음
- 모든 클래스에는 반드시 하나 이상의 생성자가 있어야 함.

인스턴스 초기화 - 인스턴스 변수에 적절한 값을 저장하는 것


생성자의 조건

- 생성자의 이름은 클래스의 이름과 같아야 한다.
- 생성자는 리턴값이 없다. (하지만 void를 쓰지 않는다)


기본 생성자

- 매개변수가 없는 생성자
- 클래스에 생성자가 하나도 없으면 컴파일러가 기본 생성자를 추가
  (생성자가 하나라도 있으면 컴파일러는 기본 생성자를 추가하지 않음)


매개변수가 있는 생성자


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년식 소나타 검정색

위의 예제에서 매개변수를 가지는 첫 번째 생성자는 this 참조 변수를 사용하여 인스턴스 변수에 접근하고 있다.

또한, 매개변수를 가지지 않는 두 번째 생성자는 내부에서 this() 메소드를 이용하여 첫 번째 생성자를 호출한다.

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


필드(field)

클래스의 필드(field)란 클래스에 포함된 변수(variable)를 의미합니다.

클래스 내에서 필드는 선언된 위치에 따라 다음과 같이 구분됩니다.

  1. 클래스 변수(static variable)
  2. 인스턴스 변수(instance variable)
  3. 지역 변수(local variable)

예제

class Car {
    static int modelOutput; // 클래스 변수
    String modelName;       // 인스턴스 변수 
    
    void method() {

        int something = 10; // 지역 변수
    }
}

클래스 변수와 인스턴스 변수는 초기화를 하지 않아도 변수의 타입에 맞게 자동으로 초기화된다.

하지만 지역 변수는 사용하기 전에 초기화하지 않으면, 자바 컴파일러가 오류를 발생시킨다.

예제

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

기본형 매개변수
- 변수의 값을 읽기만 할 수 있다.
참조형 매개변수
- 변수의 값을 읽고 변경할 수 있다.


메소드(method)

클래스에서 메소드(method)란 어떠한 특정 작업을 수행하기 위한 명령문의 집합이라 할 수 있다.

메소드 장점

- 메소드를 사용하면 중복되는 코드의 반복적인 프로그래밍을 피할 수 있게 된다.
- 모듈화로 인해 전체적인 코드의 가독성이 좋아진다.
- 프로그램에 문제가 발생하거나 기능의 변경이 필요할 때도 손쉽게 유지보수를 할 수 있게 됩니다.

예제

접근제어자 반환타입 메소드이름(매개변수목록) { // 선언부

    // 구현부

}

Car myCar = new Car();   // 객체를 생성함.

myCar.accelerate(60, 3); // myCar 인스턴스의 accelerate() 메소드를 호출함.
  1. 접근 제어자 : 해당 메소드에 접근할 수 있는 범위를 명시합니다.
  2. 반환 타입(return type) : 메소드가 모든 작업을 마치고 반환하는 데이터의 타입을 명시합니다.
  3. 메소드 이름 : 메소드를 호출하기 위한 이름을 명시합니다.
  4. 매개변수 목록(parameters) : 메소드 호출 시에 전달되는 인수의 값을 저장할 변수들을 명시합니다.
  5. 구현부 : 메소드의 고유 기능을 수행하는 명령문의 집합입니다.

인스턴스메서드

- 인스턴스 생성 후, '참조변수.메서드이름()'으로 호출
- 인스턴스변수나 인스턴스메서드와 관련된 작업을 하는 메서드
- 메서드 내에서 인스턴스변수 사용가능

클래스메서드(static메서드)

- 객체생성없이 '클래스이름.메서드이름()'으로 호출
- 인스턴스변수나 인스턴스메서드와 관련없는 작업을 하는 메서드
- 메서드 내에서 인스턴스변수 사용불가
- 메서드 내에서 인스턴스 변수를 사용하지 않는다면 static을 붙이는 것을 고려

멤버간의 참조와 호출

메서드 호출

같은 클래스의 멤버간에는 객체생성이나 참조변수 없이 참조할 수 있다.

그러나 static멤버들은 인스턴스멤버들을 참조할 수 없다.


변수의 접근



return문

메소드가 정상적으로 종료되는 경우

- 메서드의 블럭{}의 끝에 도달했을 때
- 메서드의 블럭{}을 수행 도중 return문을 만났을 때

return문

-현재 실행중인 메서드를 종료하고 호출한 메서드로 돌아간다.



JVM의 메모리 구조

메서드 영역

- 클래스 정보와 클래스변수가 저장되는 곳

호출스택(call stack)

- 메서드의 작업공간

- 인스턴스가 생성되는 공간
- new연산자에 의해서 생성되는 배열과 객체는 모두 여기에 생성

호출스택의 특징

- 메서드가 호출되면 수행에 필요한 메모리를 스택에 할당받음
- 메서드가 수행을 마치면 사용했던 메모리를 반환
- 호출스택의 제일 위에 있는 메서드가 현재 실행중인 메서드
- 아래에 있는 메서드가 바로 위의 메서드를 호출한 메서드


실습 - ch06 / S01.java

주석으로 설명..

package ch06;

import javafx.scene.layout.VBox;

//고양이를 추상화
class Cat {
    //필드 (객체의 속성)
    String name;
    int age;

    //생성자 (객체를 생성할 때 사용)
    //생성자 이름은 클래스명과 동일하게 만든다
    // 생성자가 있어야 클래스를 인스턴스화 할 수 있다
    // 생성자는 리턴 타입이 없다(무조건 void)
    // 클래스에 아무 생성자가 없을 경우
    // 매개변수가 없는 생성자가 기본적으로 세팅 되어 있다.
    // public Cat() {
    //     System.out.println("내가 태어났다.");
    // }

    // 다른 생성자를 직접 만들 경우
    // 기본적으로 세팅 되어 있는 생성자는 없어진다.
    public Cat(String name, int age) {
        // this를 붙여줘야 해당 위치에 들어가 아니면 자기 자신에서 변경이 일어남.
        // this는 클래스가 아니라 생성될 인스턴스
        this.name = name;
        this.age = age;
        System.out.println(this.name + "가 태어났다.");
    }
    // 길고양이
    // 일부 데이터만 받을 수 있다.
    // 받지 않은 데이터는 개발자가 직접 초기화 해줘야 한다.
    public Cat(int age){
        this.name = "길냥이";
        this.age = age;

        System.out.println(this.name + "가 태어났다.");
    }

    // public Cat(){
    //     this.name = "길냥이";
    //     this.age = 1;
    //     System.out.println(this.name + this.age);
    // }

    // 문제해답1
    // public Cat(int age){
           // this를 이용해서 생성자에서 다른 생성자를 불러낼 수 있다.
           // 보통은 제일 매개변수가 많은 생성자를 사용한다.
    //     this("길냥이", age);
    // }
    // 문제해답2
    // public Cat(){
    //     this("길냥이", 1);
    // }
    // 문제해답3
    public Cat(){
        // 필드에 값을 직접 입력한다
    }

    //메소드 (객체의 기능)
    // 생성된 인스턴스에서 사용할 수 있는 기능
    public void cry() {
        System.out.println("야옹");
    }
}

public class S01 {
    public static void main(String[] args) {
        // //오브젝트 오브젝트이름 = 인스턴스
        // Cat cat = new Cat();

        // 오브젝트는 상상할 수 있지만 실체화 되지 않은 것
        Dog cat;

        
        // new를 통해서 오브젝트에 인스턴스를 넣어 준다.
        // 생성자가 요구하는 내용대로 작성해야한다.
        cat = new Dog("야옹이", 2);
        
        cat.cry();

        new Cat(1).cry();

        // 문제
        // 이름이 '길냥이'이고 나이가 1살인 고양이를 생성하시오.
        // 아래 빨간 줄을 없애보시오
        // 괄호 안에는 값을 넣지 않습니다.
        new Cat();
    }
}

생성자의 조건
생성자의 이름은 클래스의 이름과 같아야한다.

vscode에서 생성자 만들 때 단축키 사용


위의 JVM을 설명하자면 아래와 같다.

0. 프로그램 실행
1. 파일에 만들어 둔 클래스와 
static 변수 / 함수가 스태틱 영역에 올라간다
2. main 함수가 실행 된다(스택 영역에 올라간다)
3. cat 인스턴스가 만들어진다(힙 영역에 올라간다)
4. cat.cry메소드가 실행된다(스택 영역에 올라간다)
5. cat.cry메소드가 완료된다(스택 영역에서 내려온다)
6. cat 인스턴스가 쓰이지 않기 때문에 가비지 컬렉션 된다
(힙 영역에서 내려온다)
7.main함수가 완료된다(스택 영역에서 내려온다)
8.프로그램이 종료된다(스태틱 영역에서 모든 데이터가 내려온다)

변수의 초기화

- 변수를 선언하고 처음으로 값을 저장하는 것
- 멤버변수(인스턴스변수, 클래스변수)와 배열은 각 타입의 기본값으로 자동초기화되므로 초기화를 생략할 수 있다.
- 지역변수는 사용전에 꼭 초기화를 해주어야 함.
class InitTest{
	int x; // 인스턴스 변수
    int y = x; //인스턴스 변수
    
    void methhod1(){
    	int i; //지역 변수
        int j = i; //컴파일 에러!! 지역변수를 초기화하지 않고 사용했음
    }
}


멤버변수의 초기화

멤버변수의 초기화 방법

1. 명시적 초기화

2. 생성자

3. 초기화 블럭

- 인스턴스 초기화 블럭 : {}
- 클래스 초기화 블럭 : static {}

초기화 블럭

클래스 초기화 블럭
: 클래스 변수의 복잡한 초기화에 사용되며 클래스가 로딩될 때 실행됨

인스턴스 초기화 블럭
: 생성자에서 공통적으로 수행되는 작업에 사용되면 인스턴스가 생성될 때 마다 (생성자보다 먼저) 실행됨


멤버변수의 초기화 시기와 순서

클래스 변수 초기화 시점 : 클래스가 처음 로딩될때 단 한번
인스턴스변수 초기화 시점 : 인스턴스가 생성될 때 마다


실습 - ch06 / S02.java

주석으로 설명..

package ch06;

class Dog{
    String name;
    int position;

    public Dog(String name, int position) {
        this.name = name;
        this.position = position;
        System.out.println(this.name + "가 태어났습니다.");
    }
    
    public Dog(String name){
        this(name, 0);
    }

    public void moveRight(){
        this.position++;
        System.out.println(this.name + "가 오른쪽으로 이동했습니다.");
    }

    public void moveLeft(){
        this.position--;
        System.out.println(this.name + "가 왼쪽으로 이동했습니다.");
    }
}

public class S02 {
    public static void main(String[] args) {
        // 고양이 생성
        Dog dog = new Dog("댕댕이");

        // 유저가 고양이를 움직임
        dog.moveRight();
        dog.moveLeft();

        // 캐릭터 위치 확인
        System.out.println(dog.position);
    }
}

실습 - ch06 / S03.java

주석으로 설명..

package ch06;

class Cat{
    String name;
    int hp;
    int position;

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

    // 이름만 받고 피 100 포지션 0
    public Cat(String name){
        this(name, 100, 0);
    }

    public void moveRight(){
        this.position++;
        System.out.println(this.name + "가 오른족으로 이동했습니다.");
        //this.hp--;
    }

    public void moveLeft(){
        if(this.position < 1){
            System.out.println(this.name + "는 왼쪽으로 갈 수 없습니다.");
            // 함수(메소드)에서 return을 만나면 아래 코드는 실행되지 않는다
            return;
        }
        this.position--;
        System.out.println(this.name + "가 왼쪽으로 이동했습니다.");
        //this.hp--;
    }

    public void reduceHp(){
        this.hp--;
        System.out.println(this.name + "의 체력이 내려갔습니다.");
    }

    public void yam(int food){
        // 밥을 먹었을 때 체력이 100을 초과하는 경우
        // 100으로 세팅하고 체력이 가득 찼다고 메시지 올리기       
        if(this.hp+food>100){
            this.hp = 100;
            System.out.println(this.name+"의 체력이 가득 찼습니다.");
            return;
    
        }
        this.hp = this.hp + food;
        System.out.println(this.name + "가 밥을 먹습니다.");
    }

    public String dong(){
        return "이쁜똥";
    }
}


public class S03 {
    public static void main(String[] args) {
        Cat cat = new Cat("야옹이");

        cat.moveLeft();

        cat.moveRight();

        cat.yam(5);

        System.out.println(cat.hp);

        System.out.println(cat.dong());

    }
}

실습 - ch06 / S04.java

주석으로 설명

package ch06;

class Cat{
    static int countCat = 0;
    String name;

    public Cat() {
        this.name = "길고양이";
        Cat.addCat();
    }

    public static void addCat(){
        Cat.countCat++;
        System.out.println("새로운 고양이가 태어났습니다.");
    }
}

public class S04 {
    public static void main(String[] args) {

        new Cat();
        new Cat();
        new Cat();
        new Cat();
        new Cat();

        System.out.println("고양이 수는 " + Cat.countCat);
    }
}

실습 - ch06 / S05.java

주석으로 설명

package ch06;

// 함수를 사용하기 위한 클래스
class CalcUtil {

    // static을 사용하면 객체를 생성하지 않아도 기능을 사용할 수 있다
    // 함수
    // 리턴 타입은 없거나 있을 수 있다 (아래 함수는 int를 리턴한다.)
    // 함수의 이름은 개발자가 정한다 (기능과 관련 있는 이름을 추천)
    // 소괄호 안에는 외부에서 받아올 데이터 타입과 변수명을 적는다
    // 외부 데이터를 매개변수 / 인자 / 인수
    public static int add(int a, int b){
        // return 뒤에는 내부에서 연산된 값을 요청한 곳에 되돌려 준다
        // 리턴 타입이 없으면 return을 적지 않거나
        // return; 으로 마무리 할 수 있다.
        return a + b;
    }

}

public class S05 {
    public static void main(String[] args) {
        
        // 호출된 함수는 (CalcUtil.add)는 결과 값으로 바뀐다.
        // ex)자판기에 500원을 넣으면 
        // 자판기에서 콜라가 나오는게 아니라
        // 자판기 자체에서 콜라가 되어버리는 것과 비슷하다
        int result = CalcUtil.add(2, 3);

        System.out.println(result);
    }
}

실습 - ch06 / S06.java

주석으로 설명

package ch06;

class 아이템 {
    String name;
    int reinforce;

    public 아이템(String name) {
        this.name = name;
        this.reinforce = 0;
    }

    public void reinforceItem(){
        this.reinforce++;
    }
}

class 강화재료 {
    String name;

    public 강화재료(String name) {
        this.name = name;
    }
}

class 강화유틸{
    public static 아이템 강화하기(아이템 item, 강화재료 source){
        item.reinforceItem();
        return item;
    }
}

public class S06 {
    public static void main(String[] args) {
        
        아이템 item = new 아이템("노가다 목장갑");
        강화재료 source = new 강화재료("숯돌");

        아이템 결과아이템 = 강화유틸.강화하기(item, source);

        System.out.println(결과아이템.reinforce);

    }
}

실습 - ch06 / S10.java

주석으로 설명

class Cat{
    String name;

    public Cat(String name) {
        this.name = name;
    }
}

public class S10 {
    public static void main(String[] args) {
        Cat cat1 = new Cat("야옹이");
        // 참조형 변수를 아래처럼 사용하면
        // 복사의 개념이 아니라 같은 객체에
        // 별명을 하나 더 붙여 준 것과 비슷하다
        Cat cat2 = cat1;
        
        // cat2의 내용을 바꾸면
        cat2.name = "뚱땡이";

        // cat1의 내용도 바뀐다. (cat1과 cat2는 같은 객체이기 때문)
        System.out.println(cat1.name);
    }
}
profile
미래가 기대되는 풀스택개발자 공부 이야기~~

0개의 댓글