답변:
두 가지 차이점을 생각할 수 있습니다
스칼라 프로그래밍에는 "특성 또는 특성이 아닌가?" 라는 섹션이 있습니다. 이 질문을 해결합니다. 첫 번째 에디션은 온라인으로 제공되므로 여기에 모든 내용을 인용해도 무방합니다. (스칼라 프로그래머라면 누구나이 책을 구입해야합니다) :
재사용 가능한 동작 모음을 구현할 때마다 특성 또는 추상 클래스를 사용할지 결정해야합니다. 확실한 규칙은 없지만이 섹션에는 고려해야 할 몇 가지 지침이 있습니다.
동작이 재사용되지 않으면 구체적인 클래스로 만드십시오. 결국 재사용 가능한 동작은 아닙니다.
관련이없는 여러 클래스에서 재사용 할 수 있다면 특성으로 만드십시오. 특성 만 클래스 계층의 다른 부분에 혼합 할 수 있습니다.
Java 코드에서 상속 하려면 추상 클래스를 사용하십시오. 코드가있는 특성은 가까운 Java 아날로그를 갖지 않기 때문에 Java 클래스의 특성에서 상속하는 것이 어색한 경향이 있습니다. 스칼라 클래스에서 상속하는 것은 Java 클래스에서 상속하는 것과 정확히 같습니다. 한 가지 예외로, 추상 멤버 만있는 스칼라 특성은 Java 인터페이스로 직접 변환되므로 Java 코드에서 상속 될 것으로 예상되는 경우에도 해당 특성을 자유롭게 정의해야합니다. Java와 Scala를 함께 사용하는 방법에 대한 자세한 내용은 29 장을 참조하십시오.
컴파일 된 형식으로 배포하려는 경우 외부 그룹에서 상속 된 클래스를 작성하려는 경우 추상 클래스를 사용하는 것이 좋습니다. 문제는 특성이 멤버를 얻거나 잃을 때 특성을 상속하는 클래스가 변경되지 않은 경우에도 다시 컴파일해야한다는 것입니다. 외부 클라이언트가 동작을 상속하는 대신 동작 만 호출하는 경우 특성을 사용하는 것이 좋습니다.
효율성이 매우 중요한 경우 클래스 사용을 고려하십시오. 대부분의 Java 런타임은 클래스 멤버의 가상 메소드 호출을 인터페이스 메소드 호출보다 빠른 조작으로 만듭니다. 특성은 인터페이스로 컴파일되므로 약간의 성능 오버 헤드가 발생할 수 있습니다. 그러나 문제의 특성이 성능 병목을 구성하고 클래스를 사용하면 실제로 문제가 해결된다는 증거가있는 경우에만이 선택을해야합니다.
위 내용을 고려한 후에도 여전히 모르는 경우 에는 특성으로 시작하십시오. 나중에 언제든지 변경할 수 있으며 일반적으로 특성을 사용하면 더 많은 옵션을 열 수 있습니다.
@Mushtaq Ahmed가 언급했듯이, 특성은 매개 변수가 클래스의 기본 생성자로 전달 될 수 없습니다.
또 다른 차이점은의 치료입니다 super
.
클래스와 특성의 다른 차이점은 클래스에서는
super
호출이 정적으로 바인딩되고 특성에서는 동적으로 바인딩된다는 것입니다.super.toString
클래스 를 작성 하면 어떤 메소드 구현이 호출되는지 정확히 알 수 있습니다. 그러나 특성에 동일한 것을 쓰면 특성을 정의 할 때 수퍼 호출을 호출하는 메소드 구현이 정의되지 않습니다.
자세한 내용은 12 장의 나머지 부분 을 참조하십시오.
편집 1 (2013) :
추상 클래스가 특성과 비교하여 동작하는 방식에는 미묘한 차이가 있습니다. 선형화 규칙 중 하나는 클래스의 상속 계층 구조를 유지한다는 점입니다.이 클래스는 나중에 체인에서 추상 클래스를 푸시하는 경향이 있지만 특성을 행복하게 혼합 할 수 있습니다. 특정 상황에서는 실제로 클래스 선형화의 후자 위치에있는 것이 좋습니다 따라서 추상 클래스를 사용할 수 있습니다. Scala의 클래스 선형화 제한 (mixin order)을 참조하십시오 .
편집 2 (2018) :
스칼라 2.12부터 특성의 이진 호환성 동작이 변경되었습니다. 2.12 이전에는 특성을 멤버를 추가하거나 제거하려면 클래스가 변경되지 않은 경우에도 특성을 상속하는 모든 클래스를 다시 컴파일해야했습니다. 이는 특성이 JVM에서 인코딩 된 방식 때문입니다.
Scala 2.12부터 특성 은 Java 인터페이스로 컴파일 되므로 요구 사항이 약간 완화되었습니다. 특성이 다음 중 하나를 수행하는 경우 해당 서브 클래스에는 여전히 재 컴파일이 필요합니다.
- 필드 정의 (
val
또는var
이지만 상수는 괜찮습니다 –final val
결과 유형 없음)- 부름
super
- 본문의 이니셜 라이저 문
- 수업 연장
- 올바른 초 특징에서 구현을 찾기 위해 선형화에 의존
그러나 특성이 없으면 바이너리 호환성을 손상시키지 않으면 서 특성을 업데이트 할 수 있습니다.
If outside clients will only call into the behavior, instead of inheriting from it, then using a trait is fine
-누군가 여기서 차이점이 무엇인지 설명 할 수 있습니까? extends
vs with
?
extends
하고 with
. 순전히 구문 적입니다. 여러 템플릿에서 상속하면 첫 번째는 extend
이고 나머지는 모두 얻 with
습니다. with
쉼표로 생각하십시오 class Foo extends Bar, Baz, Qux
.
스칼라 의 Odersky et al 's Programming 은 가치가있는 것이 무엇이든 의심 할 때 특성을 사용할 것을 권장합니다. 필요할 경우 언제든지 나중에 추상 클래스로 변경할 수 있습니다.
여러 추상 클래스를 직접 확장 할 수는 없지만 여러 특성을 클래스로 혼합 할 수 있다는 사실 외에도 특성의 슈퍼 호출이 동적으로 바인딩되기 때문에 특성을 스택 할 수 있다고 언급 할 가치가 있습니다 (이전에 클래스 또는 특성이 혼합되어 있음) 현재 하나).
초록 클래스와 특성의 차이점에 대한 토마스의 대답에서 :
trait A{
def a = 1
}
trait X extends A{
override def a = {
println("X")
super.a
}
}
trait Y extends A{
override def a = {
println("Y")
super.a
}
}
scala> val xy = new AnyRef with X with Y
xy: java.lang.Object with X with Y = $anon$1@6e9b6a
scala> xy.a
Y
X
res0: Int = 1
scala> val yx = new AnyRef with Y with X
yx: java.lang.Object with Y with X = $anon$1@188c838
scala> yx.a
X
Y
res1: Int = 1
추상 클래스는 동작을 포함 할 수 있습니다-생성자 인수 (특성으로는 불가능)로 매개 변수화 할 수 있으며 작업 엔티티를 나타냅니다. 특성은 하나의 기능, 즉 하나의 기능의 인터페이스 인 단일 기능 만 나타냅니다.
trait Enumerable
많은 도우미 함수로 정의 할 때 동작 이라고 부르지 않고 하나의 기능과 연결된 기능 만 호출합니다 .