Ergebnis 1 bis 9 von 9

Java Unterklassen Aufrufe abkürzen

  1. #1 Zitieren
    Ritter Avatar von Feuerstern
    Registriert seit
    Sep 2007
    Beiträge
    1.816
    Hallo zusammen,
    ich habe eine etwas verkapselte Klassenstruktur welche das nutzen der Klasse etwas unübersichtlich macht.
    Hier ein stark vereinfachtes Beispiel:
    Code:
    public class ParentAdapterItem {
        public static class InnerAdapterItem {
              public static final int TYPE_IMAGE = 0;
            ...
        }
    
    ...
    }
    Wenn ich die Klasse InnerAdapterItem nutzen möchte sieht das so aus:
    Code:
    ParentAdapterItem.InnerAdapterItem item = new ParentAdapterItem.InnerAdapterItem(ParentAdapterItem.InnerAdapterItem.TYPE_IMAGE);
    Das würde ich gerne abkürzen:
    Code:
    InnerAdapterItem item = new InnerAdapterItem(InnerAdapterItem.TYPE_IMAGE);
    In C++ kenne ich defines die das ermöglichen, gibt es in java ähnliche Wege?
    Feuerstern ist offline

  2. #2 Zitieren
    Auserwählter
    Registriert seit
    Jul 2017
    Beiträge
    6.578
    Du könntest mit extends arbeiten.

    Die obere Klasse bekommt alles mit, was die Subklassen auch haben sollen. Die Subklassen eben das, was für diese relevant ist.

    Code:
    class Fuer_alle_Unterklassen{
        bla,bla,bla;
       }
    
    class Unterklasse_von_Fuer_alle_Unterklassen extends Fuer_alle_Unterklassen {
        public static final int TYPE_IMAGE = 0;
     }
    
    Unterklasse_von_Fuer_alle_Unterklassen item=new Unterklasse_von_Fuer_alle_Unterklassen();
    
    System.out.println("Item= "+item.TYPE_IMAGE); //Item= 0
    Stiller Leser ist offline

  3. #3 Zitieren
    dann wähle doch deinen sonderrang Avatar von Heinzi
    Registriert seit
    Jul 2007
    Ort
    Aachen
    Beiträge
    13.608
    extends macht aber was ganz anderes als define.

    Wenn wir das mal am Beispiel Student und Person machen, d.h. jeder Student ist auch eine Person, dann wäre Student extends Person in C++ Student : Person, also eben genau das was Stiller Leser beschreibt, die Klasse Student erbt alle Eigenschaften der Klasse Person.

    Wenn jede Person einen Namen hat und jeder Student einen Namen und einen Studiengang, dann sieht das z.B. so aus:

    C++

    Code:
    #include <string>
    using namespace std;
    
    class Person {
        private:
            string name;
        public:    
            Person(string n) {
                name = n;
            }
        string getName(){
            return name;        
        }
    };
    
    class Student : Person {
        private:
            string studiengang;
        public:
            Student(string n, string s):Person(n) {
                studiengang = s;
            }
        string getStudiengang(){
            return studiengang;     
        }
    };
    Java

    Code:
    class Person {
    	private String name;
    
    	public Person(String n) {
            name = n;
    	}
    
    	public String getName() {
    	    return name;
    	}
    }
    class Student extends Person {
    	private String studiengang;
    
    	public Student(String n, String s) {
            super(n);
            studiengang = s;
        }
    
        public String getStudiengang() {
            return studiengang;
        }
    }
    Was Feuerstern im EP beschreibt ist aber keine Subklasse im Sinne von Kindklasse, sondern eine Klasse als Eigenschaft einer anderen Klasse. Das kann man nicht durch Vererbung ersetzen. Ein Beispiel zur Veranschaulichung mit Person und Auto:

    Code:
    public class Main{
    
         public static void main(String []args){
            Auto A3 = new Auto("Audi A3");
            Person Peter = new Person("Peter",A3);
            System.out.println(Peter.getAuto().getMarke());
         }
    }
    
    class Person {
    	private String name;
        private Auto car;
        Person(String n, Auto c) {
            name = n;
            car = c;
        }
        public String getName() {
            return name;
        }
        public Auto getAuto() {
            return car;
        }
    }
    
    class Auto {
        private String marke;
        Auto(String m) {
            marke = m;
        }
        public String getMarke() {
            return marke;
        }
    }
    Um hier die Automarke zu erhalten kann ich nur über Peter.getAuto().getMarke() gehen, da das Objekt Peter keine Funktion hat, um direkt auf die Marke seines Autos zugreifen zu können. Die Klasse Auto extended die Klasse Person nicht, das sind zwei völlig verschiedene Klassen.

    Ich kann aber tricksen und die Funktion Person.getMarke() definieren, dann kann ich auch direkt mit Peter.getMarke() auf die Automarke zugreifen:

    Code:
    public class Main{
    
         public static void main(String []args){
            Auto A3 = new Auto("Audi A3");
            Person Peter = new Person("Peter",A3);
            System.out.println(Peter.getMarke());
         }
    }
    
    class Person {
    	private String name;
        private Auto car;
        Person(String n, Auto c) {
            name = n;
            car = c;
        }
        public String getName() {
            return name;
        }
        public Auto getAuto() {
            return car;
        }
        public String getMarke() {
            return car.getMarke();
        }
    }
    
    class Auto {
        private String marke;
        Auto(String m) {
            marke = m;
        }
        public String getMarke() {
            return marke;
        }
    }
    Also sowas kannst du schon machen, ist aber halt auch nicht ungefährlich wenn du beispielsweise die Variable marke umbenennen möchtest und infolgedessen auch die Getter-Funktion umbenennst, dann musst du das nicht nur in der Auto-Klasse und der Main-Funktion korrigieren, sondern auch in der Person-Klasse. Klar kann ein Programm wie Eclipse das automatisch machen, aber das führt die Klassentrennung irgendwie ad absurdum, dann kann ich ja auch gleich String automarke in die Person-Klasse reinschreiben und brauche keine Auto-Klasse mehr. Und später wenn man dann im Team an größeren Programmen arbeitet oder andere Leute das Programm weiterentwickeln müssen nachdem du gar nicht mehr an diesem Projekt arbeitest, da ist das auch nicht unbedingt optimal zum nachhalten. Wobei ich mit sowas auch kaum Erfahrung habe und ich auch kein Experte in sauberem Programmierstil bin.

    So, das ist aber auch nicht deine Frage.

    Du scheinst ja mit nested classes zu arbeiten, davon hab ich keinen Plan, hab ich noch nie benutzt. Wenn du nested classes wirklich brauchst, bleibt dir nicht viel anderes übrig, denn sowas wie #define gibt es in Java nicht, hat keinen Precompiler wo quasi Stringvariablen erstmal in Javacode umgesetzt werden.

    Du kannst halt die Konstruktoren verpacken, also sowas machen wie

    Code:
    public class Main{
    
         public static void main(String []args){
            ParentAdapterItem parent = new ParentAdapterItem();
            ParentAdapterItem.InnerAdapterItem item = parent.newInner();
         }
    }
    
    class ParentAdapterItem {
            class InnerAdapterItem {
            public static final int TYPE_IMAGE = 0;
        }
        
        ParentAdapterItem.InnerAdapterItem newInner() {
            ParentAdapterItem.InnerAdapterItem item = new ParentAdapterItem.InnerAdapterItem();
            return item;
        }
    }
    ...dann sparst du dir zumindest die rechte Seite

    Oder nochmal verpacken à la

    Code:
    public class Main{
    
         public static void main(String []args){
            ParentAdapterItem parent = new ParentAdapterItem();
            InnerAdapter x = new InnerAdapter(parent.newInner());
         }
    }
    
    class ParentAdapterItem {
            class InnerAdapterItem {
            public static final int TYPE_IMAGE = 0;
        }
        
        ParentAdapterItem.InnerAdapterItem newInner() {
            ParentAdapterItem.InnerAdapterItem item = new ParentAdapterItem.InnerAdapterItem();
            return item;
        }
    }
    
    class InnerAdapter {
        private ParentAdapterItem.InnerAdapterItem inner;
        ParentAdapterItem.InnerAdapterItem getInner() {
            return inner;
        }
        void setInner(ParentAdapterItem.InnerAdapterItem i) {
            inner = i;
        }
        InnerAdapter(ParentAdapterItem.InnerAdapterItem i) {
            inner = i;
        }
    }
    und dann mit x.getInner() drauf zugreifen

    Ah nee, das ist unschön.

    Kannst auch einen Preprocessor als Plugin vorschalten: https://github.com/manifold-systems/...d-preprocessor

    Aber dann kann das keiner außer dir mehr bearbeiten ohne dass die dasselbe Plugin auch haben.

    Stackoverflow erwähnt Dependency Injections, allerdings hab ich davon absolut keinen Plan, also ka ob du damit was anstellen kannst.
    "wenn ich jmd respektlos behandelt habe warst dass immer nur du" - wahre Freunde!

    Legen Sie das verdammte Eis zurück auf Ihre Zwei-Millionen-Dollar-Hand!
    EDL: Es wird Menschenansammlungen in allen Größenordnungen geben in hinreichender Zahl.
    Mission Impossible mit Heinzi Cruise
    Heinzi ist offline

  4. #4 Zitieren
    Auserwählter
    Registriert seit
    Jul 2017
    Beiträge
    6.578
    Ja, das ist mir schon klar. Extends war auch eher als Notlösung gedacht.
    Insgesamt empfinde ich das alles aber als ziemlich unsauber. Sehr leicht, Fehler zu machen. Habe auch noch nicht so ganz den Sinn dahinter verstanden, für was man das so machen müsste.

    Aber für kleine Programme hatte ich mir gedacht, dass Extends helfen könnte, wenn man sich Schreibarbeit ersparen will, obwohl es da eigentlich ums Vererben geht. Davon mal abgesehen, wenn man mit Eclipse und Co arbeitet, ist es gar nicht so viel Schreibarbeit. Wird ja dann alles direkt angeboten.

    Na, mal sehen, was der TE möchte.
    Stiller Leser ist offline

  5. #5 Zitieren
    Forentroll Avatar von Harbinger
    Registriert seit
    Jul 2003
    Ort
    Rheinhessische Toscana
    Beiträge
    19.032
    Ich schätze, was du suchst ist Static Import. Das kann mit inneren Klassen etwas tricky sein (Klasse darf nicht im Default-Package liegen) aber sollte das erledigen können, was du gerne hättest.
    Harbinger ist offline

  6. #6 Zitieren
    Pretty Pink Pony Princess  Avatar von Multithread
    Registriert seit
    Jun 2010
    Ort
    Crystal Empire
    Beiträge
    11.231
    Mal ne frage am Rande: Weshalb nutzt du überhaupt verschachtelte Klassenkonstrukte?
    Ich weiss das es geht, habe aber bisher noch keinen Anwendungsfall gesehen, wo dies nötig oder gar Vorteilhaft gewesen wäre.


    Solange eine Klasse verschachtelt ist, kannst du Sie nur über dieses Doppel aufrufen. Dies gilt z.B. auch für Enums, welche in einer Klasse definiert sind.
    [Bild: AMD_Threadripper.png] Bei Hardware gibt es keine eigene Meinung, bei Hardware zählen nur die Fakten.


    Probleme mit der Haarpracht? Starres Haar ohne Glanz? TressFX schafft Abhilfe. Ja, TressFX verhilft auch Ihnen zu schönem und Geschmeidigen Haar.
    [Bild: i6tfHoa3ooSEraFH63.png]
    Multithread ist offline

  7. #7 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.376
    Zitat Zitat von Multithread Beitrag anzeigen
    Mal ne frage am Rande: Weshalb nutzt du überhaupt verschachtelte Klassenkonstrukte?
    Ich weiss das es geht, habe aber bisher noch keinen Anwendungsfall gesehen, wo dies nötig oder gar Vorteilhaft gewesen wäre.
    Das habe auch ich mich gefragt. Da steht doch, dass ParentAdapterItem den "Bauplan" für InnerAdapterItem hat und dass es diesen öffentlich zur Verfügung stellt. Folglich muss man den Namen von ParentAdapterItem mit angeben, um speziell diesen Bauplan auszuwählen. Da frage ich mich doch, ob es verschiedene Ausführungen von InnerAdapterItem geben kann, also zwar immer mit demselben Namen, aber spezifisch für ParentAdapterItem (keine Ahnung, ob der Name von InnerAdapterItem unterschiedliche Typen meinen kann). Bei einem Ordnungssystem, z.B. für ein Framework, könnte ich mir schon vorstellen, dass das Vorgehen sinnvoll ist. Allerdings hätte man immer noch die Packages an der Hand, weswegen es wohl eher auf eine Einzelfallentscheidung ankäme. Den vergebenen Namen nach würde ich aber eher von etwas anderem ausgehen und auch erst einmal fragen wollen, ob das so sein muss.

    Falls z.B. ParentAdapterItem solch ein InnerAdapterItem erstellen (siehe auch Heinzi dazu) oder verwenden würde, könnte das tatsächlich der Ort sein, wo zu stehen hat, wie es beschaffen ist. Es könnte z.B. darum gehen, diesen speziellen Typ, welcher sich hinter dem Namen InnerAdapterItem verbirgt, nicht mit anderen Typen, die denselben Namen tragen, zu verwechseln (weil er voll qualifiziert sein muss, schwer zu verwechseln). Dann sollte dieses Nesting sogar überaus sinnvoll sein. Aber allgemein ist das wohl nicht so oft nötig (Edit#1: Ich meinte, bei User-Code. Bei fetten Libs, die viele unterschiedliche Typen anbieten, kann das schon anders aussehen.).

    Edit#2:
    Eine weitere Idee (die ich vorerst zurückgestellt hatte): Vielleicht war eine "echte" innere Klasse gewollt, wobei static bloß hingeschrieben wurde, weil die Instanziierung so auf den ersten Blick bequem(/-er) erscheint oder weil momentan nicht geläufig war, wie sie bei einer inneren Klasse zu erfolgen hätte?

    Kleiner Hinweis am Rande, weil C++ angeführt wurde:
    Unter C++ würde man nicht #define nehmen (textuelle Ersetzung durch den Präprozessor macht nicht immer, was man meint, und der Compiler kann sie nicht prüfen, sondern nur stur übernehmen), sondern das gute alte (aus C übernommene) typedef oder das (modernere (ab C++11)) using, sodass man (bei beiden Varianten) einen echten Typalias erhält, z.B. using AdapterItem=ParentAdapterItem::InnerAdapterItem;
    jabu ist offline Geändert von jabu (15.07.2020 um 17:25 Uhr)

  8. #8 Zitieren
    Ritter Avatar von Feuerstern
    Registriert seit
    Sep 2007
    Beiträge
    1.816
    Danke für eure Tipps und Anregungen. Ich habe das ganze dann letztlich doch außeinander gezogen.
    Das ganze hier war ein stark vereinfachtes Beispiel.
    Konkret ging es um eine Recyclerview in einem Android Projekt. Diese kann dazu verwendet werden Daten in einer Art Liste oder einem Grid anzuzeigen. Dafür braucht man einen Adapter indem definiert ist wie die Daten aus einer Liste (in diesem Fall ParentAdapterItem mit verschiedenen Unterklassen) angezeigt werden.
    Dieser Adapter benötigt dann einen ViewHolder in dem genau definiert ist wie ein Eintrag letztlich aussieht. Den ViewHolder habe ich z.B. noch immer als Unterklasse des Adapters. Da der ViewHolder nur im Adapter benutzt wird bekommt man das Problem mit der langen Auflösung a la Adapter.ViewHolder.bla nicht. Ursprünglich hatte ich im Adapter noch die ParentAdapterItem Klasse und dessen Unterklassen untergebacht. Da diese Klasse aber auch außerhalb der Adapter Klasse benutzt wird um die Daten zu laden kam es dann zu Adapter.ParentAdapterItem.InnerAdapterItem Aufrufen. Da diese Items nur in Verbindung mit dem Adapter benötigt werden und praktisch direkt dazu gehören wollte ich die Items erst innerhalb der Adapter Klasse definiere. Aber da es sich in der Praxis als zu unübersichtlich erwiesen hat hab ich davon abgelassen.
    Der ViewHolder ist aber meiner Meinung nach ein Beispiel dafür, wo es durchaus sinnvoll sein kann die Sache so zu machen.
    Feuerstern ist offline

  9. #9 Zitieren
    Legende Avatar von jabu
    Registriert seit
    Jul 2011
    Beiträge
    7.376
    Zitat Zitat von Feuerstern Beitrag anzeigen
    Konkret ging es um eine Recyclerview in einem Android Projekt. Diese kann dazu verwendet werden Daten in einer Art Liste oder einem Grid anzuzeigen. Dafür braucht man einen Adapter indem definiert ist wie die Daten aus einer Liste (in diesem Fall ParentAdapterItem mit verschiedenen Unterklassen) angezeigt werden.
    Dieser Adapter benötigt dann einen ViewHolder in dem genau definiert ist wie ein Eintrag letztlich aussieht.
    Gut, dass du das jetzt sagst. Meistens ist es besser, auch den Kontext mitgeteilt zu bekommen (wie nun geschehen).
    Da der ViewHolder nur im Adapter benutzt wird bekommt man das Problem mit der langen Auflösung a la Adapter.ViewHolder.bla nicht.
    Ja, das ergibt für mich (nachdem ich mich in der Android-Dokumentation zu RecyclerView umgesehen habe) einen Sinn, z.B.:
    Code:
    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
        . . .
        public static class ViewHolder extends RecyclerView.ViewHolder {
            . . . .
            public ViewHolder(View itemView) {
                super(itemView);
                . . .
            }
        }
        . . . 
    }
    So ungefähr?
    Ursprünglich hatte ich im Adapter noch die ParentAdapterItem Klasse und dessen Unterklassen untergebacht. Da diese Klasse aber auch außerhalb der Adapter Klasse benutzt wird um die Daten zu laden kam es dann zu Adapter.ParentAdapterItem.InnerAdapterItem Aufrufen.
    Von wegen "Daten laden" (weil ich nicht weiß, wie du das gemeint hattest): Aufgaben mit einer Ausführungszeit von mehr als wenigen Millisekunden (wobei schon das verdammt lange ist, also eigentlich Mikrosekunden) gehören, wenn sie nicht asynchron angestoßen werden können (sodass sofort nach dem, hoffentlich schnellen, Absetzen einer Nachricht aus dem Funktionsaufruf in den Event-Handler zurückgesprungen wird, sodass seine Durchlaufzeit annähernd minimal bleibt), in einen Worker-Thread (wie auch immer der hier heißen mag), schon damit sie nichts einfrieren lassen (wobei dieses Einfrieren sowohl die Darstellungs- als auch Interaktionsebene betreffen kann).
    Da diese Items nur in Verbindung mit dem Adapter benötigt werden und praktisch direkt dazu gehören wollte ich die Items erst innerhalb der Adapter Klasse definiere. Aber da es sich in der Praxis als zu unübersichtlich erwiesen hat hab ich davon abgelassen.
    Ich weiß zu wenig Konkretes, um das einzuschätzen zu können, aber es klingt zumindest unter den von dir angeführten Bedingungen (wobei ich nicht weiß, inwiefern die sich mal ändern können) plausibel, und du sitzt an der Sache dran und wirst das schon machen.
    Der ViewHolder ist aber meiner Meinung nach ein Beispiel dafür, wo es durchaus sinnvoll sein kann die Sache so zu machen.
    Ja, es sieht danach aus. Um solche Sachen beurteilen zu können, muss man ganz schön viele konkrete Details wissen, vor allem das Framework betreffend (man sollte möglichst nicht gegen seine Natur arbeiten).
    jabu ist offline

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •