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 6849 Точки

Ами отговорът ти го има в документацията на 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
KevanyTrump avatar KevanyTrump -4 Точки

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

-1
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.