달력

12

« 2018/12 »

  •  
  •  
  •  
  •  
  •  
  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  
  •  
  •  

'상속'에 해당되는 글 2

  1. 2010.12.09 가급적 상속보다는 컴포지션을 사용하자.
  2. 2010.12.08 상속

일단 상속을 피해야하는 이유에 대해서 구글링과 책자를 찾아보았다.

일단 구글링 중에 무지 좋은 사이트 발견 http://www.javaworld.com/

그중에 Allen Holub 분의 Why extends is evil (왜 상속이 나쁠까) 라는 글을 발견

원문 : http://www.javaworld.com/javaworld/jw-08-2003/jw-0801-toolbox.html

일단 자세한건 주소로 들어가서 보고

핵심은

Losing Flexibility
Coupling
The fragile base-class problem
Framework
Summing up fragile base classes

이정도랄까.

(보면서 흥미로웠던건 아직 안봤던 GOF -Gang Of Four Design Pattern-  에서 인터페이스 상속을 지지한다고 한다.)

각각 내용은 나중에 따로 따로 블로깅 하기로 하고 슬슬 책 내용을 공부하자.

여기서 핵심은 요약 부분정리 ㅋ

상속은 강력하지만 캡슐화를 위배하므로 문제가 된다. 그리고 서브 클래스와 수퍼 클래스간에 진정한 서브 타입 관계가 있을 때만 적합하다. 만일 서브 클래스가 수퍼 클래스와 다른 패키지에 있고, 수퍼 클래스가 상속을 위해 설계된 것이 아니라면 상속은 서브 클래스를 허약하게 만들 수 있다.

그냥 이 항목 , 다음 항목은 상속에 대한 문제점을 분석하는게 낫겠다.

Posted by 유쾌한순례자
2010.12.08 19:50

상속 Study/Java2010.12.08 19:50

EJ2E 항목 16 가급적 상속 보다는 컴포지션을 사용하자 공부전에 상속 복습.

자바의 꽃이자 생명이라고 생각했던 상속.

자바의 정석 : 상속이란, 기존의 클래스를 재사용하여 새로운 클래스를 작성하는 것이다. 상속을 통해서 클래스를 작성하면, 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있고 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 매우 용이하다.


즉 자식이 부모 꺼 쓸때 라고 생각하면 쉽다 -.-

쉽게 예제를 들어보고 밑에 JLS 부분을 적어둬야겠다.


class Car {
protected int carNum = 2011;
void name(){
System.out.println("택시입니다");
}
public class Taxi extends Car{
public static void main(String args[]){
Car car = new Car();
System.out.println(car.carNum);
car.name();
}
}

결과값
2011
택시입니다.

자식인 Taxi 에서 부모인 Car의 모든 것을 사용해보았다. 다음은 JLS 에서는 뭐라고 설명해놨나 발췌


8.1.4 Superclasses and Subclasses

The optional extends clause in a normal class declaration specifies the direct
superclass of the current class.
Super:
extends ClassType
The following is repeated from §4.3 to make the presentation here clearer:
ClassType:
TypeDeclSpecifier TypeArgumentsopt
A class is said to be a direct subclass of its direct superclass. The direct superclass
is the class from whose implementation the implementation of the current
class is derived. The direct superclass of an enum type E is Enum<E>. The
extends clause must not appear in the definition of the class Object, because it is
the primordial class and has no direct superclass.
Given a (possibly generic) class declaration for C<F1,...,Fn>, ,
, the direct superclass of the class type (§4.5) C<F1,...,Fn> is the type
given in the extends clause of the declaration of C if an extends clause is present,
or Object otherwise.
Let C<F1,...,Fn>, , be a generic class declaration. The direct superclass
of the parameterized class type C<T1,...,Tn> , where Ti, , is a type, is
D<U1 theta , ..., Uk theta>, where D<U1,...,Uk> is the direct superclass of
C<F1,...,Fn>, and theta is the substitution [F1 := T1, ..., Fn := Tn].
The ClassType must name an accessible (§6.6) class type, or a compile-time
error occurs. If the specified ClassType names a class that is final (§8.1.1.2),
then a compile-time error occurs; final classes are not allowed to have subclasses.
It is a compile-time error if the ClassType names the class Enum or any
invocation of it. If the TypeName is followed by any type arguments, it must be a
correct invocation of the type declaration denoted by TypeName, and none of the
type arguments may be wildcard type arguments, or a compile-time error occurs.
In the example:
class Point { int x, y; }
final class ColoredPoint extends Point { int color; }
class Colored3DPoint extends ColoredPoint { int z; } // error
the relationships are as follows:
• The class Point is a direct subclass of Object.
• The class Object is the direct superclass of the class Point.
• The class ColoredPoint is a direct subclass of class Point.
n ≥ 0
C ≠ Object
n > 0
1 ≤ i ≤ n

• The class Point is the direct superclass of class ColoredPoint.
The declaration of class Colored3dPoint causes a compile-time error because it
attempts to extend the final class ColoredPoint.
The subclass relationship is the transitive closure of the direct subclass relationship.
A class A is a subclass of class C if either of the following is true:
• A is the direct subclass of C.
• There exists a class B such that A is a subclass of B, and B is a subclass of C,
applying this definition recursively.
Class C is said to be a superclass of class A whenever A is a subclass of C.
In the example:
class Point { int x, y; }
class ColoredPoint extends Point { int color; }
final class Colored3dPoint extends ColoredPoint { int z; }
the relationships are as follows:
• The class Point is a superclass of class ColoredPoint.
• The class Point is a superclass of class Colored3dPoint.
• The class ColoredPoint is a subclass of class Point.
• The class ColoredPoint is a superclass of class Colored3dPoint.
• The class Colored3dPoint is a subclass of class ColoredPoint.
• The class Colored3dPoint is a subclass of class Point.
A class C directly depends on a type T if T is mentioned in the extends or implements
clause of C either as a superclass or superinterface, or as a qualifier of a
superclass or superinterface name. A class C depends on a reference type T if any
of the following conditions hold:
• C directly depends on T.
• C directly depends on an interface I that depends (§9.1.3) on T.
• C directly depends on a class D that depends on T (using this definition recursively).
It is a compile-time error if a class depends on itself.
For example:
class Point extends ColoredPoint { int x, y; }
class ColoredPoint extends Point { int color; }

causes a compile-time error.
If circularly declared classes are detected at run time, as classes are loaded
(§12.2), then a ClassCircularityError is thrown.

그 다음은 JLS (8.2.1 Example of Inheritance 총 발췌) 핵심사항 8.2.1.2 Inheritance with public and protected


8.2.1 Examples of Inheritance
This section illustrates inheritance of class members through several examples.
8.2.1.1 Example: Inheritance with Default Access
Consider the example where the points package declares two compilation units:
package points;
public class Point {
int x, y;
public void move(int dx, int dy) { x += dx; y += dy; }
}
and:
package points;
public class Point3d extends Point {
int z;
public void move(int dx, int dy, int dz) {
x += dx; y += dy; z += dz;
}
}
and a third compilation unit, in another package, is:
import points.Point3d;
class Point4d extends Point3d {
int w;
public void move(int dx, int dy, int dz, int dw) {
x += dx; y += dy; z += dz; w += dw; // compile-time errors
}
}
Here both classes in the points package compile. The class Point3d inherits the
fields x and y of class Point, because it is in the same package as Point. The
class Point4d, which is in a different package, does not inherit the fields x and y
of class Point or the field z of class Point3d, and so fails to compile.
A better way to write the third compilation unit would be:
import points.Point3d;
class Point4d extends Point3d {
int w;
public void move(int dx, int dy, int dz, int dw) {
super.move(dx, dy, dz); w += dw;
}
}
using the move method of the superclass Point3d to process dx, dy, and dz. If
Point4d is written in this way it will compile without errors.
8.2.1.2 Inheritance with public and protected
Given the class Point:
package points;
public class Point {
public int x, y;
protected int useCount = 0;
static protected int totalUseCount = 0;
public void move(int dx, int dy) {
x += dx; y += dy; useCount++; totalUseCount++;
}
}
the public and protected fields x, y, useCount and totalUseCount are inherited
in all subclasses of Point.
Therefore, this test program, in another package, can be compiled successfully:
class Test extends points.Point {
public void moveBack(int dx, int dy) {
x -= dx; y -= dy; useCount++; totalUseCount++;
}
}
8.2.1.3 Inheritance with private
In the example:
class Point {
int x, y;
void move(int dx, int dy) {
x += dx; y += dy; totalMoves++;
}
private static int totalMoves;
void printMoves() { System.out.println(totalMoves); }
}
class Point3d extends Point {
int z;
void move(int dx, int dy, int dz) {
super.move(dx, dy); z += dz; totalMoves++;
}
}
the class variable totalMoves can be used only within the class Point; it is not
inherited by the subclass Point3d. A compile-time error occurs because method
move of class Point3d tries to increment totalMoves.
8.2.1.4 Accessing Members of Inaccessible Classes
Even though a class might not be declared public, instances of the class might be
available at run time to code outside the package in which it is declared by means
a public superclass or superinterface. An instance of the class can be assigned to
a variable of such a public type. An invocation of a public method of the object
referred to by such a variable may invoke a method of the class if it implements or
overrides a method of the public superclass or superinterface. (In this situation,
the method is necessarily declared public, even though it is declared in a class
that is not public.)
Consider the compilation unit:
package points;
public class Point {
public int x, y;
public void move(int dx, int dy) {
x += dx; y += dy;
}
}
and another compilation unit of another package:
package morePoints;
class Point3d extends points.Point {
public int z;
public void move(int dx, int dy, int dz) {
super.move(dx, dy); z += dz;
}
public void move(int dx, int dy) {
move(dx, dy, 0);
}
}
public class OnePoint {
public static points.Point getOne() {
return new Point3d();
}
}
An invocation morePoints.OnePoint.getOne() in yet a third package would
return a Point3d that can be used as a Point, even though the type Point3d is
not available outside the package morePoints. The two argument version of
method move could then be invoked for that object, which is permissible because
method move of Point3d is public (as it must be, for any method that overrides a
public method must itself be public, precisely so that situations such as this will
work out correctly). The fields x and y of that object could also be accessed from
such a third package.
While the field z of class Point3d is public, it is not possible to access this
field from code outside the package morePoints, given only a reference to an
instance of class Point3d in a variable p of type Point. This is because the
expression p.z is not correct, as p has type Point and class Point has no field
named z; also, the expression ((Point3d)p).z is not correct, because the class
type Point3d cannot be referred to outside package morePoints.
The declaration of the field z as public is not useless, however. If there were
to be, in package morePoints, a public subclass Point4d of the class Point3d:
package morePoints;
public class Point4d extends Point3d {
public int w;
public void move(int dx, int dy, int dz, int dw) {
super.move(dx, dy, dz); w += dw;
}
}
then class Point4d would inherit the field z, which, being public, could then be
accessed by code in packages other than morePoints, through variables and
expressions of the public type Point4d.

중요한건 자식 부모간의 private 안되니까 protected 써! 이거인듯.

참고완료!

이제 항목16 가급적 컴포지션을 쓰라고 하는지 보러가야겠다.
TAG 상속, 자바
Posted by 유쾌한순례자