Quizfrage zu JNI

Status
Nicht offen für weitere Antworten.
S

Spacerat

Gast
Ist schon etwas länger her, da hat man mir im Forum gesagt, "private final" sei für Methoden überflüssig. Das hab' ich mal so hingenommen. Nicht zuletzt, weil sich die folgenden beiden Klassen fehlerlos (ok, 2 Warnungen kommen) kompilieren lassen.
Java:
public class ExtendMe
{
  static
  {
    System.loadLibrary("ExtendMe");
  }

  private final void privateFinalMethod()
  {
    System.out.println("You are in ExtendMe.class");
  }

  public final native void doCallback();
}
Java:
public class Extension
extends ExtendMe
{
  private final void privateFinalMethod()
  {
    System.out.println("You are in Extension.class");
  }

  public static void main(String[] args)
  {
    new Extension().doCallback();
  }
}
In der DLL sieht die "native"-Method so aus:
Code:
JNIEXPORT void JNICALL Java_ExtendMe_doCallback
  (JNIEnv * pEnv, jobject obj)
{
  jclass clazz = pEnv->GetObjectClass(obj);
  jmethodID mid = pEnv->GetMethodID(clazz, "privateFinalMethod", "()V");
  pEnv->CallVoidMethod(obj, mid);
}
Die Frage ist nun, welchen der beiden Sätze man zu lesen bekommt. HINT: Die Antwort rät zur Vorsicht!
 
S

Spacerat

Gast
Na ein Glück gibt's 'ne Lösung... und die löst dann auch gleich noch ein Performance-Problem (toller Nebeneffekt).
Na ja... Trotzdem hätte in diesem Fall doch ein simpler "can't override final method"-Error genügt, um diese Ausgabe zu verhindern:
Code:
You are in Extension.class
 

Marco13

Top Contributor
Naja - es wird ja nicht overridden. Dass man mit JNI auf private Sachen zugreifen kann, sorgt in diesem Fall eben für eine Zweideutigkeit, die es ohne JNI garnicht gibt...
 
S

Spacerat

Gast
gar nicht (...wird gar nicht zusammen geschrieben...) overridden? Dann versteh' ich das mit den Methoden überschreiben wohl nicht. Diese beiden Methoden oben, haben die gleichen Signaturen. Nur weil sie private sind, rechtfertigt das unter keinen Umständen, das eine von mir als final deklarierte Methode in einer erweiternden Klasse erneut deklariert werden darf. Das sagt zumindest final aus und das unabhängig von standard, public, protected oder private. Aber was solls... Sun wird sich dabei schon nichts gedacht haben.
 
Zuletzt bearbeitet von einem Moderator:

Marco13

Top Contributor
Ja hm - eine private Methode kann ja grundsätzlich nicht overridden werden (deswegen ist das "final" ja eigentlich auch überflüssig). Wenn man privateFinalMethod aufruft, macht das in der einen Klasse das eine und in der anderen das andere - das sind einfach zwei unterschiedliche Methoden, die mit den praktischen Features wie Vererbung und Polymorphie nichts zu tun haben....
 

sliwalker

Top Contributor
So siehts aus.
Die Methode in der Superklasse ist private und genau aus diesem Grund für die Subklasse nicht sichtbar und kann sie deshalb auch nicht überschreiben. Deshalb ist das fehlerfreie Kompilieren auch möglich.
Das mit JNI auf private-Sachen zugegriffen werden ist klar.

Also...alles gut!
Oder auch nicht...ich geb zu, dass es verwirrend ist, wenngleich einfach absolut korrekt umgesetzt.

greetz
SLi
 
S

Spacerat

Gast
In silkwalkers Signatur kann man es sehr schön nach lesen:
Ich finde, dass das "final" bei privaten Methoden keineswegs überflüssig ist, weil es eben eine Trapdoor darstellt. Bei jeder anderen Zugriffsart einer Methode gilt: "final" verhindert weitere Deklarationen in erweiternden Klassen. "private final" sollte da keine Ausnahme sein, nur weil es eigentlich nicht möglich ist, von aussen darauf zuzugreifen. Vergleicht man das z.B. mit einer SPS-Motorsteuerung mit Rechts- Linkslauf, wurde die Ausgangsverriegelung schlicht vergessen. In der Automatisierungstechnik wird man für so etwas "erhängt" (-> Kurzschluss). Hier fällt man blos in eine "Trapdoor", die durch "final" verhindert wäre.
 

sliwalker

Top Contributor
Hmm,

Dein Motorsteuerungsbeispiel erschließt sich mir nicht.
Aber dennoch, final bei privaten Methoden ist aus der Perspektive sinnlos, weil die Methode eben so oder so nicht gesehen wird und deshalb schon alleine dadurch nicht überschrieben werden kann. Es wäre also redundant.

Dies ist mir persönlich aber egal. Denn ich deklariere auch jede Methode in einem Interface public abstract, auch wenn es automatisch so kompiliert wird. "girl code" hin oder her, für mich macht es Sinn "für jeden offensichtliche" Dinge nochmal explizit hinzuschreiben.

Wenn Du trotzdem darauf bestehst, dass es Sinn macht private Methoden als final zu deklarieren, dann ignorierst Du die Mechanik von access-modifiers, die in der Wichtigkeitshirachie weiter oben stehen, als non-access-modifiers wie final.

Oder fängts Du an zu debuggen, wenn Du nur die Information hast, dass eine Methode final ist und nicht weißt welche Sichtbarkeit dazu gehört? Nach logischem Ausschlussverfahren brauchst Du an der Stelle schon nicht mehr weitersuchen, wenn Du siehst, dass eine Methode private ist. Es ist schlicht egal was danach kommt. Logisches ODER. Eins erfüllt und weg....

greetz
SLi
 
S

Spacerat

Gast
Dann wird's Zeit das man dazu lernt...
1. Access-Modifiers und Nonaccess-Modifiers sind zwei verschiedene Dinge, wie beim Motor der Rechts- bzw. Linkslauf.
2. Bei Drehstrom-Motoren erreicht man die Umschaltung vom Rechts- nach Linkslauf durch das vertauschen von 2 Phasen (Wendeschützschaltung).
3. Drei Phasen des Netzes gehen auf 2 Schütze (Relais). Pro Richtung einer. Bei einem werden dabei 2 Phasen miteinander vertauscht.
4. Die Steuerleitungen der Relais kommen jeweils auf einen Ausgang der SPS.
5. Innerhalb der SPS müssen die Ausgänge gegeneinander verriegelt werden, da beim setzen beider Ausgänge gleichzeitig ein Kurzschluss entsteht. Die Verriegelung wird dadurch erreicht, das man beim Setzen des Einen unbedingt ausschliesst, das der jeweils Andere bereits gesetzt ist (UND-Verknüpfung mit negiertem Eingang).

Fazit: Würde man in Java auch stets beides prüfen, gäbe es nicht nur mindestens eine Trapdoor weniger sondern man könnte sich auch solche "Workarounds", wie oben von Marco13 verlinkt, sparen.
@Edit: ... und das man von Java aus nicht drauf zugreifen kann und damit auch die Tatsache das nicht weiter geprüft werden muss, hat sich mit diesem Experiment dann wohl auch erledigt:
Java:
import java.lang.reflect.Method;

public class Extension
extends ExtendMe
{
  private final void privateFinalMethod()
  {
    System.out.println("You are in Extension.class");
  }

  public static void main(String[] args)
  {
    new Extension().doCallback();
    ExtendMe em = new ExtendMe();
    try {
      Method m = em.getClass().getDeclaredMethod("privateFinalMethod");
      m.setAccessible(true);
      m.invoke(em);
    } catch(Throwable e) {
    }
  }
}
Ausgabe:
Code:
You are in Extension.class
You are in ExtendMe.class
Mit anderen Worten: Nun ist's ein grober Fehler.
 
Zuletzt bearbeitet von einem Moderator:

sliwalker

Top Contributor
Hoi,

ja richtig.
Wie schon gesagt, mit JNI und Reflection kommst Du drumherum.
Ich will das nun gar nicht wirklich verteidigen, dass es so geht, aber wenn Du Mechanismen verwendest, die absichtlich solche Möglichkeiten bieten und Du absichtlich eine private final Method aufrufst, dann bist Du selber Schuld. Normalerwiese würde es Dir verboten werden. Du programmierst also absichtlich drumherum. Ist jetzt ne Glaubensfrage, ob das verboten sein müsste oder nicht.

greetz
SLi
 
S

Spacerat

Gast
Selber Schuld heisst, man hat eine Dummheit gemacht! So viel ist Klar. Mit der Dummheit anderer ist stets zu rechnen. Und wenn nun irgend so ein "Vollpfosten" (uns natürlich ausgeschlossen, da uns diese Trapdoor spätestens bekannt ist) nun statt "m.invoke(em);" "m.invoke(this);" (irgendwo innerhalb von ExtendMe, warum auch immer usw.) dahinkritzelt, weil er davon ausgeht, das seine Methode eh' nicht überschrieben werden kann, weil sie doch "final" ist, hat er ein Problem. Das ist also keine Glaubensfrage, sondern Sicherheit. ->Idiotensicher... wenn ich es mal so ausdrücken darf.
Anm.: Jeder der das liest, muss sich nicht auf den Schlips getreten fühlen. Man bedenke, das Ich letztendlich einer dieser "Vollpfosten" bin (war), für den Java etwas "idiotensicherer" gemacht werden sollte. Ferner möchte ich die Herren Sicherheitsfachkräfte (Also Menschen, die beruflich solche Problematiken aufspüren und eliminieren) keinesfalls als Berufs-Idioten bezeichnen.
 
Zuletzt bearbeitet von einem Moderator:

sliwalker

Top Contributor
Ok,

ich weiß woruaf Du hinaus willst.
Aber wenn wir anfangen, um die Dummheit "anderer" (wir natürlich nicht) drumherum zu programmieren, brauchen wir auch keine LangSpec mehr. Es ist halt die Aufgabe eines jeden Entwicklers sein Instrument zu kennen. Sagen Ärtze nach einer misslungenen Herz-OP, "oh, ich wusste jetzt nicht, dass der Knop da am Laserskalpell den Schneidradius erhöht, sorry". Denn wenn man die API in Bezug auf invoke liest steht da deutlich:

If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The Java Language Specification, Second Edition, section 15.12.4.4; in particular, overriding based on the runtime type of the target object will occur.

So. Jetzt ist das ohne Frage eine Ausnahme. Aber Reflection selbst ist eine große Ausnahme.
Ich bleib dabei, Java verbietet es, wenn man Java ohne Reflection und dergleichen verwendet. Greift man auf solche Mechanismen zu, muss manwissen was man macht. Allein schon den access-modifier zu verändern ist nicht grad das gelbe vom Ei. Dann ist doch die Klasse an sich schon schlecht designed, wenn man auf die Methode in dieser Art Zugriff braucht...

Sei froh, dass es keine C++-Pointer gibt... :)

greetz
SLi

PS: Ich diskutiere nur, ich klage niemanden an und meine niemanden bestimmtes!
 
Zuletzt bearbeitet:
S

Spacerat

Gast
Sei froh, dass es keine C++-Pointer gibt... :)
YESSSSS.... :D
Obwohl: An dieser Stelle könnte wieder eine Grundsatzdiskussion entbrennen, wenn irgend jemand mal wieder sagt, die Referenzen in Java sind eigentlich die Pointer in C++, weswegen es in Java keine Referenzen gibt (oder so). :lol: Neee... lieber doch nicht.
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben