Ішкі сыныптарды автоматты түрде ArrayList-ге қалай қоюға болады?

Менде супер класса бар, содан кейін бірнеше төменгі сыныптар бар:

public abstract class A {
    public abstract int getValue();
}

public class B extends A {
    public int getValue() {
        return 1;
    }
}

public class C extends A {
    public int getValue() {
        return 123;
    }
}

public class D extends A {
    public int getValue() {
        return 15234;
    }
}

Шамамен 100 немесе одан да кіші сыныптар бар. Менде сондай-ақ менеджер бар:

public class Manager {
    public static ArrayList list = new ArrayList();
}

Қалайша «сиқырлы» әрбір кодтың данасын қолмен жасай және оны тізімге қоспай A тізіміне барлық ішкі сыныптарының мысалын қосуға болады? Мүмкін, инициализация блогын пайдалану арқылы?

ӨҢДЕУ

Manager ішіндегі тізіміне қатынасатыным маңызды емес. Мен оны статикалық етіп редакцияладым.

4
Әрбір сыныбында түзетулер енгізуге болады
қосылды автор blake305, көзі
Әрбір класс команда ұсынатын болады. Пәрменнің атауын алу әдісі, әмірді орындаған кезде шақырылатын әдіс және бірнеше басқа нәрсе болады. Жаңа пәрменді жасаған сайын немесе пәрменді жойғанда әр команданың атымен list.add (жаңа D ()); жасау керек емес;
қосылды автор blake305, көзі
@RyanThames Пожалуйста, біраз жақсырақ түсіндіріңіз. Субкасымалдауға жазылған кезде әрбір команда орындалуы мүмкін болғандықтан, ішкі класта болғым келеді
қосылды автор blake305, көзі
@ blake305 - Массив A түріндегі барлық объектілердің иесі сияқты болып көрінеді. Мен тізімді A конструкторына аударып, тізімге қосыламын. Интерфейсті шынымен табуға болады, stackoverflow.com/questions/435890/…
қосылды автор Jayan, көзі
Алғашқы мәселе, әрине: неге? Сіз не істеп жатырсыз, мұны істеуіңізді талап етеді. Екінші мәселе: неге? Тізім меңгерушісі A-ге ғана назар аударады және А-дан А-ға дейін шығарылған кез келген элементті қайтарады.
қосылды автор Mike 'Pomax' Kamermans, көзі
Бұл ерекше нәрсе сияқты көрінеді. Сіз шынымен қалай жетуге тырысасыз? Сіз шешуге тырысып жатқан мәселені түсіндіріп бере аласыз ба?
қосылды автор SimonC, көзі

7 жауаптар

(Екінші әрекет - менің алғашқы әрекетім Сұрақты дұрыс түсінбеуге негізделген болатын).

Мен жасағыңыз келетін нәрсе (статикалық) тізімін құрастырады деп ойлаймын:

  • әрбір ішкі сыныптың бір данасын қамтиды,
  • құрылды және уақыт өткеннен кейін және
  • тізімнің өзіндік данасын жасайтын/қосатын әрбір ішкі сыныпта кодты қамтымайды.

Біріншіден, инициализатордың данасы бұны жасамайды. Дана инициализаторы дананы жасаған кезде іске қосылады ... және бұл үшін new сыныпқа (яғни әрбір ішкі сыныптың) қажет.

Менің ойымша, өмір сүрудің бірден-бір тәсілі - бұл бірнеше жасанды шағылысушы кодты жазу:

  • класс жолындағы барлық сыныптарды қайта итереді,
  • әрбірін Class.forName() ,
  • арқылы жүктейді
  • сынып сыныбы A ,
  • секілді,
  • егер ол болса, көрсетілмейтін сыныптарда no-args конструкторын шақырады және алынған «дананы» тізімге қосады.

Бұл (IMO) әдемі хаки !! Және бұл қымбат болады ... егер сіз осы пакеттерді іздестіруге керек «пакет кеңістігін» шектей алмасаңыз.


Шындығында, бұл мүмкін enum пайдалану арқылы шешілуі мүмкін мәселе ... әсіресе, егер ішкі сыныптарда талап ететін мінез-құлықтық айырмашылықтар болмаса түрлі әдістерді енгізу. (Мысалы, сіздің getValue() әдісі тек қана конструкторды инициализациялауға болатын жеке айнымалы мәнді қайтаруы мүмкін.) @Paul Bellora сұрағын қараңыз.

(Кейбір подкластердің бірнеше данасы болу керек болса, бұл қолдануға болмайтындай болатын нәрсе еді enums ).

2
қосылды
Бастауыш ешқашан аталмайды. Мен A барлық ішкі сыныптарының инициализаторын автоматты түрде қоңырау шалу әдісін қажет деп санаймын
қосылды автор blake305, көзі

Әрбір класс командасын ұсынады.

Мәселіңіздің сипаттамасына сүйене отырып, A сияқты enum :

public enum A {

    B(1) {
        @Override
        public void execute() {
            //code and stuff
        }
    },
    C(123) {
        @Override
        public void execute() {
            //code and stuff
        }
    },
    D(15234) {
        @Override
        public void execute() {
            //code and stuff
        }
    };

    private final int value;

    private A(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    public abstract void execute();
}

Енді, әр команданың бір данасы бар және сіз A.values ​​() командасымен оңай итерациялай аласыз.

1
қосылды
Бірақ әр команданың коды мен материалдары бар іске асырылатын болады
қосылды автор blake305, көзі
@ blake305 Менің түзетуімді қараңыз.
қосылды автор Paul Bellora, көзі
Enums-де код пен заттар болуы мүмкін, мен уәде беремін.
қосылды автор Paul Bellora, көзі

Бұл әрекетті орындаудың сәтсіздігі, бірақ егер сіздің барлық сыныптарыңыз бір қалтада (нақты сыныптағы файлдар) болса, сіз қалтадағы файлдарды қайталап, ClassLoader пайдалануыңыз мүмкін. Сіз кодты сызық бойымен бір нәрсе көресіз -

for(String className : classNames){
    Class clazz = classLoader.loadClass(className);
    list.add(clazz.newInstance());
}

ClassLoader API бөлімін қараңыз. ақпарат. Сондай-ақ, бұл өте тиімді емес екенін есіңізде сақтаңыз, бірақ егер сіз мұны жасай берсеңіз, онда сіз жақсы боласыз.

0
қосылды
@ blake305 кейбір жалған кодпен жаңартылды.
қосылды автор David Grinberg, көзі
@ blake305 Бұрын айтқанымдай, барлық нақты сынып файлдарының қай жерде екендігін білсеңіз, сынып атауларының тізімін жасау үшін барлық файлдарды оқу үшін файлды жасауға болады.
қосылды автор David Grinberg, көзі
@ blake305 сіз сондай-ақ бұл
қосылды автор David Grinberg, көзі
Сіз маған мысал келтіре аласыз ба?
қосылды автор blake305, көзі
Егер сынып атауларының тізімін алудың мүмкіндігі болса, бұл жұмыс істейтін еді. Мен қандай да бір себеппен қолмен баптандырусыз сыныптың атын ала алмаймын.
қосылды автор blake305, көзі

Мұның бәрі мағынасы болмаса да ... Сіз жасай алатын тәсілдердің біреуі - көктемнің компоненттерін сканерлеуге ұқсас нәрселерді жасаңыз: PathMatchingResourcePatternResolver сияқты нәрселерді пайдаланыңыз және барлық ықтимал сыныптарды табыңыз. Оларды айналдырып, А тізімінің қосалқы тізіміне қосылыңыз.

0
қосылды

1) Сіз сыныптың барлық қолжетімді ішкі сыныптарын табуыңыз керек. Ол үшін Java класс жолындағы барлық сыныптарды сканерлеу керек. Барлық істерді жеңілдету үшін, барлық ішкі сыныптар A.class сияқты бір жерде орналасқан деп болжауға болады. A банкада немесе қалтада болуы керек. Біз оның нақты орналасқан жерін біле аламыз

URL url = A.class.getProtectionDomain().getCodeSource().getLocation();

2) Мысалы, бұл қалта, мысалы:/D:/workspace1/x/target/classes/деп болжауға мүмкіндік береді. Енді осы қалтадағы және ішкі қалталарда барлық .class файлдары арқылы жүру керек. Біз File.listFiles немесе Java 7 NIO2 үшін пайдалана аламыз. Бізде 2 нұсқа бар

а) әрбір сыныпты жүктеп, оның суперклассын тексеріңіз

   Class cls = Class.forName();
   if (cls.getSuperClass() == A.class) {
     ...

б) javaassist шеңберін http://www.javassist.org немесе сынып файлымен тікелей жұмыс істеуге қолданыңыз

DataInputStream ds = new DataInputStream(new BufferedInputStream(path));
ClassFile cf =  new ClassFile(ds);
String superClass = cf.getSuperClass();
if (superClass.equals("A")) {
    Class cls = Class.forName(cf.getName());
...

b нұсқасы сізге қажетті тек сыныптарды жүктейді, опция a қарапайым, бірақ қалтадағы барлық сыныптарды жүктейді

Екі жағдайда да сіз дананы жасай аласыз

A a = (A) cls.newInstance();

барлық қосалқы сыныптарда no-arg конструкторы бар деп есептеледі

0
қосылды

Мүмкін:

public abstract class A {
    public A(Manager m) {
        m.list.add(this);
    }
    public abstract int getValue();
}

public class B extends A {
    public B(Manager m) {
        super(m);
    }
}

Осылайша, сіз subclassing кезінде m.list.add (жаңа A ()); дегенмен ешқашан қайта қарауға тура келмейді. Бірақ сіз іздеген нәрсені білмеймін ...


ӨҢДЕУ:

Менеджердегі тізімге кіретінім маңызды емес. Мен оны статикалық етіп редакцияладым.

Егер сіз синглонды пайдалану туралы ойламасаңыз, мұнда өте маңызды:

Бірақ Singletons туралы нашар дегенді оқыңыз .

public class Manager {
   private static Manager instance = null;
   protected Manager() {
     //Exists only to defeat instantiation.
   }
   public static Manager getInstance() {
      if(instance == null) {
         instance = new Manager();
      }
      return instance;
   }
}

Сонда:

public abstract class A {
    public A() {
        Manager.getInstance().list.add(this);
    }
    public abstract int getValue();
}

public class B extends A {
}

Бірақ, бұл тағы да дизайн ретінде қанағаттанарлық емес ...

0
қосылды
Бастауыш ешқашан аталмайды. Мен A барлық ішкі сыныптарының инициализаторын автоматты түрде қоңырау шалу әдісін қажет деп санаймын
қосылды автор blake305, көзі
Менің ойымша, сіз қол жеткізуге тырысатын синглтон дизайнымен қанағаттандыра аласыз. Ал кейбір жақсы себептерге байланысты бұл дизайн ұсынылмайды. Сондықтан менеджер кез келген данаға берілуге ​​тиіс. magic синглтон ойлау үлгісінен келуі мүмкін, бірақ мен бұған дейін продюсерлерді оқуға кеңес беремін. stackoverflow.com/questions/137975/… .
қосылды автор Gauthier Boaglio, көзі
Singleton дизайнымен менеджерден ешқашан өтуге тура келмейді, осылайша, ешқашан подкласс конструкторларын қайта анықтауға тура келмейді. Сізге үлгі болғыңыз келе ме? (немесе онымен таныс болыңыз). Singletons ~ жаман, бірақ мен оларды кейде сирек жағдайларда қолданамын ...
қосылды автор Gauthier Boaglio, көзі

Мақсатты сыныптарды автоматты түрде анықтау үшін сынып жолының сканерін пайдалану туралы не айтасыз?

   List classes = CPScanner.scanClasses(new ClassFilter().packageName("com.foo.*").superClass(A.class));

Мақсатты сыныптар болғандықтан, оларды newInstance әдісімен оңай баптай аласыз.

Айтпақшы, төмендегі тырнақшаны пайдалану үшін көкшіл тәуелділікті қолданыңыз:


    net.sf.corn
    corn-cps
    1.1.1

Көңілділер.

0
қосылды