Via Interfaces unterschiedliche Klassen ansprechen

lui

Mitglied
Hallo ,
Ich bin neu in Java, habe vorher jahre c# programmiert und weiß nicht wie ich
folgendes in Java umsetze...

versuche die Klassen java.io.File und jcifs.smb Abstrakt zu verwenden.
Ich habe eine Klasse <FileDatabrowser> ,welche diverse Suchen, Filter und Konvertierungen
für alle gelesenen(oder geschriebenen) Files macht.

Nun ist es für meine Klasse egal ob die daten über SMB(jcifs) oder IO.FILE kommen
und ich versuche nun mittels Interfaces (in C# hatte ich delegaten verwendet)
die zwei Klassen abstrakt anzusprechen (polymorphismus).
Dazu übergebe ich in der methode <getdir> den Interface Datentyp<i_File> und versuche
alle sachen über die Interface instanz zu machen.

DAS Problem is an dieser Stelle
(i_File file : f.listFiles())
ich kann nicht über die elemente des Interfaces loopen

gibt es da irgendeine Lösung ?

in c# hätte ich f.listfiles und alle weiteren funktionen per delegate umgeändert

Java:
 public interface i_File {
     String getName();
     String getPath();
     ...and many others
}

--FILE.IO Wrapper
Java:
public class genFile extends java.io.File implements i_File
{
    ...constructors
    @Override
    public String getName(){
        return super.getName();
    }

    @Override
    public String getPath(){
        return super.getPath();
    }

}

--SMB.JCIFS Wrapper
Java:
public class genSmb extends SmbFile implements i_File
{
    ...constructors
    @Override
    public String getName(){
        return super.getName();
    }

    @Override
    public String getPath(){
        return super.getPath();
    }
}

-- HAUPTKLASSE verwendet entweder SMB oder FILE IO
Java:
public class FileDatabrowser
{
    public void getdir(i_File f)
    {
        FileData fileData;
        if (f != null)
        {
            for (i_File file : f.listFiles())
            {
                if (file.canRead())
                {
                    fileData = new FileData();
                    FileDataSet(fileData,file);
                    fileDataList.add(fileData);
                }
            }
        }
    }
}
 
Zuletzt bearbeitet von einem Moderator:
versuche die Klassen java.io.File und jcifs.smb Abstrakt zu verwenden.
Was soll "jcifs.smb" sein? Was meinst du mit "abstrakt verwenden"?

Dazu übergebe ich in der methode <getdir> den Interface Datentyp<i_File> und versuche
alle sachen über die Interface instanz zu machen.
Man kann keine Instanz eines Interfaces haben.
(Nebenbei: "i_" für ein Interface ist in Java sehr ungewöhnlich. Normalerweise verwendet man hier keine Pre bzw. Postfixe)

DAS Problem is an dieser Stelle
(i_File file : f.listFiles())
ich kann nicht über die elemente des Interfaces loopen
"Ich kann nicht" ist keine Fehlerbeschreibung 😉
Was kann du nicht? Kompiliert dein Code? Kommt eine Fehlermeldung?


Es ist zwar schön das du uns zeigst wie du getName bzw. getPath überschreibst, aber nicht was du bei listFiles machst, das wäre das Interessantere.
Sofern listFiles() eine entsprechende Liste zurück gibt, sollte es möglich sein mittels foreach Schleife darüber zu iterieren.
 
1.jcifs ist ein framework (nicht von mir) für smb Datei zugriff über lan
2. i_ nur vorläufig so benannt


Also mein grundlegendes problem ist
Ich habe zwei Klassen die vollkommen identische Methoden haben, die ich aber nicht ändern kann
nun will ich in meiner Klasse nicht alle Methoden 2 mal schreiben nur weil die Klassen anderst heißen

Mein Ziel ist:
Code:
   public void getDir(AnyClassInstance o)
    {
                for (Object i : o.listFiles())
                {
                    if (i.canRead())
                    {
                        fileData = new FileData();
                        FileDataSet(fileData,i);
                        fileDataList.add(fileData);
                    }
                }
    }


Man kann keine Instanz eines Interfaces haben.
Ok das weiß ich. hab mich falsch ausgedrückt.




Listfiles ist mein problem
Die fehlermeldung ist
Error🙁52, 48) java: incompatible types: java.lang.Object cannot be converted to com.company.i_file_


Die listfiles methode sieht derzeit so aus
Code:
public  interface  i_file_<T>
{
    String getName();
    String getPath();
    boolean isDirectory();
    long lastModified();
    long length();
    boolean isHidden();
    boolean canRead();
    T[] listFiles();

}

java.io.File implements i_file_
Code:
public class genFile extends java.io.File implements i_file_
{
 @Override
  public File[] listFiles()
  {
  return super.listFiles();
  }

 }

Code:
public class genSmb SmbFile implements i_file_
{
 @Override
  public SmbFile[] listFiles()
  {
  try
  {
  return super.listFiles();
  }catch (Exception e)
  {
  return null;
  }

  }

 }
 
Mit C# hab ich auch noch nicht so viel gemacht, aber wenn ich das richtig verstehe erwartest du so etwas wie Duck-Typing? Du willst eine bestimmte Methode (listFiles) unabhängig davon ausführen, aus welcher Klasse die stammt?

Eventuell kommst du mit den Lambdas/Methodenreferenzen aus Java8 weiter.
Java:
public interface ListFilesWrapper {
     String[] listFiles();
}


String getFiles(ListFilesWrapper wrapper) {
    return wrapper.listFiles();
}

getFiles(my_smb_object::listFiles);

Wenn du in Java8 ein interface mit nur einer Funktion hast, kannst du dem einfach eine Methodenreferenz oder ein Lambda zuweisen. my_smb_object::listFiles weist ihm (durch den :: Operator) die Referenz auf die Methode listFiles des Objekts my_smb_object zu. Daß die Methode aus dem interface auch listFiles heißt ist dabei nur Zufall, die kann auch beliebig anders heißen.
Im Prinzip ist das nur eine Kurzschreibweise für eine anonyme Klasse:
Java:
getFiles(new ListFilesWrapper() {
    String[] listFiles() {
        return my_smb_object.listFiles();
    }
});

Hoffe das hilft weiter.
 
dein i_file interface ist generisch, du ignorierst den generischen Parameter aber, daher steht für den Compiler überall nur Object. Und ein Object kann nunmal nicht implizit in ein i_File gecastet werden
 
Du willst eine bestimmte Methode (listFiles) unabhängig davon ausführen, aus welcher Klasse die stammt?
Genau das ist es.
nn du in Java8 ein interface mit nur einer Funktion hast, kannst du dem einfach eine Methodenreferenz oder ein Lambda zuweisen
Danke das hat mir geholfen, das ist eine möglichkeit.
Nur will ich letztendlich für Android Entwickeln und das unterstützt JAVA 8 nur bedingt.
Ich habe es jetzt mit <instanceof> gelöst.
nicht sehr schön aber geht.
Code:
// Wrapper for JCIFS.SMB, FILE.IO
public final class genFile<T>
{

    public static boolean canRead(Object o)
    {
        if (o instanceof File)
            return ((File) o).canRead();
        else
            try
            {
                return ((SmbFile) o).canRead();
            } catch (SmbException e)
            {
                return false;
            }
    }

    public static <T> T[] listFiles(T o)
    {
        File[] f;
        SmbFile[] s;
        if (o instanceof File)
        {
            f = ((File) o).listFiles();
            return (T[]) f;
        } else
        {
            try
            {
                s = ((SmbFile) o).listFiles();
                return (T[]) s;
            } catch (SmbException e)
            {
                e.printStackTrace();
            }
        }
        return null;
    }


    public static int listFilesLength(Object o)
    {
        if (o instanceof File)
            return ((File) o).listFiles().length;
        else
            try
            {
                return ((SmbFile) o).listFiles().length;
            } catch (SmbException e)
            {
                return 0;
            }
    }

    public static String getName(Object o)
    {
        if (o instanceof File)
            return ((File) o).getName();
        else
            return ((SmbFile) o).getName();
    }

    public static String getPath(Object o)
    {
        if (o instanceof File)
            return ((File) o).getPath();
        else
            return ((SmbFile) o).getPath();
    }

    public static long length(Object o)
    {
        if (o instanceof File)
            return ((File) o).length();
        else
            try
            {
                return ((SmbFile) o).length();
            } catch (SmbException e)
            {
                return 0;
            }
    }

    public static boolean isDirectory(Object o)
    {
        if (o instanceof File)
            return ((File) o).isDirectory();
        else
            try
            {
                return ((SmbFile) o).isDirectory();
            } catch (SmbException e)
            {
                return false;
            }
    }

    public static long lastModified(Object o)
    {
        if (o instanceof File)
            return ((File) o).lastModified();
        else
            try
            {
                return ((SmbFile) o).lastModified();
            } catch (SmbException e)
            {
                return 0;
            }
    }

    public static boolean isHidden(Object o)
    {
        if (o instanceof File)
            return ((File) o).isHidden();
        else
            try
            {
                return ((SmbFile) o).isHidden();
            } catch (SmbException e)
            {
                return false;
            }
    }
}


W
 
dein i_file interface ist generisch, du ignorierst den generischen Parameter aber, daher steht für den Compiler überall nur Object. Und ein Object kann nunmal nicht implizit in ein i_File gecastet werden

Ja das war verzeiflung, denn wenn ich den generischen parameter benutze kann ich die Funtkion nicht mehr nutzen

So gehts :
Code:
  public File[] listFiles()
  {
  return super.listFiles();
  }
So nicht
Code:
    public T[] listFiles()
    {
        return (T).listFiles(); ?????
    }
 
Die Lösung mit einem Wrapper fände ich wesentlich eleganter und auch besser nutzbar.
Man braucht dafür auch weder Generics noch extends, einfach nur ein Interface und für beide Typen einen Wrapper, der jeweils ein Feld des Typen enthält, listfiles() gibt dann eine Liste des Interfaces zurück.
 
Nur will ich letztendlich für Android Entwickeln und das unterstützt JAVA 8 nur bedingt.
Letztendlich sparst du in meinem Beispiel durch Java8 auch nur, daß du die anonyme Klasse selbst schreiben musst. Schreibst du die Klasse so aus, wie ich das darunter geschrieben habe, geht das auch mit älteren Versionen.
 

Neue Themen


Zurück
Oben