[java] Java에서 자식 개체에 부모 참조를 할당하는 이유는 무엇입니까?

나는 아주 간단한 질문을하고 있지만 이것에 약간 혼란스러워합니다.

클래스가 있다고 가정합니다 Parent.

public class Parent {

    int name;
}

그리고 다른 수업이 있습니다 Child.

public class Child extends Parent{

    int salary;
}

그리고 마지막으로 Main.java 클래스

public class Main {

    public static void main(String[] args)
    {
        Parent parent = new Child();
        parent.name= "abcd";
    }
}

자식 개체를 다음과 같이 만들면

Child child = new Child():

그러면 child개체가 두 name and salary변수에 모두 액세스 할 수 있습니다 .

내 질문은 :

Parent parent = new Child();

nameParent 클래스의 변수 만 액세스 할 수 있습니다 . 그래서이 선의 정확한 사용은 무엇입니까 ??

 Parent parent = new Child();

또한 동적 다형성을 사용하는 경우이 작업을 수행 한 후 자식 클래스의 변수에 액세스 할 수없는 이유

Parent parent = new Child();



답변

첫째, 용어 설명 : Child객체를 유형의 변수에 할당합니다 Parent. , a Parent의 하위 유형이되는 객체에 대한 참조 입니다.ParentChild

더 복잡한 예에서만 유용합니다. getEmployeeDetailsParent 클래스에 추가한다고 상상해보십시오 .

public String getEmployeeDetails() {
    return "Name: " + name;
}

Child자세한 내용을 제공하기 위해 해당 메서드를 재정의 할 수 있습니다 .

@Override
public String getEmployeeDetails() {
    return "Name: " + name + " Salary: " + salary;
}

이제 객체가 Parent또는 Child다음 과 같이 사용 가능한 모든 세부 정보를 가져 오는 코드 한 줄을 작성할 수 있습니다 .

parent.getEmployeeDetails();

다음 코드 :

Parent parent = new Parent();
parent.name = 1;
Child child = new Child();
child.name = 2;
child.salary = 2000;
Parent[] employees = new Parent[] { parent, child };
for (Parent employee : employees) {
    employee.getEmployeeDetails();
}

결과는 다음과 같습니다.

Name: 1
Name: 2 Salary: 2000

우리 Child는을 Parent. 그것은에 행동이 고유의 전문 한 Child클래스,하지만 우리가 전화했을 때 getEmployeeDetails()우리는 방법에 차이 초점을 무시할 수 ParentChild유사하다. 이를 하위 유형 다형성 이라고 합니다.

업데이트 된 질문은 객체가 참조에 저장 Child.salary될 때 액세스 할 수없는 이유를 묻습니다 . 대답은 “다형성”과 “정적 타이핑”의 교차점입니다. Java는 컴파일 시간에 정적으로 형식화되기 때문에 컴파일러로부터 특정 보장을 받지만 교환 규칙을 따르지 않으면 코드가 컴파일되지 않습니다. 여기서 관련 보장은 하위 유형의 모든 인스턴스 (예 :)가 상위 유형 (예 :)의 인스턴스로 사용될 수 있다는 것 입니다. 예를 들어, 액세스 하거나 메소드 또는 필드가 유형 의 변수 에 할당 될 수있는 널이 아닌 객체에 정의되어 있음을 보장합니다.ChildParentChildParentemployee.getEmployeeDetailsemployee.nameemployeeParent. 이를 보장하기 위해 컴파일러 Parent는 액세스 할 수있는 항목을 결정할 때 해당 정적 유형 (기본적으로 변수 참조 유형) 만 고려 합니다. 따라서 개체의 런타임 유형에 정의 된 멤버에 액세스 할 수 없습니다 Child.

당신이 진정 Child으로 a 를 사용하고 싶을 때 Parent이것은 함께 살기 쉬운 제한이며 당신의 코드는 Parent모든 하위 유형에 대해 사용할 수 있습니다 . 허용되지 않는 경우 참조 유형을 작성하십시오 Child.


답변

프로그램을 컴파일 할 때 기본 클래스의 참조 변수가 메모리를 가져오고 컴파일러는 해당 클래스의 모든 메서드를 확인합니다. 따라서 모든 기본 클래스 메서드를 확인하지만 자식 클래스 메서드는 확인하지 않습니다. 이제 개체가 생성 될 때 런타임에 확인 된 메서드 만 실행할 수 있습니다. 함수가 실행되는 자식 클래스에서 메서드가 재정의 된 경우. 컴파일러가 컴파일 타임에 인식하지 않았기 때문에 자식 클래스의 다른 함수는 실행되지 않습니다.


답변

공통 상위 인터페이스를 통해 모든 하위 클래스에 액세스 할 수 있습니다. 이는 모든 하위 클래스에서 사용 가능한 공통 작업을 실행하는 데 유용합니다. 더 나은 예가 필요합니다.

public class Shape
{
  private int x, y;
  public void draw();
}

public class Rectangle extends Shape
{
  public void draw();
  public void doRectangleAction();
}

이제 다음이있는 경우 :

List<Shape> myShapes = new ArrayList<Shape>();

목록의 모든 항목을 Shape로 참조 할 수 있습니다. Rectangle 또는 Circle과 같은 다른 유형인지 걱정할 필요가 없습니다. 그들 모두를 똑같이 대할 수 있습니다. 모두 그릴 수 있습니다. Shape가 실제로 직사각형인지 모르기 때문에 doRectangleAction을 호출 할 수 없습니다.

이것은 일반적인 방식으로 물건을 취급하는 것과 구체적으로 취급하는 것 사이의 거래입니다.

정말 OOP에 대해 더 읽어야한다고 생각합니다. 좋은 책이 도움이 될 것입니다 : http://www.amazon.com/Design-Patterns-Explained-Perspective-Object-Oriented/dp/0201715945


답변

상위 유형을 하위 클래스에 할당하면 상위 클래스의 공통 기능을 사용하는 데 동의하는 것입니다.

다른 서브 클래스 구현에서 자유롭게 추상화 할 수 있습니다. 결과적으로 상위 기능으로 제한됩니다.

그러나 이러한 유형의 할당을 업 캐스팅이라고합니다.

Parent parent = new Child();

그 반대는 다운 캐스팅입니다.

Child child = (Child)parent;

따라서 인스턴스를 생성 Child하고 다운 캐스트하면 Parent해당 유형 속성을 사용할 수 있습니다 name. 인스턴스를 생성 Parent하면 이전 사례와 동일하게 할 수 있지만 salary.NET Framework에 이러한 속성이 없기 때문에 사용할 수 없습니다 Parent. 사용할 수 salary있지만로 다운 캐스팅하는 경우에만 이전 케이스로 돌아갑니다 Child.


더 자세한 설명이 있습니다


답변

간단 해.

Parent parent = new Child();

이 경우 개체의 유형은입니다 Parent. Ant Parent에는 하나의 속성 만 있습니다. 그것은이다 name.

Child child = new Child();

이 경우 개체의 유형은입니다 Child. Ant Child에는 두 가지 속성이 있습니다. 그들은 namesalary.

사실 선언에서 즉시 non-final 필드를 초기화 할 필요가 없습니다. 일반적으로 이것은 정확히 어떤 구현이 필요한지 정확히 알 수 없기 때문에 런타임에 수행됩니다. 예를 들어 Transport머리에 클래스가있는 클래스 계층 구조가 있다고 가정합니다 . 그리고 세 개의 하위 클래스 : Car, HelicopterBoat. 그리고 Tourfield가있는 또 다른 클래스 가 있습니다 Transport. 그건:

class Tour {
   Transport transport;
}

사용자가 여행을 예약하지 않았고 특정 유형의 교통 수단을 선택하지 않은 한이 필드를 초기화 할 수 없습니다. 첫 번째입니다.

둘째, 이러한 모든 클래스에는 메서드가 go()있지만 구현이 달라야 한다고 가정합니다 . 기본적으로 수퍼 클래스에서 기본 구현을 정의하고 Transport각 하위 클래스에서 고유 한 구현을 정의 할 수 있습니다 . 이 초기화 Transport tran; tran = new Car();를 사용하면 tran.go()특정 구현에 대해 걱정하지 않고 메서드를 호출하고 결과를 얻을 수 있습니다. 특정 하위 클래스에서 재정의 된 메서드를 호출합니다.

또한 수퍼 클래스의 인스턴스가 사용되는 모든 곳에서 서브 클래스의 인스턴스를 사용할 수 있습니다. 예를 들어, 당신은 당신의 교통 수단을 임대 할 기회를 제공하고자합니다. : 당신은 다형성을 사용하지 않는 경우, 각각의 경우에 대한 방법을 많이 작성해야 rentCar(Car car), rentBoat(Boat boat)등등합니다. 동시에 다형성을 통해 하나의 보편적 인 방법을 만들 수 있습니다 rent(Transport transport). 의 모든 하위 클래스의 객체를 전달할 수 있습니다 Transport. 또한 시간이 지남에 따라 논리가 증가하고 계층 구조에 다른 클래스를 만들어야하는 경우? 다형성을 사용할 때 아무것도 변경할 필요가 없습니다. 클래스를 확장 Transport하고 새 클래스를 메서드에 전달하면됩니다.

public class Airplane extends Transport {
    //implementation
}

rent(new Airplane()). 그리고 new Airplane().go()두 번째 경우.


답변

이 상황은 여러 구현이있을 때 발생합니다. 설명하겠습니다. 몇 가지 정렬 알고리즘이 있고 런타임에 구현할 알고리즘을 선택하거나 다른 사람에게 그의 구현을 추가 할 수있는 기능을 제공하려고한다고 가정합니다. 이 문제를 해결하기 위해 일반적으로 추상 클래스 (Parent)를 만들고 다른 구현 (Child)을 사용합니다. 당신이 쓰는 경우 :

Child c = new Child();

구현을 Child 클래스에 바인딩하면 더 이상 변경할 수 없습니다. 그렇지 않으면 다음을 사용하는 경우 :

Parent p = new Child();

Child가 Parent를 확장하는 한 나중에 코드를 수정하지 않고 변경할 수 있습니다.

인터페이스를 사용하여 동일한 작업을 수행 할 수 있습니다. 부모는 더 이상 클래스가 아니라 자바 인터페이스입니다.

일반적으로 여러 DB 종속 구현을 원하는 DAO 패턴에서이 접근 방식을 사용할 수 있습니다. FactoryPatter 또는 AbstractFactory Pattern을 살펴볼 수 있습니다. 이것이 당신을 도울 수 있기를 바랍니다.


답변

부모 클래스의 인스턴스 배열과 부모를 확장하는 자식 클래스 Child1, Child2, Child3 집합을 원한다고 가정 해 보겠습니다. 보다 일반적인 부모 클래스 구현에만 관심이 있고 자식 클래스에 의해 도입 된 더 구체적인 내용 에는 관심이없는 상황이 있습니다.