Java에서 "최종 클래스"의 요점은 무엇입니까?
Java에 관한 책을 읽고 있으며 전체 클래스를로 선언 할 수 있다고 말합니다 final
. 나는 이것을 사용할 곳을 생각할 수 없다.
나는 프로그래밍에 익숙 하지 않으며 프로그래머가 실제로 프로그램에서 이것을 사용 하는지 궁금 합니다 . 그들이 사용하는 경우, 언제 사용하는지 더 잘 이해하고 사용시기를 알 수 있습니다.
Java가 객체 지향적이고 클래스를 선언하면 final
객체의 특성을 가진 클래스의 아이디어를 멈추지 않습니까?
그들이 사용하는 경우, 언제 사용하는지 더 잘 이해하고 사용시기를 알 수 있습니다.
final
클래스는 단순히 클래스 확장 할 수 없습니다 .
(이것은 클래스의 객체에 대한 모든 참조가 마치로 선언 된 것처럼 행동한다는 것을 의미하지는 않습니다 final
.)
클래스를 final로 선언하는 것이 유용한 경우이 질문의 답변에서 다룹니다.
Java가 객체 지향적이고 클래스를 선언하면
final
객체의 특성을 가진 클래스의 아이디어를 멈추지 않습니까?
어떤 의미에서는 그렇습니다.
클래스를 최종으로 표시하면 해당 코드 부분에 대해 강력하고 유연한 언어 기능이 비활성화됩니다. 일부 클래스는하지만, (그리고 어떤 경우에는 안 할 수 있는 좋은 방법에서 고려의 서브 클래스하도록 설계 할 수 없습니다)가. 이러한 경우 OOP를 제한하더라도 클래스를 최종 클래스로 표시하는 것이 좋습니다. 그러나 최종 클래스는 여전히 최종 클래스가 아닌 다른 클래스를 확장 할 수 있습니다.
관련 기사 : Java : 최종 클래스 작성시기
Java에서는 final
수정자가있는 항목을 변경할 수 없습니다!
여기에는 최종 클래스, 최종 변수 및 최종 메소드가 포함됩니다.
- 마지막 수업은 다른 수업으로 확장 할 수 없습니다
- 최종 변수는 다른 값을 재 할당 할 수 없습니다
- 최종 방법은 재정의 할 수 없습니다
보안상의 이유로 클래스 상속 을 방지 하려는 경우 final이 중요한 시나리오 . 이를 통해 실행중인 코드를 누군가 가 재정의 할 수 없도록 할 수 있습니다 .
또 다른 시나리오는 최적화입니다 .Java 컴파일러는 최종 클래스에서 일부 함수 호출을 인라인한다는 것을 기억합니다. 따라서 호출 a.x()
하고 a가 선언 final
되면 컴파일 타임에 코드가 무엇인지 알고 호출 함수에 인라인 할 수 있습니다. 이것이 실제로 수행되는지 여부는 알 수 없지만 최종적으로는 가능합니다.
가장 좋은 예는
공개 최종 클래스 문자열
불변 클래스이며 확장 할 수 없습니다. 물론, 클래스를 최종적으로 불변으로 만드는 것 이상이 있습니다.
클래스 계층 구조를 Java와 같이 트리로 생각하면 추상 클래스는 분기 일 수 있으며 최종 클래스는 리프 일 수있는 클래스입니다. 이러한 범주에 속하지 않는 수업은 가지와 잎이 될 수 있습니다.
여기서 OO 원칙을 위반하지 않으며 final은 단순히 훌륭한 대칭을 제공합니다.
실제로 객체를 불변으로 만들거나 API를 작성하는 경우 final을 사용하여 클래스의 확장이 아닌 API 사용자에게 신호를 보냅니다.
관련 자료 : Bob Martin 의 공개 원칙 .
주요 인용문 :
확장을 위해 소프트웨어 엔터티 (클래스, 모듈, 기능 등)가 열려 있지만 수정을 위해 닫혀 있어야합니다.
final
키워드는 방법이나 클래스에 사용되는 여부, 자바에서이를 시행 할 수있는 수단입니다.
키워드 final
자체는 최종적인 것을 의미하며 어떤 식 으로든 수정해서는 안됩니다. 클래스가 표시되어 있으면 클래스를 final
확장하거나 하위 클래스 로 만들 수 없습니다. 그러나 문제는 왜 우리가 수업을 표시 final
합니까? IMO에는 여러 가지 이유가 있습니다.
- 표준화 : 일부 클래스는 표준 기능을 수행하며 문자열 조작 또는 수학 함수 등과 관련된 다양한 기능을 수행하는 클래스와 같이 수정되지 않습니다.
- 보안 이유 : 때때로 우리는 다양한 인증 및 암호 관련 기능을 수행하는 클래스를 작성하며 다른 사람이 변경하지 않기를 바랍니다.
나는 마킹 클래스가 final
효율성을 향상 시킨다고 들었지만 솔직히 말해서 많은 무게를 지니고있는이 주장을 찾을 수 없었습니다.
Java가 객체 지향적이며 클래스를 final로 선언하면 객체의 특성을 가진 클래스의 아이디어를 멈추지 않습니까?
아마도 그렇습니다. 그러나 때때로 그것은 의도 된 목적입니다. 때때로 우리는이 클래스의 능력을 확장하여 보안 등의 더 큰 이점을 얻기 위해 그렇게합니다. 그러나 필요한 경우 최종 클래스는 여전히 하나의 클래스를 확장 할 수 있습니다.
참고로 상속보다는 구성을 선호 해야 하며 final
키워드는 실제로이 원칙을 시행하는 데 도움이됩니다.
수업을 "최종"으로 만들 때주의하십시오. 최종 클래스에 대한 단위 테스트를 작성하려면 Michael C. Feathers의 저서 "레거시 코드로 효과적으로 작업하기"에 설명 된 "하위 클래스 및 재정의 방법"기술을 사용하기 위해이 최종 클래스를 서브 클래 싱 할 수 없습니다. . 이 책에서 Feathers는 "진실하게, 봉인과 최종은 잘못된 실수이며, 프로그래밍 언어에 추가되어서는 안된다고 믿기 쉽다. 그러나 실제 결점은 우리에게있다. 우리가 통제 할 수없는 도서관은 문제를 요구하고 있습니다. "
클래스가로 표시 final
되면 클래스 구조를 외부에서 수정할 수 없음을 의미합니다. 이것이 가장 눈에 띄는 곳은 전통적인 다형성 상속을 할 때 기본적으로 class B extends A
작동하지 않습니다. 그것은 기본적으로 코드의 일부 보호하는 방법 (범위)를 .
명확히하기 위해 클래스를 final
표시하면 필드가 표시 final
되지 않으므로 객체 속성이 아니라 실제 클래스 구조가 대신 보호됩니다.
최종 클래스 문제를 해결하려면 :
수업을 마무리하는 두 가지 방법이 있습니다. 첫 번째는 클래스 선언에서 final 키워드를 사용하는 것입니다.
public final class SomeClass {
// . . . Class contents
}
클래스를 final로 만드는 두 번째 방법은 모든 생성자를 private으로 선언하는 것입니다.
public class SomeClass {
public final static SOME_INSTANCE = new SomeClass(5);
private SomeClass(final int value) {
}
마지막으로 표시하면이 테스트 클래스를 살펴 보는 것이 실제로 최종적인 것으로 밝혀지면 문제가 해결됩니다. 언뜻보기에 공개적으로 보입니다.
public class Test{
private Test(Class beanClass, Class stopClass, int flags)
throws Exception{
// . . . snip . . .
}
}
불행히도 클래스의 유일한 생성자는 private이므로이 클래스를 확장 할 수 없습니다. Test 클래스의 경우 클래스가 최종적인 이유는 없습니다. Test 클래스는 암시 적 최종 클래스가 어떻게 문제를 일으킬 수 있는지에 대한 좋은 예입니다.
따라서 암시 적으로 클래스를 생성자 전용으로 만들어서 클래스를 마지막으로 만들 때는이를 마지막으로 표시해야합니다.
final class
새로운 메소드를 추가 할 때 퍼블릭 API가 깨지는 것을 피할 수 있습니다
Base
클래스 의 버전 1에서 다음 을 수행 한다고 가정하십시오 .
public class Base {}
그리고 클라이언트는 :
class Derived extends Base {
public int method() { return 1; }
}
그런 다음 버전 2에서 method
메소드를 추가 하려면 Base
다음 을 수행하십시오 .
class Base {
public String method() { return null; }
}
클라이언트 코드가 손상 될 수 있습니다.
우리가 final class Base
대신 사용했다면 , 클라이언트는 상속 할 수 없었고 메소드 추가는 API를 손상시키지 않을 것입니다.
예, 때로는 보안 또는 속도상의 이유로이를 원할 수도 있습니다. C ++에서도 수행됩니다. 그것은하지 않을 수 가 있지만있는 moreso 프레임 워크를위한 프로그램에 적용. http://www.glenmccl.com/perfj_025.htm
마지막 수업은 확장 할 수없는 수업입니다. 또한 서브 클래스로 대체 할 수 없음을 나타 내기 위해 메소드를 final로 선언 할 수 있습니다.
API 또는 라이브러리를 작성하고 기본 동작을 변경하기 위해 확장되지 않도록하려는 경우 클래스의 서브 클래스 화를 방지하는 것이 특히 유용 할 수 있습니다.
클래스를 최종으로 유지하는 한 가지 장점 :-
String 클래스는 최종적으로 유지되므로 아무도 메서드를 재정의하고 기능을 변경할 수 없습니다. 예를 들어 아무도 length () 메소드의 기능을 변경할 수 없습니다. 항상 문자열의 길이를 반환합니다.
이 클래스의 개발자는 아무도이 클래스의 기능을 변경하기를 원하지 않았으므로 최종 클래스로 유지했습니다.
최종 수업은 연장 할 수 없습니다. 따라서 클래스가 특정 방식으로 동작하기를 원하고 누군가가 덜 효율적이고 악의적 인 코드로 메소드를 재정의하지 않도록하려면 전체 클래스를 원하지 않는 최종 또는 특정 메소드로 선언 할 수 있습니다 변경되었습니다.
클래스를 선언한다고해서 클래스가 인스턴스화되는 것을 막을 수는 없다고해서 클래스가 객체의 특성을 갖는 것을 막을 수는 없습니다. 단지 클래스에서 선언 된 방식대로 메소드를 고수해야한다는 것입니다.
FINAL을 "줄의 끝"이라고 생각하십시오. 그 남자는 더 이상 자손을 낳을 수 없습니다. 따라서 이런 식으로 볼 때, '줄 끝'마커를 클래스에 표시해야하는 수많은 실제 시나리오가 있습니다. 도메인 기반 디자인입니다. 도메인에서 지정된 ENTITY (클래스)가 서브 클래스를 작성할 수 없도록 요구하는 경우이를 FINAL로 표시하십시오.
"최종 태그로 지정해야합니다"클래스를 상속받지 못하게하는 것은 없습니다. 그러나 그것은 일반적으로 "상속의 남용"으로 분류되며, 클래스의 기본 클래스에서 일부 기능을 상속 받기를 원하기 때문에 수행됩니다.
가장 좋은 방법은 도메인을보고 디자인 결정을 지시하는 것입니다.
위에서 말했듯이 아무도 메소드의 기능을 변경할 수 없도록하려면 final로 선언 할 수 있습니다.
예 : 다운로드 / 업로드 용 응용 프로그램 서버 파일 경로, 오프셋을 기준으로 문자열 분할 등의 메서드 이러한 메서드 함수는 변경되지 않도록 Final로 선언 할 수 있습니다. 그리고 그러한 최종 메소드를 별도의 클래스에서 원한다면 해당 클래스를 Final 클래스로 정의하십시오. 따라서 Final 클래스에는 Final 메서드가 최종 클래스가 아닌 클래스에서 선언 및 정의 될 수있는 모든 최종 메서드가 있습니다.
Android Looper 클래스가 이에 대한 좋은 예입니다. http://developer.android.com/reference/android/os/Looper.html
Looper 클래스는 다른 클래스에서 재정의하지 않는 특정 기능을 제공합니다. 따라서 여기에는 하위 클래스가 없습니다.
Employee
메소드 가있는 클래스가 있다고 가정 해 봅시다 greet
. greet
메소드가 호출 되면 단순히 인쇄합니다 Hello everyone!
. 이것이 방법 의 예상되는 동작 입니다greet
public class Employee {
void greet() {
System.out.println("Hello everyone!");
}
}
이제 아래 표시된대로 GrumpyEmployee
서브 클래스 Employee
및 greet
메소드를 재정의하십시오 .
public class GrumpyEmployee extends Employee {
@Override
void greet() {
System.out.println("Get lost!");
}
}
이제 아래 코드에서 sayHello
메소드를 살펴보십시오 . 그것은 소요 Employee
매개 변수로 인스턴스를하고 말 것이라고 기대하는 인사 메소드를 호출 Hello everyone!
하지만 우리가 얻을 것은 Get lost!
. 이 행동의 변화는Employee grumpyEmployee = new GrumpyEmployee();
public class TestFinal {
static Employee grumpyEmployee = new GrumpyEmployee();
public static void main(String[] args) {
TestFinal testFinal = new TestFinal();
testFinal.sayHello(grumpyEmployee);
}
private void sayHello(Employee employee) {
employee.greet(); //Here you would expect a warm greeting, but what you get is "Get lost!"
}
}
이 상황은 수업이 이루어진 경우 피할 수 있습니다 . 클래스가로 선언되지 않은 경우 건방진 프로그래머가 발생할 수있는 혼란의 정도를 상상해보십시오 .Employee
final
String
final
최종 수업은 더 이상 연장 할 수 없습니다. 자바에서 클래스를 상속받을 필요가 없다면이 접근법을 사용할 수 있습니다.
오버라이드되지 않도록 클래스의 특정 메소드를 작성해야하는 경우 마지막 키워드를 앞에 추가 할 수 있습니다. 클래스는 여전히 상속 가능합니다.
자바에서 최종 키워드는 아래 경우에 사용됩니다.
- 최종 변수
- 최종 방법
- 최종 수업
자바에서 최종 변수는 재 할당 할 수없고, 최종 클래스 는 확장 될 수없고, 최종 메소드는 재정의 할 수 없습니다.
객체 지향은 상속에 관한 것이 아니라 캡슐화에 관한 것입니다. 그리고 상속은 캡슐화를 깨뜨립니다.
클래스 파이널 선언은 많은 경우에 적합합니다. 색상이나 금액과 같은“가치”를 나타내는 모든 물체는 최종적 일 수 있습니다. 그들은 스스로 서 있습니다.
라이브러리를 작성하는 경우 클래스를 명시 적으로 들여 쓰지 않으면 클래스를 최종 클래스로 만듭니다. 그렇지 않으면 사람들이 클래스를 파생시키고 메소드를 재정 의하여 가정 / 불변을 깨뜨릴 수 있습니다. 보안에 영향을 줄 수도 있습니다.
"Effective Java"의 Joshua Bloch는 상속을 위해 명시 적으로 디자인하거나이를 금지 할 것을 권장하며 상속을 위해 디자인하는 것은 쉽지 않다고 지적합니다.
참고 URL : https://stackoverflow.com/questions/5181578/what-is-the-point-of-final-class-in-java
'development' 카테고리의 다른 글
PHP는 T_PAAMAYIM_NEKUDOTAYIM을 기대합니까? (0) | 2020.02.11 |
---|---|
Git으로 큰 바이너리 파일 관리 (0) | 2020.02.11 |
프로그래밍 방식으로 iPhone에서 SMS를 보내는 방법은 무엇입니까? (0) | 2020.02.11 |
StackOverflow의 입력 태그와 같은 jQuery 자동 완성 태그 지정 플러그인? (0) | 2020.02.11 |
반환 유형이없는 기능 위임 (0) | 2020.02.11 |