|
Java форум JavaTalks форум программистов
|
|
|
|
| Предыдущая тема :: Следующая тема |
| Автор |
Сообщение |
matvey : 33 Новичок Откуда: Novosibirsk
|
Мар 11, 2010 8:07 |
|
|
Доброго времени суток!
Вкратце опишу ситуацию, что-то не могу сообразить:
Под рукой исходников нет, но попробую:
Есть примерно следующая иерархия классов:
| Код: |
class A {
void meth1() {} // вообще у меня геттеры/сеттеры, но в данном // случае это не принципиально
void meth2() {}
void meth3() {}
}
class B extends A {
void methB1() {}
void methB2() {} // ... и т. д.
}
class C extends B {
void methC() {}
void methC2() {}
}
class D extends B {
/// ...
}
|
Есть основной класс, в котором любые созданные в иерархии объекты нужно хранить в коллекции, например в ArrayList-е:
| Код: |
class Main {
public static void main(String args[]) {
ArrayList list = new ArrayList();
list.add(new C());
list.add(new D());
list.add(new A());
}
}
|
Я думаю, понятно, что просто хочу хранить в коллекции ссылку на любой объект из иерархии. Но вот как сделать так, чтобы пробегая по листу, например, вот так:
| Код: |
Iterator iter = list.iterator();
while (iter.hasNext()) {
iter.next();
}
|
...можно было обращаться к объекту нужного мне класса из иерархии, чтобы вызвать только его (нужный) метод?
Ну если уж до конца, то задача состоит в том, чтобы вывести все объекты и их свойства в виде дерева на консоль. Решил, что лучше всего будет восрпользоваться коллекцией для хранения.
Пробовал создать свой лист, расширенный ArrayListом, наподобие этого:
| Код: |
class MyList<T> extends ArrayList<T> {
T ob;
MyList(T ob) { this.ob = ob; }
void adding(T o) {
add(o);
}
T getting() {
} // в общем пробовал применить генерики - еще больше запутался.
}
|
Может существует какое - то более универсальное решение? Подскажите, как быть. Горю! |
|
|
|
 |
Xcam : 118 Новичок
|
Мар 11, 2010 11:09 |
|
|
| Посмотрите в сторону приведения типов и оператора instanceof |
|
|
|
 |
matvey : 33 Новичок Откуда: Novosibirsk
|
Мар 11, 2010 12:10 |
|
|
| Блин, применял же уже, вылетело из головы. Спасибо! Получается, к помощи генериков можно не прибегать вообще? |
|
|
|
 |
Jean : 1989 JavaTalks Team Member Откуда: Санкт-Петербург
|
Мар 11, 2010 14:07 |
|
|
Генерики могут помочь в приведении к наименьшему общему типу. В вашем случае это класс А. Но если классы C и D, например, имеют какой-то иной интерфейс (другие методы относительно А, то нужно будет явно приводить тип.
Опишите задачу, наверняка вы решаете ее не самым оптимальным методом. _________________ Всякое решение плодит новые проблемы |
|
|
|
 |
matvey : 33 Новичок Откуда: Novosibirsk
|
Мар 11, 2010 18:10 |
|
|
Задача - вывести в виде дерева на консоль объекты иерархии классов вместе с их свойствами. У меня магазин товаров, но я был бы рад, если бы рассмотрели на любом примере.
По условию задачи больше ничего не сказано, но слово "дерево" меня настораживает: а не придется ли использовать в качестве коллекции хранения не ArrayList а какой - нибудь TreeSet? В данный момент у меня все очень примитивно:
У каждого подкласса пару своих свойств, которые достаются и устанавливаются дополнительными геттерами и сеттерами, вроде больше ничего особеного. Самое сложное - вывод. Я пока не пойму, во-первых, стоит ли использовать TreeSet вместо ArrayList и как лучше вывести на консоль в виде именно дерева?
Классы в разных файлах, просто здесь приведу все вместе.
| Код: |
public interface MainInterface {
public void setMyName(String name);
public String getMyName();
public void setPrice(Integer price);
public Integer getPrice();
public void setBarcode(Long code);
public Long getBarcode(); // all setters and getters;
}
*/
public class Product implements MainInterface {
protected String name; // название товара
protected Integer price; // цена
protected Long barcode; // штрих-код
String thisName = this.getMyName();
// ------------
public Product() {
this.setMyName("Books");
} // default constructor;
public Product(String name, Integer price, Long barcode) {
// set params:
this.name = name;
this.setMyName(name);
this.price = price;
this.barcode = barcode;
} // constructor
public void setMyName(String name) { this.name = name; };
public void setPrice(Integer price) {};
public void setBarcode(Long barcode) {};
public String getMyName() { return name; };
public Integer getPrice() { return price; };
public Long getBarcode() { return barcode; };
}
class Book extends Product {
private int PAGES; // page numbers;
public Book() {} // default constructor;
public Book(String name, Integer price, Long barcode) {
super(name, price, barcode);
} // constructor;
// то же самое и для сеттера:
final void setPages(int PAGES) {
this.PAGES = PAGES;
}
final int getPages() {
return PAGES;
} // getting pages;
}
class ProgrammersBook extends Book {
private String language;
public ProgrammersBook(String name, Integer price, Long barcode) {
super(name, price, barcode);
}
public ProgrammersBook() {}
// get and set language;
public String getLanguage() {
return language;
} // return language of programming;
public void setLanguage(String language) {
this.language = language;
} // setting language;
}
class CookBook extends Book {
private String[] ingredient;
public CookBook(String name, Integer price, Long barcode) {
super(name, price, barcode);
}
public String[] getIngradient() {
return ingredient;
} // return language of programming;
public void setIngradient(String[] ingredient) {
this.ingredient = ingredient;
} // setting language;
}
class Esotericism extends Book {
private int age;
public Esotericism(String name, Integer price, Long barcode) {
super(name, price, barcode);
}
public int getAge() {
return age;
} // return language of programming;
public void setAge(int age) {
this.age = age;
} // setting language;
}
public class Main {
private static ArrayList list = new ArrayList();
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Product pr = new Product();
list.add(new ProgrammersBook("Java2", 1200, 4353245345L));
list.add(new ProgrammersBook("C++", 1300, 123121231145L));
list.add(new CookBook("Receptes", 340, 123124435456L));
list.add(new CookBook("Recepts 2", 340, 123124435456L));
list.add(new Esotericism("Сафронов А.Г", 500, 1243234324234L));
Iterator iter = list.iterator();
// while cycle:
while (iter.hasNext()) {
Object ob = iter.next();
// if - else instanceof:
if (ob instanceof CookBook) {
CookBook cb = (CookBook)ob;
cb.getMyName();
cb.getPages();
cb.getPrice();
cb.getIngradient();
} else if (ob instanceof ProgrammersBook) {
ProgrammersBook pb = (ProgrammersBook)ob;
pb.getLanguage();
pb.getMyName();
pb.getPages();
pb.getPrice();
} else if (ob instanceof Esotericism) {
Esotericism e = (Esotericism)ob;
e.getAge();
e.getMyName();
e.getPages();
e.getPrice();
} // end if - else;
}
}
}
|
упростил все до примитивного, главное - понять суть. Так вот, как мне посоветовали выше, использовал instanceof. Будет ли это приемлемым решением? Или лучше поступить как-то по-другому?
Ну и как генерики использовать я тоже пока не пойму. Вот сейчас экспериментирую, но пока не выходит. |
|
|
|
 |
Jean : 1989 JavaTalks Team Member Откуда: Санкт-Петербург
|
Мар 11, 2010 20:58 |
|
|
Каждый элемент должен отвечать за вывод себя сам. В вашем общем классе (или лучше интерфейсе) определите любой метод, который будет отвечать за вывод. Вполне подойдет и стандартный toString().
В ваш ArrayList (или что бы там ни было) кладите объекты именно этого общего класса (или интерфейса). Заранее известно, что у них будет метод для вывода.
Затем в цикле просто вызываете этот метод и у каждого объекта он отрабатывает по-своему: не нужны будут никакие приведения типов и проверок на instanceof. Это будет правильно.
Что означает вывести в виде дерева? С отступами? У вас элементы вложены один в другой, - например, объект класса А содержит объекты класса Б и т.д.?
ArrayList от TreeSet отличаются, но не так как вам бы хотелось - к дереву оба имеют посредственное отношение (особенно в плане вывода). Почитайте об этих коллекциях в той же "Философии Java". _________________ Всякое решение плодит новые проблемы |
|
|
|
 |
sx01 : 96 Новичок Откуда: Санкт-Петербург
|
Мар 11, 2010 21:07 |
|
|
Насолько я увидел в вашем примере вам необходимо хранить в коллекции экземпляры классов унаследованных от book, для этого вы можете использовать генерик, т.е.
| Код: |
private static ArrayList<Book> list = new ArrayList<Book>();
|
Далее при добавлении книги в этот лист будет автоматически проделано восходящее преобразование к классу Book, далее так в вашем классе хранятся только объекты иерархии Book вместо
| Код: |
while (iter.hasNext()){...}
|
вы можете использовать синтаксис
| Код: |
for(Book b: list){
b.get......
}
|
Если вам нужен просто вывод на консоль я бы корневой класс Book объявил абстрактным и объявил внем абстрактным метод toString(), тем самым обязывая всех наследников переопределять его и в нем возвращал бы строку со всеми парметрами объекта. Далее никакой instanceof использовать будет не обязательно, будет работать run-time полиморфизм, т.е. каждый раз будет вызываться метод toString() нужного класса.
TreeSet - это коллекция, которая хранит элементы в отсортированном порядке, в Set не может быть одинаковых элементов. |
|
|
|
 |
matvey : 33 Новичок Откуда: Novosibirsk
|
Мар 11, 2010 21:20 |
|
|
Спасибо за ответы. Я правильно понял, что нужно заставить все классы переопределять метод toString() и вызывать в нем на вывод определенные в рамках данного класса методы, которые возвращают переменные соответствующего класса, необходимые для вывода?
| Цитата: |
| Если вам нужен просто вывод на консоль я бы корневой класс Book объявил абстрактным и объявил внем абстрактным метод toString() |
А если объявить все - таки в интерфейсе, это подойдет?
| Цитата: |
| У вас элементы вложены один в другой, - например, объект класса А содержит объекты класса Б и т.д.? |
нет, насколько мне понятно по задаче, имеет место быть только иерархия, но вложенность. например: книга - один класс, "книга по Java" или книга "поэзия Пушкина" два его наследника и т. д. - все унаследованные от Book, который в свою очередь унаследован от product. Последний класс создается на вершине иерархии, так как помимо книг есть и другие товары, получается он как бы определяет общую специфику для всех товаров.
PS Про TreeSet уже прочитал, понял, что не то совсем.
По поводу вывода на консоль - просто сказано: вывести полный список книгсо всеми свойствами.
Кстати, попутно возникло несколько вопросов:
- как лучше поступить с собственными переменными каждого класса: передавать их в конструктор, или устанавливать посредством методов?
- в каких классах будут нужны дефолтные конструкторы?
- может сеттеры в составе интерфейса убрать, раз я все равно все параметры передаю в конструктор для каждого класса? |
|
|
|
 |
matvey : 33 Новичок Откуда: Novosibirsk
|
Мар 12, 2010 10:54 |
|
|
| Цитата: |
| Что означает вывести в виде дерева? С отступами? У вас элементы вложены один в другой, - например, объект класса А содержит объекты класса Б и т.д.? |
Маленькое уточнение... Здесь. если я правильно понял, скорее да, чем нет, однако, вопрос тогда остается. Как формировать отступы? Обычными табами? Да, получается вложенная иерархия. |
|
|
|
 |
matvey : 33 Новичок Откуда: Novosibirsk
|
Мар 17, 2010 16:47 |
|
|
| Можно ли как - то осуществить сортировку по объектам? Например, чтобы объекты одного типа хранились в самом "начале" коллекции, а других - "внизу" коллекции? |
|
|
|
 |
Jean : 1989 JavaTalks Team Member Откуда: Санкт-Петербург
|
Мар 17, 2010 22:10 |
|
|
Можно. Для этого нужно реализовать интерфейс Comparator и использовать его. Для сортировки List можно вызвать это:
| Код: |
| Collections.sort(list, YourComparator ); |
Для сортировки Set можно использовать TreeSet и компаратор отдать ему в конструктор. _________________ Всякое решение плодит новые проблемы |
|
|
|
 |
|
|
|