developer tip

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

copycodes 2020. 12. 31. 22:16
반응형

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


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

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

public class Parent {

    int name;
}

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

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>();

You can reference every item in the list as a Shape, you don't have to worry if it is a Rectangle or some other type like let's say Circle. You can treat them all the same; you can draw all of them. You can't call doRectangleAction because you don't know if the Shape is really a rectangle.

This is a trade of you make between treating objects in a generic fashion and treating the specifically.

Really I think you need to read more about OOP. A good book should help: http://www.amazon.com/Design-Patterns-Explained-Perspective-Object-Oriented/dp/0201715945


If you assign parent type to a subclass it means that you agree with to use the common features of the parent class.

It gives you the freedom to abstract from different subclass implementations. As a result limits you with the parent features.

However, this type of assignment is called upcasting.

Parent parent = new Child();  

The opposite is downcasting.

Child child = (Child)parent;

So, if you create instance of Child and downcast it to Parent you can use that type attribute name. If you create instance of Parent you can do the same as with previous case but you can't use salary because there's not such attribute in the Parent. Return to the previous case that can use salary but only if downcasting to Child.

There's more detail explanation


It's simple.

Parent parent = new Child();

In this case the type of the object is Parent. Ant Parent has only one properties. It's name.

Child child = new Child();

And in this case the type of the object is Child. Ant Child has two properties. They're name and salary.

The fact is that there's no need to initialize non-final field immediately at the declaration. Usually this’s done at run-time because often you cannot know exactly what exactly implementation will you need. For example imagine that you have a class hierarchy with class Transport at the head. And three subclasses: Car, Helicopter and Boat. And there's another class Tour which has field Transport. That is:

class Tour {
   Transport transport;
}  

As long as an user hasn't booked a trip and hasn't chosen a particular type of transport you can't initialize this field. It's first.

Second, assume that all of these classes must have a method go() but with a different implementation. You can define a basic implementation by default in the superclass Transport and own unique implementations in each subclass. With this initialization Transport tran; tran = new Car(); you can call the method tran.go() and get result without worrying about specific implementation. It’ll call overrided method from particular subclass.

Moreover you can use instance of subclass everywhere where instance of superclass is used. For example you want provide opportunity to rent your transport. If you don't use polymorphism, you have to write a lot of methods for each case: rentCar(Car car), rentBoat(Boat boat) and so forth. At the same time polymorphism allows you to create one universal method rent(Transport transport). You can pass in it object of any subclass of Transport. In addition, if over time your logic will increase up and you'll need to create another class in the hierarchy? When using polymorphism you don't need to change anything. Just extend class Transport and pass your new class into the method:

public class Airplane extends Transport {
    //implementation
}

and rent(new Airplane()). And new Airplane().go() in second case.


When you compile your program the reference variable of the base class gets memory and compiler checks all the methods in that class. So it checks all the base class methods but not the child class methods. Now at runtime when the object is created, only checked methods can run. In case a method is overridden in the child class that function runs. Child class other functions aren't run because the compiler hasn't recognized them at the compile time.


This situation happens when you have several implementations. Let me explain. Supppose you have several sorting algorithm and you want to choose at runtime the one to implement, or you want to give to someone else the capability to add his implementation. To solve this problem you usually create an abstract class (Parent) and have different implementation (Child). If you write:

Child c = new Child();

you bind your implementation to Child class and you can't change it anymore. Otherwise if you use:

Parent p = new Child();

as long as Child extends Parent you can change it in the future without modifying the code.

The same thing can be done using interfaces: Parent isn't anymore a class but a java Interface.

In general you can use this approch in DAO pattern where you want to have several DB dependent implementations. You can give a look at FactoryPatter or AbstractFactory Pattern. Hope this can help you.


Let's say you'd like to have an array of instances of Parent class, and a set of child classes Child1, Child2, Child3 extending Parent. There're situations when you're only interested with the parent class implementation, which is more general, and do not care about more specific stuff introduced by child classes.


You declare parent as Parent, so java will provide only methods and attributes of the Parent class.

Child child = new Child();

should work. Or

Parent child = new Child();
((Child)child).salary = 1;

ReferenceURL : https://stackoverflow.com/questions/12159601/why-do-we-assign-a-parent-reference-to-the-child-object-in-java

반응형