2009-08-12 9 views
2

Die folgende Methode generiert eine Warnung, aber es sieht für mich sicher aus. Ich bin sicher, dass das Problem bei mir ist:Warum ist diese generische Methode unsicher?

public <S extends CharSequence> S foo(S s) { 
    return (S) new StringBuilder(s); 
} 

Es sieht aus wie das immer das Argument kehrt s. Kann jemand ein Beispiel zeigen, dass diese Methode eine Ausnahme auslöst?

Edit: Ich bin nicht besonders interessiert an der Frage, ob Generika hier notwendig sind. Ich bin eher auf der Suche nach einer Demonstration, wie diese Methode unsicher ist.

+0

Als Antwort auf die Unsicherheit, Skaffmans Antwort erklärt es gut, wie auch Sonstiges: Der Cast (S) (nach dem Schlüsselwort return) wird fehlschlagen, wenn Sie einen String als Parameter übergeben, weil er keinen StringBuilder in einen String umwandeln kann. – KLE

Antwort

1

foo ("Test");

ist genug, damit Java versucht, einen StringBuilder in einem String zu erzeugen.

Ihr Code ist garantiert falsch, können Sie erklären, was Sie erreichen möchten?

+0

Ich habe es gerade versucht, und es hat gut funktioniert. –

+0

OK, 'foo (" test ")' war alleine nicht genug, aber wenn ich es ausdrucken wollte oder es einer Zeichenkette zuordnete, bekam ich den Fehler. Was meinen Zweck betrifft, versuche ich zu verstehen. Ich versuche auch, die SCJP-Prüfung zu bestehen, wenn das hilft. –

0

meine Java ist rostig, aber würde diese Methode nicht, was Ausnahmen

new StringBuilder(s) 

werfen werfen?

+0

Ich habe gerade nachgesehen. Wenn 's' null ist, würde dies eine Ausnahme erzeugen, aber das würde auch für die nicht-generische Methode von skauffman gelten. –

6

Es ist unsicher, da StringBuilder eine CharSequence ist, ist es nicht unbedingt vom Typ S (in der Tat wird es fast sicher nicht sein). Sie können diesen Fehler nur sehen, indem Sie eine String in Ihre Methode übergeben. Dies wird eine StringBuilder mit Ihrer String als ein Argument erstellen, und dann versuchen, Ihre StringBuilder zu String (was fehlschlagen wird).

Wahrscheinlich gibt es keine Notwendigkeit, Generika zu verwenden, hier überhaupt, sollte diese gut funktionieren:

public CharSequence foo(CharSequence s) { 
    return new StringBuilder(s); 
} 
+0

Dennoch möchte ich verstehen, was damit nicht stimmt. Ich gestehe, dass ich für die SCJP-Prüfung studiere. –

+0

+1 Ich stimme Ihnen zu, wenn Sie sagen, dass hier keine Generika verwendet werden müssen – dfa

+0

Ihre Methode hat einen Rückgabetyp S, der durch den Typ des Objekts definiert ist, das Sie als Argument übergeben. Der StringBuilder wird in diesen Typ umgewandelt, wenn die Methode ausgeführt wird. Wenn Sie einen String als Argument übergeben, dann ist Typ S eigentlich String, und StringBuilder kann nicht in String umgewandelt werden. – skaffman

2

Zum Beispiel diese kompilieren:

String a = foo("ss"); 

aber es wird zur Laufzeit fehlschlagen:

seit foo gibt S, die Art Ihrer Eingabe pa zurück rameter (String in diesem Fall).

Ich denke, dass Sie Generika nicht hier verwenden müssen (wie skaffman said in his answer):

public StringBuilder foo(CharSequence s) { 
    return new StringBuilder(s); 
} 
1

Die unsafety hier liegt nicht innerhalb der Methode selbst (obwohl es hat seine Probleme, auch), aber beim Aufruf Seite? ˅. Die Verwendung von S für den Typ des Eingabearguments sowie für den Rückgabewert teilt dem Compiler mit, dass unabhängig vom Objekttyp, der an die Funktion übergeben wird, das Ergebnis den gleichen Typ hat (oder ein abgeleiteter Typ , tatsächlich).

Somit wird der Compiler davon ausgehen darf, dass in dem Aufruf

foo("hello, world") 

das Ergebnis wird ein java.lang sein.String, während im Aufruf

foo(new StringBuffer("hello, world")) 

das Ergebnis wird ein String, und so weiter. In beiden Fällen gibt Ihre Methode jedoch nicht zurück, was zurückgegeben werden soll, nämlich ein Objekt des gleichen Typs wie das Eingabeargument. Stattdessen wird ein StringBuilder zurückgegeben.

die einzige Art von Eingabeargument Ihrer Methode mit arbeiten ist eigentlich ein String, alles anderes wird verurteilt mit einem Classcast zum Absturz früher oder später, als der Compiler könnte (und oft den Fall bin) ein (versteckt) wirft an den Rufstellen.

Und natürlich, wie andere schon darauf hingewiesen haben, ist der Einsatz von Generika hier sowieso nicht nötig.

1

Der Rückgabetyp Ihres Methodencodes ist IMMER ein StringBuilder.

Das liegt daran, dass der deklarierte Typ des Ausdrucks ‚new Stringbuilder (x)‘ IMMER ein String ist, unabhängig von der X.

es völlig sinnlos ist, zu versuchen und werfen diese zu nichts. Die "S" -Information ist Teil der Löschung, die nur zur Kompilierungszeit existiert und zu der Zeit, zu der das Programm läuft, dh zur Laufzeit, gelöscht wird. (Casting ist eine Laufzeit-Sache exklusiv, und Casting etwas zu einem Typ/Klasse, deren Identität wurde eine Laufzeit gelöscht, ist in der Tat völlig sinnlos.)

Verwandte Themen