java代码优化前后性能对比测试

  1. 云栖社区>
  2. 博客>
  3. 正文

java代码优化前后性能对比测试

技术小胖子 2017-11-04 01:06:00 浏览423
展开阅读全文

下面的代码是我用来比较代码优化前后的性能

 


  1. import java.util.ArrayList;  
  2. import java.util.Date;  
  3. import java.util.HashMap;  
  4. import java.util.Iterator;  
  5. import java.util.Map;  
  6. import java.util.Set;  
  7. import java.util.StringTokenizer;  
  8.  
  9. public class Test {  
  10.  
  11.     public static void main(String argv[]) {  
  12.  
  13.         /*  
  14.          * 避免在循环条件中使用复杂表达式  
  15.          * @author yifangyou  
  16.          * @since 2011-08-16 09:35:00  
  17.          *   
  18.          */ 
  19. //      test0();  
  20.         /*  
  21.          * 如果只是查找单个字符的话,用charAt()代替startsWith()  
  22.          * @author yifangyou  
  23.      * @since 2011-08-16 09:35:00  
  24.          */ 
  25. //      test1();  
  26.  
  27.  
  28.         /*  
  29.          * 能够使用移位的乘除,最好用移位  
  30.          * @author yifangyou  
  31.      * @since 2011-08-16 09:35:00  
  32.          */ 
  33. //       test2();  
  34.  
  35.         /*  
  36.          * 只有一个字符的字符串拼接,用''代替""  
  37.          * @author yifangyou  
  38.      * @since 2011-08-16 09:35:00  
  39.          */ 
  40. //       test3();  
  41.  
  42.         /**  
  43.          * try catch最好不要放在循环里  
  44.          * @author yifangyou  
  45.      * @since 2011-08-16 09:35:00  
  46.          */ 
  47. //       test4();  
  48.  
  49.         /**  
  50.          * switch的实现 map比较稳定,if最慢,switch在数量少于10个时最快,随着数量增加下降厉害  
  51.          * @author yifangyou  
  52.      * @since 2011-08-16 09:35:00  
  53.          */ 
  54. //      test5();  
  55.  
  56.         /*  
  57.          * 对于常量字符串,用'String' 代替 'StringBuffer' ,节省空间,节省时间  
  58.          * @author yifangyou  
  59.      * @since 2011-08-16 09:35:00  
  60.          */ 
  61. //      test6();  
  62.         /*  
  63.          * 用'StringTokenizer' 代替 'indexOf()' 和'substring()'  
  64.          * 字符串的分析在很多应用中都是常见的。使用indexOf  
  65.          * ()和substring()来分析字符串容易导致StringIndexOutOfBoundsException。  
  66.          * 而使用StringTokenizer类来分析字符串则会容易一些,效率也会低一些。  
  67.          * @author yifangyou  
  68.      * @since 2011-08-16 09:35:00  
  69.          */ 
  70. //       test7();  
  71.  
  72.         /*  
  73.          * 不要在循环体中实例化变量 在循环体中实例化临时变量将会增加内存消耗  
  74.          * @author yifangyou  
  75.      * @since 2011-08-16 09:35:00  
  76.          */ 
  77. //       test8();  
  78.         /*  
  79.          * 确定 StringBuffer的容量  
  80.          * StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小  
  81.          * ,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建  
  82.          * StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。  
  83.          * @author yifangyou  
  84.      * @since 2011-08-16 09:35:00  
  85.          */ 
  86. //       test9();  
  87.         /*  
  88.          * 尽可能的使用栈变量  
  89.          *   
  90.          * 如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static?  
  91.          * local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。  
  92.          * @author yifangyou  
  93.      * @since 2011-08-16 09:35:00  
  94.          */ 
  95. //      test10();  
  96.         /**  
  97.          * 复制数组最好用System.arraycopy 逐个复制,最慢;批量复制,最快  
  98.          * @author yifangyou  
  99.      * @since 2011-08-16 09:35:00  
  100.          */ 
  101.           
  102. //      copyArray();  
  103.         /*  
  104.          * 复制ArrayList数组最好用addAll addAll,最快;clone,次之,逐个最慢  
  105.          * @author yifangyou  
  106.      * @since 2011-08-16 09:35:00  
  107.          */ 
  108. //      copyArrayList();  
  109.         /*  
  110.          * 复制Map最好用逐个复制最快,putAll最简单  
  111.          * @author yifangyou  
  112.      * @since 2011-08-16 09:35:00  
  113.          */ 
  114.         copyMap();  
  115.  
  116.       
  117.     }  
  118.  
  119.     int localN = 0;  
  120.     static int staticN = 0;  
  121.  
  122.     /*  
  123.      * 避免在循环条件中使用复杂表达式  
  124.      * @author yifangyou  
  125.      * @since 2011-08-16 09:35:00  
  126.      */ 
  127.     public static void test0() {  
  128.         ArrayList<Integer> a = new ArrayList<Integer>();  
  129.  
  130.         for (int i = 0; i < 10000000; i++) {  
  131.             a.add(i);  
  132.         }  
  133.  
  134.         long startTime;  
  135.         // 循环条件中使用复杂表达式  
  136.         startTime = new Date().getTime();  
  137.         for (int i = 0; i < a.size(); i++) {  
  138.             int j = a.get(i);  
  139.         }  
  140.         System.out.println(new Date().getTime() - startTime);  
  141.  
  142.         // 循环条件中不使用复杂表达式  
  143.         startTime = new Date().getTime();  
  144.         for (int i = 0, maxlen = a.size(); i < maxlen; i++) {  
  145.             int j = a.get(i);  
  146.         }  
  147.         System.out.println(new Date().getTime() - startTime);  
  148.     }  
  149.  
  150.     /*  
  151.      * 如果只是查找单个字符的话,用charAt()代替startsWith()  
  152.      * @author yifangyou  
  153.      * @since 2011-08-16 09:35:00  
  154.      */ 
  155.     public static void test1() {  
  156.         String s = "sdfsdfsdfsdfdssssssssssssssssssssssssssssdfffffffffffffffa";  
  157.         long startTime;  
  158.         // startsWith  
  159.         startTime = new Date().getTime();  
  160.         for (int i = 0; i < 10000000; i++) {  
  161.             if (s.startsWith("a")) {  
  162.  
  163.             }  
  164.         }  
  165.         System.out.println(new Date().getTime() - startTime);  
  166.         // charAt  
  167.         startTime = new Date().getTime();  
  168.         for (int i = 0; i < 10000000; i++) {  
  169.             if (s.charAt(0) == 'a') {  
  170.  
  171.             }  
  172.         }  
  173.         System.out.println(new Date().getTime() - startTime);  
  174.           
  175.         // charAt  
  176.         startTime = new Date().getTime();  
  177.         for (int i = 0; i < 10000000; i++) {  
  178.             if ("ab".equals("abcdssdds".substring(02))) {  
  179.  
  180.             }  
  181.         }  
  182.         System.out.println(new Date().getTime() - startTime);  
  183.  
  184.     }  
  185.  
  186.     /*  
  187.      * 能够使用移位的乘除,最好用移位  
  188.      * @author yifangyou  
  189.      * @since 2011-08-16 09:35:00  
  190.      */ 
  191.     public static void test2() {  
  192.         long startTime;  
  193.         int a;  
  194.         //  
  195.         startTime = new Date().getTime();  
  196.  
  197.         for (int i = 0; i < 10000000; i++) {  
  198.             a = 333333333 / 8;  
  199.         }  
  200.         System.out.println(new Date().getTime() - startTime);  
  201.         // charAt  
  202.         startTime = new Date().getTime();  
  203.         for (int i = 0; i < 10000000; i++) {  
  204.             a = 333333333 >> 3;  
  205.         }  
  206.         System.out.println(new Date().getTime() - startTime);  
  207.     }  
  208.  
  209.     /*  
  210.      * 只有一个字符的字符串拼接,用''代替""  
  211.      * @author yifangyou  
  212.      * @since 2011-08-16 09:35:00  
  213.      */ 
  214.     public static void test3() {  
  215.         long startTime;  
  216.  
  217.         startTime = new Date().getTime();  
  218.         String s = "123";  
  219.         for (int i = 0; i < 10000000; i++) {  
  220.             String a = s + "d";  
  221.         }  
  222.         System.out.println(new Date().getTime() - startTime);  
  223.         // charAt  
  224.         startTime = new Date().getTime();  
  225.         for (int i = 0; i < 10000000; i++) {  
  226.             String a = s + 'd';  
  227.         }  
  228.         System.out.println(new Date().getTime() - startTime);  
  229.     }  
  230.  
  231.     /**  
  232.      * try catch最好不要放在循环里  
  233.      * @author yifangyou  
  234.      * @since 2011-08-16 09:35:00  
  235.      */ 
  236.     public static void test4() {  
  237.         long startTime;  
  238.         startTime = new Date().getTime();  
  239.         for (int i = 0; i < 10000000; i++) {  
  240.             try {  
  241.                 int a = Integer.parseInt("1");  
  242.             } catch (Exception e) {  
  243.  
  244.             }  
  245.         }  
  246.         System.out.println(new Date().getTime() - startTime);  
  247.  
  248.         startTime = new Date().getTime();  
  249.         try {  
  250.             for (int i = 0; i < 10000000; i++) {  
  251.                 int a = Integer.parseInt("1");  
  252.             }  
  253.         } catch (Exception e) {  
  254.  
  255.         }  
  256.  
  257.         System.out.println(new Date().getTime() - startTime);  
  258.  
  259.     }  
  260.  
  261.     /**  
  262.      * switch的实现 map比较稳定,if最慢,switch在数量少于10个时最快,随着数量增加下降厉害,在switch最好把出现次数最多的判断放在最前面  
  263.      * @author yifangyou  
  264.      * @since 2011-08-16 09:35:00  
  265.      */ 
  266.     public static void test5() {  
  267.         HashMap<String, Integer> types = new HashMap<String, Integer>() {  
  268.             {  
  269.                 int i = 0;  
  270.                 this.put("a", i++);  
  271.                 this.put("b", i++);  
  272.                 this.put("c", i++);  
  273.                 this.put("d", i++);  
  274.                 this.put("e", i++);  
  275.             }  
  276.         };  
  277.         String a = "e";  
  278.         int b = 0;  
  279.         long startTime;  
  280.         startTime = new Date().getTime();  
  281.         for (int i = 0; i < 10000000; i++) {  
  282.             if ("a".equals(a)) {  
  283.                 b = 0;  
  284.             } else if ("b".equals(a)) {  
  285.                 b = 1;  
  286.             } else if ("c".equals(a)) {  
  287.                 b = 2;  
  288.             } else if ("d".equals(a)) {  
  289.                 b = 3;  
  290.             } else if ("e".equals(a)) {  
  291.                 b = 4;  
  292.             }  
  293.         }  
  294.         System.out.println(new Date().getTime() - startTime);  
  295.  
  296.         startTime = new Date().getTime();  
  297.         for (int i = 0; i < 10000000; i++) {  
  298.             b = types.get(a);  
  299.         }  
  300.         System.out.println(new Date().getTime() - startTime);  
  301.         int c = 14;//改为0的话则最快  
  302.         startTime = new Date().getTime();  
  303.         for (int i = 0; i < 10000000; i++) {  
  304.             switch (c) {  
  305.             case 0:  
  306.                 break;  
  307.             case 1:  
  308.                 break;  
  309.             case 2:  
  310.                 break;  
  311.             case 3:  
  312.                 break;  
  313.             case 4:  
  314.                 break;  
  315.             case 5:  
  316.                 break;  
  317.             case 6:  
  318.                 break;  
  319.             case 7:  
  320.                 break;  
  321.             case 8:  
  322.                 break;  
  323.             case 9:  
  324.                 break;  
  325.             case 10:  
  326.                 break;  
  327.             case 11:  
  328.                 break;  
  329.             case 12:  
  330.                 break;  
  331.             case 13:  
  332.                 break;  
  333.             case 14:  
  334.                 break;  
  335.             default:  
  336.                 break;  
  337.             }  
  338.         }  
  339.  
  340.         System.out.println(new Date().getTime() - startTime);  
  341.     }  
  342.  
  343.     /*  
  344.      * 对于常量字符串,用'String' 代替 'StringBuffer' ,节省空间,节省一半时间  
  345.      * @author yifangyou  
  346.      * @since 2011-08-16 09:35:00  
  347.      */ 
  348.     public static void test6() {  
  349.         StringBuffer s = new StringBuffer("Hello");  
  350.         int maxlen=1000000;  
  351.         long startTime;  
  352.         startTime = new Date().getTime();  
  353.         for (int i = 0; i < maxlen; i++) {  
  354.             String t =new String("Hello ") + "World!";  
  355.         }  
  356.         System.out.println(new Date().getTime() - startTime);  
  357.           
  358.         startTime = new Date().getTime();  
  359.         for (int i = 0; i < maxlen; i++) {  
  360.             StringBuffer t =new StringBuffer("Hello ").append("World!");  
  361.         }  
  362.         System.out.println(new Date().getTime() - startTime);  
  363.     }  
  364.  
  365.     /*  
  366.      * 用'StringTokenizer' 代替 'indexOf()' 和'substring()'  
  367.      * 字符串的分析在很多应用中都是常见的。使用indexOf  
  368.      * ()和substring()来分析字符串容易导致StringIndexOutOfBoundsException。  
  369.      * 而使用StringTokenizer类来分析字符串则会容易一些,效率也会低一些。  
  370.      * @author yifangyou  
  371.      * @since 2011-08-16 09:35:00  
  372.      */ 
  373.     public static void test7() {  
  374.         String domain = "www.a.com.";  
  375.         long startTime;  
  376.         startTime = new Date().getTime();  
  377.  
  378.         for (int i = 0; i < 100000; i++) {  
  379.             int index = 0;  
  380.             while ((index = domain.indexOf(".", index + 1)) != -1) {  
  381.                 domain.substring(index + 1, domain.length());  
  382.                 // System.out.println(domain.substring(index+1,  
  383.                 // domain.length()));  
  384.             }  
  385.         }  
  386.         System.out.println(new Date().getTime() - startTime);  
  387.         startTime = new Date().getTime();  
  388.         for (int i = 0; i < 100000; i++) {  
  389.             StringTokenizer st = new StringTokenizer(domain, ".");  
  390.             while (st.hasMoreTokens()) {  
  391.                 st.nextToken();  
  392.                 // System.out.println(st.nextToken());  
  393.             }  
  394.         }  
  395.         System.out.println(new Date().getTime() - startTime);  
  396.     }  
  397.  
  398.     /*  
  399.      * 不要在循环体中实例化变量 在循环体中实例化临时变量将会增加内存消耗  
  400.      * @author yifangyou  
  401.      * @since 2011-08-16 09:35:00  
  402.      */ 
  403.     public static void test8() {  
  404.         ArrayList<Integer> a = new ArrayList<Integer>();  
  405.         int maxlen = 10000000;  
  406.         for (int i = 0; i < maxlen; i++) {  
  407.             a.add(i);  
  408.         }  
  409.         long startTime;  
  410.         startTime = new Date().getTime();  
  411.         for (int i = 0; i < maxlen; i++) {  
  412.             Object o = new Object();  
  413.             o = a.get(i);  
  414.         }  
  415.         System.out.println(new Date().getTime() - startTime);  
  416.         Object o = new Object();  
  417.         startTime = new Date().getTime();  
  418.         for (int i = 0; i < maxlen; i++) {  
  419.             o = a.get(i);  
  420.         }  
  421.         System.out.println(new Date().getTime() - startTime);  
  422.     }  
  423.  
  424.     /*  
  425.      * 确定 StringBuffer的容量  
  426.      * StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存  
  427.      * ,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建  
  428.      * StringBuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。  
  429.      * @author yifangyou  
  430.      * @since 2011-08-16 09:35:00  
  431.      */ 
  432.     public static void test9() {  
  433.         int maxlen = 1000000;  
  434.         long startTime;  
  435.         startTime = new Date().getTime();  
  436.         for (int i = 0; i < maxlen; i++) {  
  437.             StringBuffer buffer = new StringBuffer(); // violation  
  438.             buffer.append("hellosdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");  
  439.         }  
  440.         System.out.println(new Date().getTime() - startTime);  
  441.         startTime = new Date().getTime();  
  442.         for (int i = 0; i < maxlen; i++) {  
  443.             StringBuffer buffer = new StringBuffer(128); // violation  
  444.             buffer.append("hellosdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");  
  445.         }  
  446.         System.out.println(new Date().getTime() - startTime);  
  447.     }  
  448.  
  449.     /*  
  450.      * 尽可能的使用栈变量 如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static?  
  451.      * local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。  
  452.      * @author yifangyou  
  453.      * @since 2011-08-16 09:35:00  
  454.      */ 
  455.     public static void test10() {  
  456.         int maxlen = 100000000;  
  457.         long startTime;  
  458.         int n = 0;  
  459.         Test test = new Test();  
  460.         // 局部变量  
  461.         startTime = new Date().getTime();  
  462.         for (int i = 0; i < maxlen; i++) {  
  463.             n = i;  
  464.         }  
  465.         System.out.println(new Date().getTime() - startTime);  
  466.         // 类变量  
  467.         startTime = new Date().getTime();  
  468.         for (int i = 0; i < maxlen; i++) {  
  469.             test.localN = i;  
  470.         }  
  471.         System.out.println(new Date().getTime() - startTime);  
  472.  
  473.         // 静态变量  
  474.         startTime = new Date().getTime();  
  475.         for (int i = 0; i < maxlen; i++) {  
  476.             Test.staticN = i;  
  477.         }  
  478.         System.out.println(new Date().getTime() - startTime);  
  479.     }  
  480. //    
  481. //  /*1.尽量使用final修饰符。  
  482. //带有final修饰符的类是不可派生的。在JAVA核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了使用者覆盖length()方法。另外,如果一个类是final的,则该类所有方法都是final的。java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。  
  483. //   */  
  484. //  public static void test11() {  
  485. //      int maxlen = 10000000;  
  486. //      long startTime;  
  487. //      int n = 0;  
  488. //        
  489. //      // 普通类  
  490. //      startTime = new Date().getTime();  
  491. //      A a = new A();  
  492. //      for (int i = 0; i < maxlen; i++) {  
  493. //          a.inc();  
  494. //      }  
  495. //      System.out.println(new Date().getTime() - startTime);  
  496. //        
  497. //      // final类  
  498. //      startTime = new Date().getTime();  
  499. //      FinalA finalA = new FinalA();  
  500. //      for (int i = 0; i < maxlen; i++) {  
  501. //          finalA.inc();  
  502. //      }  
  503. //      System.out.println(new Date().getTime() - startTime);  
  504. //  }  
  505.  
  506.     /**  
  507.      * 复制数组最好用System.arraycopy 逐个复制,最慢;批量复制,最快  
  508.      * @author yifangyou  
  509.      * @since 2011-08-16 09:35:00  
  510.      */ 
  511.     static void copyArray() {  
  512.         int[] array1 = new int[10000000];  
  513.         int[] array2 = new int[10000000];  
  514.         for (int i = 0, maxlen = array1.length; i < maxlen; i++) {  
  515.             array1[i] = i;  
  516.         }  
  517.  
  518.         long startTime;  
  519.         // 逐个复制,最慢  
  520.         startTime = new Date().getTime();  
  521.  
  522.         for (int i = 0, maxlen = array2.length; i < maxlen; i++) {  
  523.             array2[i] = array1[i]; // Violation  
  524.         }  
  525.         System.out.println(new Date().getTime() - startTime);  
  526.  
  527.         // 批量复制,最快  
  528.         startTime = new Date().getTime();  
  529.         System.arraycopy(array1, 0, array2, 010000);  
  530.         System.out.println(new Date().getTime() - startTime);  
  531.  
  532.     }  
  533.  
  534.     /*  
  535.      * 复制ArrayList数组最好用addAll addAll,最快;clone,次之,逐个最慢  
  536.      * @author yifangyou  
  537.      * @since 2011-08-16 09:35:00  
  538.      */ 
  539.     static void copyArrayList() {  
  540.         int maxlen = 1000000;  
  541.         ArrayList<Integer> array1 = new ArrayList<Integer>();  
  542.         ArrayList<Integer> array2 = new ArrayList<Integer>();  
  543.         ArrayList<Integer> array3 = new ArrayList<Integer>();  
  544.         ArrayList<Integer> array4;  
  545.         for (int i = 0; i < maxlen; i++) {  
  546.             array1.add(i);  
  547.         }  
  548.  
  549.         long startTime;  
  550.         // 逐个复制,最慢  
  551.         startTime = new Date().getTime();  
  552.  
  553.         for (int i = 0; i < maxlen; i++) {  
  554.             array2.add(array1.get(i)); // Violation  
  555.         }  
  556.         System.out.println(new Date().getTime() - startTime);  
  557.  
  558.         // 批量复制,最快  
  559.         startTime = new Date().getTime();  
  560.         array3.addAll(array1);  
  561.         System.out.println(new Date().getTime() - startTime);  
  562.  
  563.         // 克隆,次快  
  564.         startTime = new Date().getTime();  
  565.         array4 = (ArrayList<Integer>) array1.clone();  
  566.         System.out.println(new Date().getTime() - startTime);  
  567.         array4.set(04);  
  568.         System.out.println("array1[0]=" + array1.get(0));  
  569.         System.out.println("array4[0]=" + array4.get(0));  
  570.  
  571.     }  
  572.  
  573.     /*  
  574.      * 复制Map最好用逐个复制最快,putAll最简单  
  575.      * @author yifangyou  
  576.      * @since 2011-08-16 09:35:00  
  577.      */ 
  578.     static void copyMap() {  
  579.         int maxlen = 1000000;  
  580.         Map<Integer, Integer> map1 = new HashMap<Integer, Integer>();  
  581.         Map<Integer, Integer> map2 = new HashMap<Integer, Integer>();  
  582.         Map<Integer, Integer> map3 = new HashMap<Integer, Integer>();  
  583.         Map<Integer, Integer> map4 = new HashMap<Integer, Integer>();  
  584.         for (int i = 0; i < maxlen; i++) {  
  585.             map1.put(i, i);  
  586.         }  
  587.  
  588.         long startTime;  
  589.         // 逐个复制,最快  
  590.         startTime = new Date().getTime();  
  591.         Set<Integer> key = map1.keySet();  
  592.         for (Iterator it = key.iterator(); it.hasNext();) {  
  593.             Integer k = (Integer) it.next();  
  594.             map2.put(k, map1.get(k));  
  595.         }  
  596.         System.out.println(new Date().getTime() - startTime);  
  597.  
  598.         // 批量复制,最慢  
  599.         startTime = new Date().getTime();  
  600.         map3.putAll(map1);  
  601.         System.out.println(new Date().getTime() - startTime);  
  602.         System.out.println("map2[9999]=" + map2.get(9999));  
  603.         System.out.println("map3[9999]=" + map3.get(9999));  
  604.  
  605.         // 逐个复制,次快  
  606.         startTime = new Date().getTime();  
  607.         Set<Map.Entry<Integer, Integer>> set = map1.entrySet();  
  608.         for (Iterator<Map.Entry<Integer, Integer>> it = set.iterator(); it  
  609.                 .hasNext();) {  
  610.             Map.Entry<Integer, Integer> entry = (Map.Entry<Integer, Integer>) it  
  611.                     .next();  
  612.             map4.put(entry.getKey(), entry.getValue());  
  613.         }  
  614.         System.out.println(new Date().getTime() - startTime);  
  615.  
  616.     }  
  617.  
  618. }  

      本文转自yifangyou 51CTO博客,原文链接:http://blog.51cto.com/yifangyou/641251,如需转载请自行联系原作者



网友评论

登录后评论
0/500
评论
技术小胖子
+ 关注