본문 바로가기
TIL

2024.04.18 41일차 JAVA 상속2, static, final, 열거형

by Song.dev 2024. 4. 18.

 

상속

- Child 필드에 a, b 없는데도 childMethod에서 this.a 사용할 때 에러 발생하지 않음

 

- Child에서 this.a, this.b가 없네?

  → 자동으로 super 링크로 부모에게 접근한 뒤 부모의 a, b를 가져옴  ( this.a == super.a )

public class Child extends Parent {

//    int a;
//    double b;
    boolean c;

    Child() {
        // super(); // 쓰지 않아도 자동으로 적용됨
        // 부모클래스의 기본생성자를 호출
        this(100);
        System.out.println("Child 클래스의 생성자 호출!");
        this.c = true;
    }
    Child(int x) {
        System.out.println("Child 클래스의 2번째 생성자 호출!");
    }

    void childMethod() {
        System.out.println("child a = " + this.a);
//        System.out.println("child a = " + super.a);
        System.out.println("child b = " + this.b);
//        System.out.println("child b = " + super.b);
        System.out.println("child c = " + this.c);
    }

}

====
child a = 15
child b = 20.5
child c = true

 

 

 

** 부모 클래스에 기본생성자 없고 다른 생성자는 있을 때 자식 클래스에서 에러 발생

더보기

자바에서는 super()가 숨어있는데 부모 가보니 기본생성자가 없어서 에러 발생

해결방법

super(매개변수)로 부모 클래스를 생성하도록 명시함

 

    public Warrior(String nickname) {
        super(nickname);   ---> 이렇게 매개변수 있는 생성자를 명시하면 에러 안 남
        this.rage = 100;
    }

 

 

 

static 키워드

사용 제한자(usage modifier)

 

 * static 필드 선언

static 타입 필드명
static int x;
int y;

 

* static 필드 또는 메서드 호출

클래스명.필드명/메서드명 
Count.b;
Count.add();

 

  • 정적 필드 : 모든 객체가 공유, 정적 메서드 public static void m1() { }
  • 인스턴스 필드 : 각 객체별로 따로 관리, 인스턴스 메서드 public void m2() { }
  • 생성자, 클래스에는 static 사용 X
    * inner class 는 예외
  • static 데이터는 객체 생성없이 접근 가능
  • static이 저장되는 공간은 Heap 안에 객체와 따로 있음
  • C언어의 전역변수처럼 동작함
  • static 블록 내부에서는 this를 사용할 수 없음 (객체 생성 없이도 호출되므로)
    *** static블록 내부에서 인스턴스멤버를 사용하려면 반드시 객체를 생성해서 주소값을 통해 참조해야 함

** 정적 멤버 : 정적 필드 + 정적 메서드

 

 

static 필드는 Heap에서 별도의 Data 공간에 있으며 클래스명으로 접근 가능

 

static을 언제 붙여야 하나?

  • 메서드 내부에서 non-static 데이터를 참조하고 있는 메서드는 해당 변수의 정확한 위치(객체의 주소값)을 알려줘야 하기 때문에 정적 메서드로 선언하기가 부적합
  • 메서드 내부에서 인스턴스 변수를 사용하지 않고 범용성 있게 사용하는 메서드는 static키워드를 붙여서 정적 메서드로 선언하는 것이 좋음

 

static initializer 정적 초기화자 

static 필드의 생성자 같은 역할 (static 필드 초기화 담당)

static {
   필드명 = 초기값;
}
public class Person {

    String name;
    int age;
    static String nation; // 국가

    // 정적 초기화자 (static initializer)
    // static필드의 생성자같은 역할 (static필드 초기화담당)
    static {
        nation = "대한민국";
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
//        this.nation = "대한민국"; // 객체 생성해야지만 nation 세팅됨

    }
}

 

 

 

*** static 내부에서 instance 사용 방법

    1. 내부에서 객체를 생성 후 c3.y 

    2. 매개변수로 Count c3를 받은 뒤 c3.y

    // 정적 메서드 : 모든 객체가 공유하며 객체 생성없이 접근 가능
    public static void m1(Count c3) {
        System.out.println("static method call!");
        System.out.println("x (static) = " + x);
        
        // static메서드 내부에서는 instance필드를 직접 참조할 수 없다.
        // static은 객체 생성 없이 호출되므로 this를 가질 수 없기 때문에
        
//        Count c3 = new Count();  
        System.out.println("y (instance) = " + c3.y); // 그냥 사용하면 에러
        m2(); // 인스턴스 메서드 호출도 안됨 this.m2()이므로 (c3.m2()는 가능)
    }

 

import static

static 멤버를 사용할 때 import하면 클래스명. 을 생략할 수 있음

    ex ) String name = SimpleInput.input("이름: "); → String name = input("이름: ");

import static util.SimpleInput.input;

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

        Calculator redCal = new Calculator();
        Calculator blueCal = new Calculator();

//        redCal.calcArea(5);
//        blueCal.calcArea(5);
        // 어느 계산기로 하든 동일
        Calculator.calcArea(5);

        // 어떤 계산기에 칠해야 하는지 알려줘야 함
        redCal.paint("빨강");
        blueCal.paint("파랑");
        String name = input("이름: ");

 

 


 싱글톤 디자인 패턴

1. private 생성자

2. 자신의 클래스 내부에서 스스로의 객체 단 1개 생성

3. 외부에서 객체에 접근할 수 있도록 미리 만든 객체의 주소값을 public static 메서드를 통해 리턴

 

  • static개념을 이해해야 사용할 수 있는 코드 디자인 패턴
  • 싱글톤(Singleton) 패턴은 단 하나의 인스턴스만 생성하도록 보장
  • 무분별한 객체의 생성을 막고, 메모리의 낭비를 막을 수 있게 하는 코드 디자인 패턴
  • 필드가 static변수로 선언되다 보니 getInstance() 말고 직접 변수로 접근할 수 있기 때문에 private 을 붙여 접근 방지

 

public class Singleton {

	//생성자에 private
	private Singleton() {
		System.out.println("객체가 생성됨!");
	}
	
	//스스로의 객체 생성
	private static Singleton s = new Singleton();
	
	//객체 주소값을 리턴하는 메서드
	public static Singleton getInstance() {
		return s;
	}
	
	/////////////////////////////////////////////
	
	public void method1() {
		System.out.println("여러 군데에서 쓰이는 중요한 메서드");
	}
	
	public void method2() {
		System.out.println("꼭 사용해야 하는 귀한 메서드");
	}
}

 


 

final 키워드

final 키워드는 필드, 메서드, 클래스, 지역변수에 선언이 가능

  • final + 변수: 재할당 금지, 불변의 값, 반드시 초기화 필요
  • final + 메서드: 오버라이딩 금지 
  • final + 클래스: 상속 불가 (부모 클래스, super 클래스에 붙일 경우)

 

public class Person {
	
	final String nation = "대한민국";  ----> 선언과 동시에 초기화 
	final String name;
	int age;
	                              ----------> 생성자를 이용해 인스턴스마다 초기화
	//생성자를 이용해서 초기화.  
    Student(final String ssn) {
//        ssn = "DFDfdfd"; 지역변수 레벨에서 조작이 가능하기 때문에 매개변수에도 final 권장
		this.name = name;
	}

}

 

 

 

상수 constant

static final double SURFACE_AREA; 
static {
   SURFACE_AREA = RADIUS * RADIUS * Math.PI
}
  • 고정된 불변의 값
  • 불변성 + 전역성 (모든 객체가 해당 값을 공유할 수 있으며 유일한 값)
  • static과 final을 같이 선언해서 상수로 선언
  • 상수는 다른 일반 변수와의 차이를 위해 모든 글자를 대문자로 선언
  • 두 단어를 연결해서 선언하려면 _를 이용하여 연결

static final 타입 대문자상수명

 

import static day08.final_.quiz1.WeatherConstants.*; --> import static으로 클래스명 생략

public class WeatherAnalyzer {
    public static boolean checkTemperatureAlert(double temperature) {
        return temperature > MAX_TEMPERATURE_ALERT || temperature < MIN_TEMPERATURE_ALERT;
        // WeatherConstants.MAX_TEMPERATURE_ALERT
    }

    public static boolean checkPrecipitationAlert(double precipitation) {
        return precipitation > PRECIPITATION_ALERT;
    }
}

 

*** 경우의 수가 정해진 String 변수는 상수를 활용하면 코드 가독성도 높아지고 오타 등의 실수를 방지할 수 있음

 

 

 

Enum 키워드 : 열거형

  • 열거형(Enum)은 일련의 고정된 상수들을 한 곳에 모아 관리할 수 있도록 하는 자료형
  • 자바의 enum은 클래스처럼 동작하며, 각 상수는 enum 타입의 인스턴스
  • 제한된 값(상수) 집합을 정의할 때 사용
  • enum 타입은 java.lang.Enum 클래스를 상속받음
  • enum 내의 각 항목은 고유의 속성과 메서드를 가질 수 있음
  • enum상태 집합, 옵션 집합 등을 표현할 때 유용

 

열거형 선언

public enum Day {
     SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY
}
public enum List {
     A("첫번째", 1), B("두번째", 2), C("세번째", 3);

    private String ordianlString;  // 열거형 상수의 속성이나 값을 필드로 선언
    private Int cardinalNum;

   List(String ordinal, int cardinal) {  // 생성자
       this.ordinalString = ordinal;
       this.cardinalNum = cardinal;
   } 

 

  • A, B, C는 List 열거형 클래스의 인스턴스. 즉, A, B, C는 List 클래스의 객체로 간주
  • enum의 생성자는 기본적으로 prviate 으로 간주  
  • enum 타입은 equals 없이 '==' 비교연산자로 비교 가능

 

 

열거형의 고급 기능

  • 메서드 및 필드 추가
    열거형에 메서드, 필드, 생성자를 추가할 수 있으며, 각 열거형 상수는 생성 시 지정된 값으로 초기화
  • 열거형의 메서드
    values(): 모든 열거 상수를 배열로 반환

    valueOf(String name): 지정된 이름의 열거 상수를 반환
TeamRole[] values = TeamRole.values(); 
System.out.println(Arrays.toString(values)); // [LEADER, DEVELOPER, DESIGNER, TESTER]

TeamRole dsg = TeamRole.valueOf("DESIGNER");
System.out.println("dsg = " + dsg);  // dsg = DESIGNER

 

** 열거형으로 여러 필드 사용 가능

package day08.enum_;

// enum: 열거형 - 상수를 모아 놓은 클래스
public enum PizzaStatus {

    ORDERED("주문 완료", 5)
    , READY("준비 완료", 20)
    , DELIVERED("배달 완료", 30);

    private String description;
    private int timeToSetUp;

    PizzaStatus(String description, int timeToSetUp) {
        this.description = description;
        this.timeToSetUp = timeToSetUp;
    }

    public String getDescription() {
        return description;
    }

    public int getTimeToSetUp() {
        return timeToSetUp;
    }
}