2017-08-18 3 views
0

En Java, si je joue plusieurs méthodes sur un objet, je peux les enchaîner, ou je peux faire une variable temporaire, comme siEst-ce que les méthodes de chaînage et la création de variables temporaires en Java affectent l'allocation de mémoire?

Chaînage

System.out.println(str.substring(0,4).substring(0,2)); 

variable Temp

String tmp = str.substring(0,4); 
    tmp = tmp.substring(0,2); 
    System.out.println(tmp); 

De toute évidence, la différence est négligeable dans cet exemple, mais pourrait avoir un impact lorsque vous le faites sur des milliers de chaînes/un autre objet. Ma question est, est-ce que l'un d'entre eux est plus «efficace» en termes de ne pas faire des allocations d'objets supplémentaires ou de remplir le tas (et donc de faire appel au GC plus tôt)?

J'ai essayé de comparer les bytecodes des deux dans une boucle sur quelques chaînes, mais il semble similaire, sans pour les dernières lignes. Je ne comprends pas tous les appels bytecode, donc je ne suis pas sûr si l'un de ces derniers a à voir avec l'allocation de nouveaux objets.

Compiled from "TestNoTmp.java" 
public class TestNoTmp { 
    public TestNoTmp(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: iconst_4 
     1: anewarray  #2     // class java/lang/String 
     4: dup 
     5: iconst_0 
     6: ldc   #3     // String These 
     8: aastore 
     9: dup 
     10: iconst_1 
     11: ldc   #4     // String Are__ 
     13: aastore 
     14: dup 
     15: iconst_2 
     16: ldc   #5     // String Some_ 
     18: aastore 
     19: dup 
     20: iconst_3 
     21: ldc   #6     // String Strings 
     23: aastore 
     24: astore_1 
     25: aload_1 
     26: astore_2 
     27: aload_2 
     28: arraylength 
     29: istore_3 
     30: iconst_0 
     31: istore  4 
     33: iload   4 
     35: iload_3 
     36: if_icmpge  69 
     39: aload_2 
     40: iload   4 
     42: aaload 
     43: astore  5 
     45: getstatic  #7     // Field java/lang/System.out:Ljava/io/PrintStream; 
     48: aload   5 
     50: iconst_0 
     51: iconst_4 
     52: invokevirtual #8     // Method java/lang/String.substring:(II)Ljava/lang/String; 
     55: iconst_0 
     56: iconst_2 
     57: invokevirtual #8     // Method java/lang/String.substring:(II)Ljava/lang/String; 
     60: invokevirtual #9     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     63: iinc   4, 1 
     66: goto   33 
     69: return 
} 

public class TestTmp { 
    public TestTmp(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: iconst_4 
     1: anewarray  #2     // class java/lang/String 
     4: dup 
     5: iconst_0 
     6: ldc   #3     // String These 
     8: aastore 
     9: dup 
     10: iconst_1 
     11: ldc   #4     // String Are__ 
     13: aastore 
     14: dup 
     15: iconst_2 
     16: ldc   #5     // String Some_ 
     18: aastore 
     19: dup 
     20: iconst_3 
     21: ldc   #6     // String Strings 
     23: aastore 
     24: astore_1 
     25: aload_1 
     26: astore_2 
     27: aload_2 
     28: arraylength 
     29: istore_3 
     30: iconst_0 
     31: istore  4 
     33: iload   4 
     35: iload_3 
     36: if_icmpge  77 
     39: aload_2 
     40: iload   4 
     42: aaload 
     43: astore  5 
     45: aload   5 
     47: iconst_0 
     48: iconst_4 
     49: invokevirtual #7     // Method java/lang/String.substring:(II)Ljava/lang/String; 
     52: astore  6 
     54: aload   6 
     56: iconst_0 
     57: iconst_2 
     58: invokevirtual #7     // Method java/lang/String.substring:(II)Ljava/lang/String; 
     61: astore  6 
     63: getstatic  #8     // Field java/lang/System.out:Ljava/io/PrintStream; 
     66: aload   6 
     68: invokevirtual #9     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     71: iinc   4, 1 
     74: goto   33 
     77: return 
} 
+2

Eh bien, voici votre réponse. Alors que 'javac' ne fait pas beaucoup d'optimisation, ce genre de choses mineures n'a aucun effet sur le bytecode résultant. En outre, vous pouvez vous concentrer sur les goulots d'étranglement des performances réelles. Ce ne serait pas un, même si la variable temp affectait le bytecode. – Kayaman

+0

Le bytecode varie légèrement, donc je n'étais pas sûr si cela a eu un impact, ou si mon hypothèse était bonne (j'aurais pu écrire mon exemple d'une manière qui ne fait pas de différence) – Parker

+1

Ça ne fait pas de différence . –

Répondre

1

Dans votre exemple, vous travaillez avec des chaînes, qui sont immuables. Dans votre code:

str.substring(0,4).substring(0,2) 

Le premier appel à la sous-chaîne doit générer un nouvel objet String car str ne peut pas être modifié. De même, le deuxième appel à la sous-chaîne sur ce nouvel objet String créera un autre nouvel objet String.

La différence entre les bytecodes est simplement le résultat de l'ordre dans lequel le compilateur appelle les méthodes. Dans le cas TestTmp, toute la manipulation de chaîne se produit avant l'appel à PrintStream. Pour TestNoTmp, les appels de chaîne se produisent dans l'appel PrintStream, ce qui est très logique lorsque vous regardez le code.

Pour répondre à votre question, cela ne fera aucune différence en termes d'allocation d'objets et donc d'impact GC.