[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();
name
Parent 클래스의 변수 만 액세스 할 수 있습니다 . 그래서이 선의 정확한 사용은 무엇입니까 ??
Parent parent = new Child();
또한 동적 다형성을 사용하는 경우이 작업을 수행 한 후 자식 클래스의 변수에 액세스 할 수없는 이유
Parent parent = new Child();
답변
첫째, 용어 설명 : Child
객체를 유형의 변수에 할당합니다 Parent
. , a Parent
의 하위 유형이되는 객체에 대한 참조 입니다.Parent
Child
더 복잡한 예에서만 유용합니다. getEmployeeDetails
Parent 클래스에 추가한다고 상상해보십시오 .
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()
우리는 방법에 차이 초점을 무시할 수 Parent
와 Child
유사하다. 이를 하위 유형 다형성 이라고 합니다.
업데이트 된 질문은 객체가 참조에 저장 Child.salary
될 때 액세스 할 수없는 이유를 묻습니다 . 대답은 “다형성”과 “정적 타이핑”의 교차점입니다. Java는 컴파일 시간에 정적으로 형식화되기 때문에 컴파일러로부터 특정 보장을 받지만 교환 규칙을 따르지 않으면 코드가 컴파일되지 않습니다. 여기서 관련 보장은 하위 유형의 모든 인스턴스 (예 :)가 상위 유형 (예 :)의 인스턴스로 사용될 수 있다는 것 입니다. 예를 들어, 액세스 하거나 메소드 또는 필드가 유형 의 변수 에 할당 될 수있는 널이 아닌 객체에 정의되어 있음을 보장합니다.Child
Parent
Child
Parent
employee.getEmployeeDetails
employee.name
employee
Parent
. 이를 보장하기 위해 컴파일러 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
에는 두 가지 속성이 있습니다. 그들은 name
및 salary
.
사실 선언에서 즉시 non-final 필드를 초기화 할 필요가 없습니다. 일반적으로 이것은 정확히 어떤 구현이 필요한지 정확히 알 수 없기 때문에 런타임에 수행됩니다. 예를 들어 Transport
머리에 클래스가있는 클래스 계층 구조가 있다고 가정합니다 . 그리고 세 개의 하위 클래스 : Car
, Helicopter
및 Boat
. 그리고 Tour
field가있는 또 다른 클래스 가 있습니다 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 집합을 원한다고 가정 해 보겠습니다. 보다 일반적인 부모 클래스 구현에만 관심이 있고 자식 클래스에 의해 도입 된 더 구체적인 내용 에는 관심이없는 상황이 있습니다.