Професионална програма
Loading...
+ Нов въпрос
VenelinGrozev avatar VenelinGrozev 130 Точки

[Technical Issue] Java OOP subtyping

Здравейте,

Имам малък проблем с разбирането на subtyping-a при Java List-вете. Става въпрос за първа задача от домашното. Пускам по-долу скелета на класовете

public class Vertex2D {
    private double x;
    private double y;
}

public class Vertex3D extends Vertex2D {
    private double z;
}

public abstract class Shape {
    protected List<? extends Vertex2D> vertices;

    public Shape() {
    }

    public Shape(List<? extends Vertex2D> vertices) {
        this.vertices = vertices;
    }
}

public class PlaneShape extends Shape {
    private Vertex2D vertex;

    public PlaneShape(Vertex2D vertex) {

        this.vertices = new ArrayList<Vertex2D>();
        this.vertices.add(vertex); // compile error
        // The method add(capture#2-of ? extends Vertex2D)
        // in the type List<capture#2-of ? extends Vertex2D>
        // is not applicable for the arguments (Vertex2D)
    }
}

Не мога да разбера защо при инициализация на конструктора на PlaneShape въпреки, че this.vertices става new ArrayList<Vertex2D>() не мога да вкарам в него променлива от тип Vertex2D.

В същото време това решение по-долу работи без проблем

public PlaneShape(Vertex2D vertex) {

        List<Vertex2D> verticesArray = new ArrayList<Vertex2D>();
        verticesArray.add(vertex);
        this.vertices = verticesArray;
    }

 

Явно, че пропускам нещо но не мога да разбера какво, затова всякаква помощ е добре дошла.

Тагове:
0
C# OOP Basics
Filkolev avatar Filkolev 4482 Точки

С такива геометрични задачи наследяванията са доста сложни като логика. В случая триизмерната точка наследява двуизмерната, което е спорно. Има две решения да изчистиш логиката, за които се сещам.

1) Да направиш абстрактен клас за точките и двуизмерните и триизмерните да го наследяват, при което Shape ще приема списък от Vertex, а вече наследниците на Shape ще конкретизират какви точно точки приемат. Аз така подходих.

2) Shape да е празен клас, т.е. да няма списък с точки, евентуално да имплементира интерфейса AreaCalculatable, понеже всички фигури могат да си смятат лицето. 

Не съм сигурен какъв е проблемът, може би "? extends Vertex2D" очаква наследник на Vertex2D, но не приема самия Vertex2D? Не съм ползвал този синтаксис.

0
VenelinGrozev avatar VenelinGrozev 130 Точки

В началото и аз направих абстрактен клас Vertex но се оказа, че няма нужда от него, понеже не знам какво да държа вътре. Реално в основният клас Vertex имам координати х и у, защото това е минимума с който можеш да опишеш една точка. После имаш нужда от още един клас за 3D точките, който да има и още една координата z. Какво държиш в базовият клас Vertex?

Това, че Shape класа ще имплементира AreaCalculatable не помага много. Имам предвид, че - да, трябва да имплементира AreaCalculatable но това не помага да си реша проблема.

List<? extends Vertex2D> значи - направи List в който можеш да слагаш само обекти от тип Vertex2D или наследници на този тип.

Също така имаш и израза List<? super Vertex2D>, който значи - направи List в който можеш да слагаш обекти от тип Vertex2D или негови родители. В случаят основният родител е Object.

0
Filkolev avatar Filkolev 4482 Точки

Нищо нямам във Vertex, направил съм го само като абстракция, за да мога да го ползвам в Shape. Не съм привърженик на празни класове, но е някакво решение.

0
RoYaL avatar RoYaL Trainer 6847 Точки

Ами отговорът ти го има в документацията на Java :)

http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html

Consider the following code:

List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35));  // compile-time error

Because is a subtype of , you can assign to . But you cannot use to add a natural number to a list of even numbers. The following operations on the list are possible:

  • You can add .
  • You can invoke .
  • You can get the iterator and invoke .
  • You can capture the wildcard and write elements that you've read from the list.

You can see that the list defined by is not read-only in the strictest sense of the word, but you might think of it that way because you cannot store a new element or change an existing element in the list.

 

По-скоро това ти трябва като документация де : http://docs.oracle.com/javase/tutorial/java/generics/subtyping.html

Де факто конкретната импелментация после, където казваш че е равно на ArrayList ще трябва да е subtype на типа.

 

0
20/02/2015 13:20:51
VenelinGrozev avatar VenelinGrozev 130 Точки

ROYAL, четох го този пример вчера но той не покрива случаят, който съм описал.

В примера имаме два класа NaturalNumber и EvenNumber - NaturalNumber е по-големият от EvenNumber и при това положение е нормално долните два реда да връщат грешка

List<? extends NaturalNumber> ln = new ArrayList<EvenNumber>();
ln.add(new NaturalNumber(35));

Т.е. не можем да сложим обект от родителският тип в лист от типа на наследника.

В моят случай обаче това не е така, защото имаме

protected List<? extends Vertex2D> vertices = new ArrayList<Vertex2D>(); //направи List в който можем да сложим обекти от тип Vertex2D или от неговите наследници.
this.vertices.add(Vertex2D vertex); //сложи обект от тип Vertex2D в List  в който можеш да слагаш обекти от тип Vertex2D или негови наследници. Връща compile error.

В моят пример поне аз не виждам конфликт в йерархията на класовете.

0
20/02/2015 14:29:35