final, abstract

서린·2024년 5월 11일

혼자개발

목록 보기
81/82

자바 제어자 - final, abstract

p.379

11.1 final 제어자

final 제어자는 필드, 지역변수, 메서드, 클래스 앞에 위치 가능
어디에 위치하느냐에 따라 의미가 다르다.

1. final 변수

한 번 대입된 값을 수정할 수 없다.
한 번 대입된 값이 최종값이 된다.

class A1 { // 선언과 동시에 값을 대입 
	int a = 3; 
    final int b = 5;
    A1() {
    }
}

class A2 { // 선언과 값의 대입을 분리
	int a; 
    final int b;
    A2() {
    	a = 3;
        b = 5;
    }
}

class A3 { // final 필드값을 대입한 후에는 추가 값 대입 불가능
	int a = 3; 
    final int b = 5;
    A3() {
    	a = 7;
        // b = 9; 불가능
    }
}
A1 a1 = new A1();
a1.a = 7;
//a1.b = 9; 값 수정 불가능

A2 a2 = new A2();
a2.a = 7;
//a2.b = 9; 값 수정 불가능

필드나 지역변수가 final로 선언되고 A a = new A()로 객체를 생성했을 때 메모리 구조

class A {
	int a;
    final int b;
    A() {
		a = 3;
        b = 5;
    }
}

필드는 멤버라서
final 필드든 일반 필드든 객체속에 포함된다.
이때 final로 선언된 필드값은 상수 영역에 1개가 복사된다.

final 지역변수를 포함하고 있는 메서드를 호출했을 때의 메모리 구조

class B {
	void bcd() {
    	int a = 3;
        final int b = 5;
    }
}
클래스 B를 정의하고 B b = new B();로 객체를 생성한 후 b.bcd() 메서드를 호출 했을 때

지역 변수들은 스택 메모리에 저장되지만 
final 지역 변수는 상수 영역에 1개가 복사된다. 
복사는 값을 선언한 후 최초로 값이 초기화될 때 딱 한 번 일어난다.

final 메서드와 final 클래스

final 메서드로 정의하면 자식클래스에서 해당 메서드를 오버라이딩 할 수 없다. = 메서드의 기능을 변경할 수 없다.

final 클래스는 상속 자체가 아예 불가능하다. = 최종 클래스의 의미로 자식 클래스가 없다.

11.2 abstract 제어자

'추상적인' 이라는 의미로 '구체적이지 않다'는 의미
추상 메서드는 중괄호가 없는 메서드로 메서드의 기능 자체가 정의되지 않으며 ;으로 끝난다.

일반 클래스를 상속해 오버라이딩

class Animal {
	void cry() {
    }
}

class Cat extends Animal {
	void cry() {
    	System.out.print("야옹");
    }
}

class Dog extends Animal {
	void cry() {
    	System.out.print("멍멍");
    }
}

public class AbstractModifier_1 {
	public static void main(String[] args) {
    	//객체 생성
        Animal animal1 = new Cat();
        Animal animal2 = new Dog();
        
        //메서드 호출
        animal1.cry(); //야옹
        animal2.cry(); //멍멍
    }
}
Animal 클래스의 cry() 메서드가 아무 기능을 수행하지 않는다면 
중괄호 자체가 없는 미완성 메서드인 추상 메서드로 정의하는 것이 효율적이다.

주의할점!
추상 메서드를 1개 이상 포함하고 있는 클래스는 반드시 추상 클래스로 정의 해야한다. 
Animal 클래스의 cry() 메서드를 추상 메서드로 만들면 Animal 클래스는 반드시 추상 클래스여야 한다.

추상 클래스를 상속해 오버라이딩

abstract class Animal {
	abstract void cry() {
    }
}

class Cat extends Animal {
	void cry() {
    	System.out.print("야옹");
    }
}

class Dog extends Animal {
	void cry() {
    	System.out.print("멍멍");
    }
}

public class AbstractModifier_2 {
	public static void main(String[] args) {
    	//객체 생성
        Animal animal1 = new Cat();
        Animal animal2 = new Dog();
        
        //메서드 호출
        animal1.cry(); //야옹
        animal2.cry(); //멍멍
    }
}

abstract의 장점

일반 클래스로 정의했을 때,
자식클래스에서 cry() 메서드를 오버라이딩 하는 과정에서 메서드명에 오타가 (cRy())생겼다고 가정해보면
자식클래스에서는 오버라이딩이 아니라 추가로 새로운 메서드를 정의한 셈이므로 2개의 메서드가 존재할 것이다.

추상 클래스를 상속받은 Cat클래스 내부에서는
상속받은 추상 메서드인 cry()와 새롭게 정의한 cRy() 메서드가 있는 셈이다.
이때 Cat 클래스는 오버라이딩도 하지 않고, 자신을 추상 클래스로 정의하지도 않았으므로 오류가 발생한다.

0개의 댓글