클래스와 메서드에 사용되는 final

  • class 에 final
    • 상속 끝!
    • fianl 선언된 class 는 확장할 수 없다.
  • 메서드에 final
    • 오버라이딩 끝!
    • final 선언된 메서드는 상속된 곳에서 오버라이드할 수 없다.

'자바 공부 > [ 完 ] 자바 실전 - 기본편' 카테고리의 다른 글

10-2. 다형성 - 캐스팅  (0) 2024.03.19
10-1. 다형성 - 이론과 다형적 참조  (0) 2024.03.19
9-3 상속과 접근제어  (0) 2024.03.14
9-2 상속과 메서드 오버라이딩  (0) 2024.03.14
9-1 상속  (0) 2024.03.14

super - 부모 참조

  • 자식 내부에서 부모의 기능을 온전하게 호출 하고 싶을때에 super 를 사용 하여 부모 class 에 대한 참조를 가리킬 수 있다.

→ super 를 사용 하면 본인 타입을 찾지 않고 부모 타입을 확인하여 갖고 온다.


super - 생성자

  • 자식 class 의 객체를 생성 하면 내부 메모리에 자식과 부모 class 가 각각 만들어진다. 따라서 각각의 생성자도 모두 호출 되어진다.
  • 상속 관계 에서는 자식 class 의 생성자에서 부모 class 의 생성자를 반드시 호출 해야 한다.
  • 생성자의 호출은 부모 class 부터 호출 하고 자식 class 가 호출 된다.

→ 조부 classA

package extends1.super2;

public class ClassA {
    public ClassA() {
        System.out.println("ClassA 생성자");
    }
}

→ 부모 classB

package extends1.super2;

public class ClassB extends ClassA{
    public ClassB(int a) {
        // super(); // 기본생성자 생략 가능
        System.out.println("ClassB 생성자 a=" + a);
    }

    public ClassB(int a, int b) {
        // super(); // 기본 생성자 생략 가능
        System.out.println("ClassB 생성자 a=" + a + " b=" + b);
    }
}

→ 자식 classC

package extends1.super2;

public class ClassC extends ClassB{
    public ClassC() {
        super(10, 20);// 기본 생성자가 없으므로 직접 호출 해주어야 한다.
        System.out.println("ClassC 생성자");
    }

}

→ 자식 classC 객체 생성

package extends1.super2;

public class Super2Main {
    public static void main(String[] args) {
        ClassC classC = new ClassC();
    }
}

→ 결과

ClassA 생성자 // <- 조부
ClassB 생성자 a=10 b=20 // <- 부모
ClassC 생성자 // <- 자식
  • 따라서 상속 관계에서 생성자를 호출 하게 되면 부모의 생성자를 먼저 탐색 하고 난 후에 자신을 호출 하게 된다.

 

상속과 접근 제어

  • 기존에 배웠던 접근제어자에서 protected 인 같은 패키지만 허용 하고, 다른 패키지 일지라도 상속된 관계의 호출 허용

→ 부모 class 와 자식 class 를 다른 class 에 생성 하고, 부모 class 에 접근 제한자를 적용 하여 만들어보자 🔽

// 부모 class
package extends1.access.parent;

public class Parent {
    public int publicValue;
    protected int protectedValue;
    int defaultValue;
    private int privateValue;

    public void publicMethod(){
        System.out.println("Parent.publicMethod");
    }

    protected void protectedMethod() {
        System.out.println("Parent.protectedMethod");
    }

    void defaultMethod() {
        System.out.println("Parent.defaultMethod");
    }

    private void privateMethod() {
        System.out.println("Parent.privateMethod");
    }

    public void printParent() {
        System.out.println("==Parent 메서드 안==");
        System.out.println("publicValue = " + publicValue);
        System.out.println("protectedValue = " + protectedValue);
        System.out.println("defaultValue = " + defaultValue);
        System.out.println("privateValue = " + privateValue);

        // 부모 메서드 안에서 모두 접근 가능
        defaultMethod();
        privateMethod();
    }
}

→ 자식 class 가 상속 받은 후 부모 class 의 변수와 메소드를 호출 해보면 🔽

// 자식 class 
package extends1.access.child;

import extends1.access.parent.Parent;

public class Child extends Parent {
    public void call() {
        publicValue = 1;
        protectedValue = 1; // 상속 관계 or 같은 패키지
        // defaultValue = 1; // 다른 패키지 접근 불가, 컴파일 오류
        // privateValue = 1; // 접근 불가, 컴파일 오류

        publicMethod();
        protectedMethod(); // 상속 관계 or 같은 패키지
        // defaultMethod(); // 다른 패키지 접근 불가, 컴파일 오류
        // privateMethod(); // 접근 불가, 컴파일 오류

        printParent(); // 부모의 public 메서드 내부에 있는 default, private 접근 제한자는
        // 상관없이 호출 가능하다
    }
}

→ 자식 class 객체를 생성 하여 작동 시켜 보면

package extends1.access;

import extends1.access.child.Child;

public class ExtendsAccessMain {
    public static void main(String[] args) {
        Child child = new Child();
        child.call();
    }
}

Parent.publicMethod
Parent.protectedMethod
==Parent 메서드 안==
publicValue = 1
protectedValue = 1
defaultValue = 0
privateValue = 0
Parent.defaultMethod
Parent.privateMethod

→ 이런 결과를 볼 수 있다.

→ 자식 class 의 객체를 생성 하면 위와 같이 생성되고 자식에서 없는 기능을 부모에서 찾으려 할 때 접근 제한자가 영향을 끼친다.


 

상속과 메서드 오버라이딩

  • 부모 타입의 기능을 자식에서 다르게 재정의 하고 싶을 때 메서드 오버라이딩을 사용해 재정의 할 수 있다.

메서드 오버라이딩

→ 사용 방법 🔽

package extends1.overriding;

public class Car {
    public void move() {
        System.out.println("차를 이동합니다");
    }

    // 추가
    public void openDoor() {
        System.out.println("문을 엽니다.");
    }
}
// 부모 class

→ 부모 class 를 상속 받아 move 메서드를 재정의 🔽

package extends1.overriding;

public class ElectricCar extends Car {
    @Override // <- 오버라이딩 했다는 표시 필수
    public void move() {
        System.out.println("전기차를 빠르게 이동합니다");
    }
    
    public void charge() {
        System.out.println("충전 합니다.");
    }
}
// 자식 class

→ 이런 식으로 자식 class 에서 재정의 하여 사용 가능하다.

메서드 오버라이딩시 구조

→ 자식class 에서 부모 class 의 기능을 overriding 하면 다음과 같은 구조를 갖는다.🔽

→ ElectricCar 객체를 생성시켜보면 🔽

ElectritcCar electricCar = new ElectricCar();
electricCar.move();

→ 다음과 같은 객체 메모리 영역에 부모 class 와 자식 class 구역이 생성 되고 move() 메서드도 동일 하게 생성 된다.🔽

→ 자식 class 를 호출 했기 때문에 자식 move() 메서드를 먼저 탐색하고 존재 한다면 자식의 기능을 사용하고 부모 타입은 찾지 않는다.

추가 - 오버로딩, 오버라이딩의 차이

  • 오버로딩 : 메서드의 이름은 갖지만 매개변수의 타입, 개수에 따라 다른 기능을 호출 하여 사용 하는 것을 오버로딩 이라고 한다.
  • 오버라이딩 : 자식 class 가 부모 class 의 기능을 재정의 하여 자식의 기능으로 덮어 씌우는 것을 말한다.

메서드 오버라이딩 조건

  • 메서드 이름이 동일
  • 메서드 의 파라미터 타입, 순서, 개수가 동일
  • 반환 타입이 동일
  • 상위 메서드 보다 하위 메서드보다 더 제한되면 안된다. ex) 상위 [ protected ] , 하위 [ public, protected ] O 상위 [ protected ] , 하위 [ private , default ] X
  • static, final, private 가 붙은 메서드는 오버라이딩 될 수 없다.
  • 생성자는 오버라이딩 할 수 없다.

'자바 공부 > [ 完 ] 자바 실전 - 기본편' 카테고리의 다른 글

8-2. 클래스와 메서드에 사용되는 final (상속 이해 필요)  (0) 2024.03.14
9-3 상속과 접근제어  (0) 2024.03.14
9-1 상속  (0) 2024.03.14
8-1. final  (0) 2024.03.12
7-4 static 메서드  (0) 2024.03.09

상속 - 시작

  • 공통되는 것을 묶어 부모를 만들고 그 하위에 공통 사항을 각각사용하며 다른 기능을 만드는 것을 제공 하기 위해 상속을 사용한다.

상속 관계

  • 상속은 객체 지향 프로그래밍의 핵심 요소 중 하나로 기존 클래스의 필드와 메서드를 새로운 클래스에 재사용하게 해준다.
  • 이름 그대로 기존 클래스의 모든것을 그대로 물려받는 것이다.
  • 사용하는 방법은 extend 키워드를 사용하면 된다.
  • 자식 클래스는 부모클래스를 하나만 상속 받을 수 있다.

상속 관계

  • 부모 클래스 (슈퍼 클래스) : 상속을 통해 자신의 필드와 메서드를 다른 클래스에 제공하는 클래스
  • 자식 클래스 (서브 클래스) : 부모 클래스로부터 필드와 메서드를 상속받는 클래스

상속 사용

  1. 자동차 속성을 갖는 부모 클래스 🔽
package extends1.ex2;

public class Car {
    public void move() {
        System.out.println("차를 이동합니다");
    }
}

  1. 부모 클래스로부터 상속 받는 전기차 클래스 🔽
package extends1.ex2;

public class ElectricCar extends Car{
    public void charge() {
        System.out.println("충전 합니다.");
    }
}

  1. 부모 클래스로부터 상속 받는 가솔린차 클래스 🔽
package extends1.ex2;

public class GasCar extends Car{
    public void fillUp(){
        System.out.println("기름을 주유 합니다.");
    }
}

  1. 전기 차 가스 차 의 기능을 구현하는 클래스
package extends1.ex2;

public class CarMain {
    public static void main(String[] args) {
        ElectricCar electricCar = new ElectricCar();
        electricCar.move();
        electricCar.charge();

        GasCar gasCar = new GasCar();
        gasCar.move();
        gasCar.fillUp();
    }
}

→ 전기 차 와 가스 차 에 move 메소드가 없지만 상속받으면 마치 자식의 메소드인것 처럼 사용 가능해진다.


상속과 메모리 구조

→ 다음과 같은 상속 구조도를 갖은 class 를 보자🔽

ElectricCar electricCar = new ElectricCar();

→ ElectritcCar 의 객체를 생성할때의 메모리 구조 상황을 보면 🔽

  • 객체를 생성 할 때에 상속 받은 부모의 기능도 ElectricCar 의 참조 값 안에 생성하게 된다.
  • 외부에서 볼때 하나의 인스턴스를 생성 하는거 같지만 내부에는 부모와 자식이 모두 생성 되고 공간이 구분 된다.
  • 실제로는 참조 값 안에 Car(부모), ElectricCar(자식) 이라는 두 가지 클래스 정보가 공존하게 된다.

→ 그럼 ElectricCar.charge() 를 호출 한 상황에서는

  • 본인의 타입에서 찾아보고 해당 기능이나 변수가 존재하면 바로 사용.

→ ElectircCar.move() 인 부모 기능을 호출

  • 우선 본인의 타입에 존재하는지 찾아보고 없으면 부모타입에서 찾아 기능을 꺼내 사용한다.
  • 상속 결론
    • 상속 받은 객체를 생성하면 그 내부에는 부모와 자식이 모두 생성 된다.
    • 상속 관계의 객체를 호출 할 때, 대상 타입을 정하고 이때 호출자의 타입을 통해 찾는다.
    • 현재 타입에서 기능을 찾지 못하면 상위 부모 타입의 기능을 찾아서 실행 한다.

'자바 공부 > [ 完 ] 자바 실전 - 기본편' 카테고리의 다른 글

9-3 상속과 접근제어  (0) 2024.03.14
9-2 상속과 메서드 오버라이딩  (0) 2024.03.14
8-1. final  (0) 2024.03.12
7-4 static 메서드  (0) 2024.03.09
7-3 static 변수  (0) 2024.03.09

fianl

  • final 키워드는 class, methid 를 포함한 여러 곳에 붙을 수 있다.
  • 하지만 지금은 변수에 붙는 final 키워드만 배우고 나머지는 상속을 배운 다음에 들을 예정

fianl 변수

  • final 키워드는 이름 그래도 끝! 이라는 뜻
  • 변수에 final 키워드가 붙으면 한번 값이 들어간 후에는 더는 값을 변경할 수 없다.

→ 지역변수에 fianl 을 사용한 경우 🔽

package final1;

public class FinalLocalMain {
    public static void main(String[] args) {
        // final 지역 변수
        final int data1;
        data1 = 10; // 초최 한번만 할당 가능
        // data1 = 20; // 컴파일 오류 발생

        // final 지역 변수2
        final int data2 = 10;
        // data2 = 20; // 컴파일오류
    }
}

→ 메서드의 매개변수에 final 을 사용한 경우 🔽

package final1;

public class FinalLocalMain {
    public static void main(String[] args) {
		    // 매개변수 주기
        method(10);
    }

    // final 을 배개변수로 사용할때
    static void method(final int parameter) { 
    // 인자로 전해 받기 때문에 무조건 초기값이 있다.
        // parameter = 20; // 컴파일 오류
    }
}

→ 클래스의 초기 값이 없는 멤버 변수에 final 을 사용한 경우 꼭 생성자로 초기 값을 지정해주어야 한다.🔽

package final1;

public class ConstructInit {

    final int value; // <- 초기 값이 없는 멤버변수 선언

    public ConstructInit(int value) {
        this.value = value; // <- 생성자 호출시 인자 값으로 초기화
    }
}
// 메서드 final 호출이랑 비슷해 보이네?? 생성자도 메서드여서 그런가??

(생성자 초기화 방식)

→ 클래스의 초기 값이 선언된 멤버 변수의 final을 사용한 경우 생성자로 값 설정을 못받는다.🔽

package final1;

public class FieldInit {

    final int value = 10; //<-이미 초기 값이 주어진 경우

// 생성자로 초기값 선언시 컴파일 오류를 발생 시킨다🔽
	//  public FieldInit(int value) {
	//      this.value = value;
	//  }
}

(필드 초기화 방식)

→ 이런식으로 필드 초기화를 하게 되면 동일한 값을 객체 생성시 마다 불러와 메모리를 낭비하게 된다.

이렇게 중복인 메모리 낭비를 막기위해 사용하면 좋은 것이 static 을 사용해 메서드 영역에서 관리 시키는 것이 좋다. 이런 static 과 fianl을 같이 사용한 방식을 사용한 변수를 상수 라고 한다.

상수

  • 변하지 않는 값
  • 변수 앞에 static final 이 같이 붙은 변수를 상수라고 한다.
  • 상수 변수 설정 규칙으로는 모두 대문자로 작성해주고 단어마다 언더라인 으로 구분해준다. EX) static final int *CONST_VALUE* = 10; 이런식으로 사용한다.

static - fianl

  • 변수를 상수로 만들어주기 위해 변수 앞에 두 개를 같이 사용한다
  • 이렇게 사용하면 공용 변수 이면서 바뀌지 않는 변수가 된다.
package final1;

public class FieldInit {

    static final int CONST_VALUE = 10;
	  // 상수 사용
}

package final1;

public class FinalFieldMain {
    public static void main(String[] args) {
        // 상수
        System.out.println("상수");
        System.out.println(FieldInit.CONST_VALUE);
    }
}

// 상수는 static (정적)변수 이므로 호출 시에도 class 명으로 바로 호출 한다.

  • 자바가 끝날때까지 상수는 변함없이 값을 유지하고
  • 메서드 영역에서 관리 하기 때문에 메모리 낭비를 막을 수 있다.

fianl 상수

  • 상수는 변하지 않고 일정한 값을 갖는 수를 말한다.
  • static final 두 키워드를 같이 붙여 사용한다.
  • 대문자를 사용하고 구분은 언더바로 구분 한다.
  • 상수는 기능이 아니기 때문에 필드를 직접 접근하여 사용한다.

→ 고정 된 값을 사용하는 예 🔽 (PI, 하루 총 시간 등등)

package final1;

public class Constant {
    // 수학 상수
    public static final double PI = 3.14;

    // 시간 상수
    public static final int HOURS_IN_DAY = 24;
    public static final int MINUTES_IN_HOURS = 60;
    public static final int SECONDS_IN_MINUTE = 60;

    // 애플리케이션 설정 상수
    public static final int MAX_USERS = 1000;
}

// 이런식으로 사용할 수 있다.
  • 상수들은 거의 애플리케이션전반에 사용 되기 때문에 public 을 주로 접근 제한자로 사용한다.
  • 상수를 변경하려면 프로그램을 종료하고 → 코드를 변경 해야 한다.

final 변수와 참조

  • final 은 변수의 밧을 변경하지 못하게 막는다.
  • 변수는 기본형과 참조형으로 나뉘는데
    • final 기본형 변수는 → 값을 변경할 수 없다.
    • final 참조형 변수는 → 참조값을 변경할 수 없다.

→ final 참조형 변수의 특징 🔽

package final1;

public class Data {
    public int value;
}
// final 이 아닌 멤버 변수를 갖는 class 를 만들고
package final1;
// 해당 클래스를 사용하는 class 를 보자
public class FinalRefMain {
    public static void main(String[] args) {
        final Data data = new Data(); // 참조형
        //data = new Data();
        // 참조형 을 이미 final 을 설정 했기 때문에 새로운 객체를 참조할 수없다.

        // 그러나, 참조 대상의 값은 final 이 아니기때문에 변경 가능하다.
        data.value = 10;
        System.out.println(data.value);
        data.value = 20;
        System.out.println(data.value);
    }
}

→ 결론 참조하는 대상 자체를 다른 대상으로 변경 못 할 뿐 해당 대상의 값은 변경 가능하다.


'자바 공부 > [ 完 ] 자바 실전 - 기본편' 카테고리의 다른 글

9-2 상속과 메서드 오버라이딩  (0) 2024.03.14
9-1 상속  (0) 2024.03.14
7-4 static 메서드  (0) 2024.03.09
7-3 static 변수  (0) 2024.03.09
7-2 스텍과 큐 자료구조  (0) 2024.03.09

static 메서드

  • static 메서드가 필요한 이유 예를 보자🔽
package static2;

public class DecoUtil1 {
    public String deco(String str) {
        String result = "*" + str + "*";
        return result;
    }
}

→ DecoUtil1 이라는 클래스에 deco 메서드만 있다고 가정 하고 이 기능만 사용하는 클래서가 있다고 보면.

package static2;

public class DecoMain1 {
    public static void main(String[] args) {
        String s = "hello Java";
        DecoUtil1 utils = new DecoUtil1();
        String deco = utils.deco(s);

        System.out.println("before: " + s );
        System.out.println("after: " + deco );
        
        String s2 = "hello world";
        DecoUtil1 utils2 = new DecoUtil1(); // <- 또 동일한 기능을 하는 객체를 생성 해야 한다.
        String deco2 = utils2.deco(s);

        System.out.println("before: " + s2 );
        System.out.println("after: " + deco2 );
    }
}

→ 동일한 기능을 사용하기 위해 매번 객체를 새로 생성해주는 번거로움이 발생한다.

→ 이렇게 매번 단순한 동일 작업(메서드)을 생략하기 위해 static 을 메서드에 붙여준다.

  • static 메서드를 사용한 예 🔽
package static2;

public class DecoUtil2 {
    public static String deco(String str) { // <- 메서드에 static을 붙여준다.
        String result = "*" + str + "*";
        return result;
    }
}

package static2;

public class DecoMain2 {
    public static void main(String[] args) {
        String s = "hello Java";
        String deco = DecoUtil2.deco(s);

        System.out.println("before: " + s );
        System.out.println("after: " + deco );

        String b = "static Method";
        String deco2 = DecoUtil2.deco(b); 
        // 2번째 객체 생성없이 바로 클래스 명에 메서드 호출이 가능해진다.
        System.out.println("before: " + b);
        System.out.println("after: " + deco2);
    }
}

→ 이렇게 사용하면 불필요한 객체 생성 없이 편리하게 메서드 사용이 가능해진다.

메서드의 종류

  • 클래스 메서드 : 메서드 앞에 staitc 이 붙은 형태로, 정적 메서드, 클래스 메서드라고 부른다. 인스턴스 생성 없이 마치 클래스에 있는 메서드를 바로 호출 하는 것 처럼 느껴진다.
  • 인스턴스 메서드 : static이 붙지 않은 메서드로 항상 인스턴스(객체)를 생성해야 호출할 수 있다.

static 메서드 사용 시 주의 사항

  • static 메서드는 static 이 선언된 것만 사용 가는하다
  • staitc 메서드가 class 내부의 기능을 사용할때에 → static 메서드는 static 이붙은 메서드나, 변수 만 사용 가능하다.
  • static 메서드는 인스턴스 변수, 인스턴스 메서드를 사용할 수 없다.
  • 접근 제어자가 허용하는 범위 내에서 클래스를 통해 staic변수,메서드를 호출할 수 있다.

static 메서드 결론

  • static 붙은 것만 staitc메서드에서 사용 가능 하고 stiatc 메서드 자신은 접근제한자 범위 내에서 마음껏 사용될 수 있다.

static 메서드 사용 범위 예 🔽

package static2;

public class DecoData {
    private int instanceValue;
    private static int staticValue;

    public static void staticCall() { // <- 정적 메서드

        // instanceValue++; // 인스턴스 변수 접근, compile error
        // instanceMethod(); // 인스턴스 메서드 접근, compile error

        staticValue++; // 정적 변수 접근 가능
        staticMethod(); // 정적 메서드 접근 가능
    }

    public void instanceCall() { // <- 인스턴스 메서드

        instanceValue++; // 인스턴스 변수 접근 가능
        instanceMethod(); // 인스턴스 메서드 접근 가능

        staticValue++; // 정적 변수 접근 가능
        staticMethod(); // 정적 메서드 접근 가능
    }

    private void instanceMethod() { // <- private 인스턴스 메서드
        System.out.println("instanceValue = " + instanceValue);
    }

    private static void staticMethod() { // private 정적 메서드
        System.out.println("staticValue = " + staticValue);
    }
}

→ 해당 코드를 작동 시켜 보면

package static2;

public class DecoDataMain {
    public static void main(String[] args) {
        System.out.println("1. 정적 호출");
        DecoData.staticCall();

        System.out.println("2. 인스턴스 호출1");
        DecoData data1 = new DecoData();
        data1.instanceCall();

        System.out.println("3. 인스턴스 호출2");
        DecoData data2 = new DecoData();
        data2.instanceCall();
    }
}

staticValue = 1 // <- static 변수는 메서드 영역에서 관리되므로 호출 하면 계속 증가 될것
2. 인스턴스 호출1
instanceValue = 1 // <- instance 변수는 힙 영역에 각각 생성 되므로 호출해도 계속 1 유지
staticValue = 2
3. 인스턴스 호출2
instanceValue = 1
staticValue = 3

// 다음과 같이 출력된다.

→ 그림으로 보면 다음과 같다 🔽


static 메서드의 용어 정리

  • 클래스에 정의한 메서드 (맴버 메서드)의 종류
    1. 인스턴스 메서드 : static이 안 붙은 것 → 객체(인스턴스)를 생성해야 사용할 수 있다.
    2. class 메서드(static 메서드) : static이 붙은 것 → 객체생성하지 않고 바로 class 에 접근 해 사용 가능하다.

static 메서드의 main() 메서드

  • main 메서드는 프로그램의 시작점이다.
  • main 메서드는 static 메서드 이므로 객체 생성없이 바로 실행이 된다.
  • 그래서 main 메서드에서 호출할 때는 static 메서드만 호출 했다.

'자바 공부 > [ 完 ] 자바 실전 - 기본편' 카테고리의 다른 글

9-1 상속  (0) 2024.03.14
8-1. final  (0) 2024.03.12
7-3 static 변수  (0) 2024.03.09
7-2 스텍과 큐 자료구조  (0) 2024.03.09
7-1 자바 메모리 구조  (0) 2024.03.09

static 키워드

  • static 키워드는 주로 멤버 변수와 메서드에 사용된다.

static 변수

  • 클래스의 인스턴스 변수와 다르게 여러곳에서 공유하는 목적으로 사용된다.
  • 특정 class 에 공용으로 함께 사용할 수 있는 변수를 만들기 위해 사용된다.
  • static변수라 할지라도 class의 멤버 변수임은 변함이 없다.
package static1;

public class Data3 {
    public String name;
    public static int count; // <- 이런식으로 맴버 변수에 붙여 사용한다.

    public Data3(String name) {
        this.name = name;
        count++;
    }
}

  • 멤버 변수에 staitc 을 붙이면 static변수, 정적 변수, 클래스 변수라 부른다.
  • static 변수에 접근하는 방식은 객체를 저장한 변수가 아닌 클래스 명을 호출하여 사용한다.
package static1;

public class DataCountMain3 {
    public static void main(String[] args) {
        Data3 data1 = new Data3("A");
        System.out.println("A count = " + Data3.count); // <- class 명 호출

        Data3 data2 = new Data3("B");
        System.out.println("B count = " + Data3.count); // <- class 명 호출

        Data3 data3 = new Data3("C");
        System.out.println("C count = " + Data3.count); // <- class 명 호출
    }
}

A count = 1
B count = 2
C count = 3
// 실행결과는 다음과 같다.
  • static 이 붙은 변수는 힙 영역이 아닌 메서드 영역에서 메서드와 같이 관리된다.

  • 최종적으로 위 코드가 작동 되면 다음과 같은 상태가 된다.

  • 그래서 static 변수에 접근하려면 메서드 영역에 접근 해야 하기 때문에 Data3.count 로 클래스에 직접 들어가야하는것 이다.

staitc 변수 사용 장점

  • static 변수를 사용함으로써 공용 변수를 사용해 편리하게 문제를 해결 할 수 있다.

static 변수 정리

  • static 변수는 클래스인 붕어빵 틀이 특별히 관리하는 변수인 붕어빵이다.
  • 붕어빵 틀(클래스)은 1개 이므로 붕어빵(static 변수)도 1개만 존재한다.
  • 반면 객체(인스턴스)로 생성한 변수들 (맴버 변수)은 객체를 생성한 만큼 변수가 존재하게 된다.


변수와 생명주기

  • 지역변수(매개변수 포함) : 스택 영역안에서만 활동 하고, 메서드가 종료되면 메서드 스택 프레임이 제거되고, 변수도 함께 제거 된다. → 가장 짧은 생명 주기
  • 인스턴스 변수 : 인스턴스에 있는 멤버 변수를 인스턴스라 하고, 인스턴스 변수는 힙 영역을 사용한다. CG가 발생하기 전까지 생존해 있다. → 중간 생명 주기
  • 클래스 변수 : 클래스 변수는 메서드 영역의 static 영역에 보관된다, 해당 class 가 JVM에 로딩 되는 순간 생성 되고, JVM이 종료되면 제거된다. → 가장 긴 생명 주기

static 변수가 정정 변수라고 하는 이유 ?

  • 힙 영역에 생성되는 인스턴스 변수는 동적으로 생성되고, 제거된다 반면 staitc 변수는 거의 프로그램 실행 시점에 딱 만들어지고, 프로그램 종료 시점에 제거된다. → 이런 특성 때문에 정적 변수라고 부른다.

static 변수 추가 사항

  • static 변수를 인스턴스 접근이 가능하나 권장하진 않는다.
// 추가
// 인스턴스를 통한 접근 (비 권장)
Data3 data4 = new Data3("D");
System.out.println("D count = " + data4.count);
  • 이유는 가져다 쓰는 사람 입장에서 힙 영역의 인스턴스 변수라 착각 할 수도 있기 때문이다.

'자바 공부 > [ 完 ] 자바 실전 - 기본편' 카테고리의 다른 글

8-1. final  (0) 2024.03.12
7-4 static 메서드  (0) 2024.03.09
7-2 스텍과 큐 자료구조  (0) 2024.03.09
7-1 자바 메모리 구조  (0) 2024.03.09
6. 접근 제어자  (0) 2024.03.07

스택과 큐 자료 구조

  • 스택 구조
    • 먼저 넣은 것이 바닥에 들어가고, 나중에 넣은 순으로 빼야 한다.
    • 후입 선출 방식이다.
     

  • 큐 구조
    • 먼저 넣은 것이 먼저 나가는 방식 넣은 순서대로 차례대로 나간다.
    • 선입 선출 방식이다.


스택 영역

  • 스택 구조 활용 예
package memory;

public class JavaMemoryMain1 {
    public static void main(String[] args) {
        System.out.println("main start");
        method1(10);
        System.out.println("main end");
    }

    static void method1(int m1) {
        System.out.println("method1 start");
        int cal = m1 * 2;
        method2(cal);
        System.out.println("method1 end");
    }

    static void method2(int m2) {
        System.out.println("method2 start");
        System.out.println("method2 end");
    }
}
// 코드를 실행해보면
main start
method1 start
method2 start
method2 end
method1 end
main end

→ 먼저 실행 된 main 이 마지막에 끝나는 것을 볼 수 있다 .

  • 정리
    • 자바는 스택영역을 사용하여 메서드 호출과 지역변수(매개변수 포함)를 관리 한다.
    • 메서드를 계속 호출하면 스택 프레임이 계속 쌓인다.
    • 스택 프레임이 종료되면 지역 변수도 함께 제거 된다.
    • 스택 프레임이 모두 제거되면 프로그램도 종료된다.

스택 영역과 힙 영역

  • 스택영역에서 힙영역의 메모리를 참조하는 메서드가 모두 종료 되면 힙 영역에 GC가 참조가 사라진 인스턴스 메모리를 제거한다.

→ 2개의 스택 영역에서 힙 영역 객체(인스턴스)를 참조

→ 스택의 후입 선출 방식으로 method2 가 종료 되어 힙 영역 참조 하나가 끊기고

→ method1 이 종료 되면서 힙 영역 객체를 참조하는 것이 모두 사라지게 된다.

→ 참조 하는 것이 없는 힙 영역의 객체는 GC(가비지 컬랙션)에 의해 제거 된다.


'자바 공부 > [ 完 ] 자바 실전 - 기본편' 카테고리의 다른 글

7-4 static 메서드  (0) 2024.03.09
7-3 static 변수  (0) 2024.03.09
7-1 자바 메모리 구조  (0) 2024.03.09
6. 접근 제어자  (0) 2024.03.07
5. 패키지  (0) 2024.03.06

+ Recent posts