說說java反射機制之Method invoke執行調用方法例子

  java反射機制之Method invoke執行調用方法例子php

  昨天在羣裏跟你們討論了下java反射調用可變參數的問題,這個問題原由是咱們須要反射調用另外一個部門提供的方法,我同事說java不能反射調用可變參數的方法,因而我寫了個demo證實了他這個觀點的錯誤。可是測試過程當中,有一點我不明白,就是反射調用可變參數的方法時,爲何必定要保證傳入的參數數組長度爲1,在羣裏跟你們討論了不少,沒有獲得確切的答案,參照網上大牛寫的東西和我本身跟源碼的過程,記錄以下:html

  1.兩個類,一個父類,一個子類java

  [java] view plain copy print?數組

  package com.reflect.test;緩存

  public class BaseObject {ide

  public void getObjectName(){函數

  System.out.println("BaseObject");性能

  }測試

  }優化

  [java] view plain copy print?

  package com.reflect.test;

  public class SubObject extends BaseObject{

  @Override

  public void getObjectName() {

  System.out.println("SubObject");

  }

  public void getParamsLength(String...params){

  System.out.println("param's length is:"+params.length);

  }

  public void getParamsLength(String param1,String param2){

  System.out.println(param1 + "-" + param2);

  }

  }

  2.測試類,主要測試重載方法的調用、可變參數方法的調用、定參方法的調用

  [java] view plain copy print?

  package com.reflect.test;

  import java.lang.reflect.Method;

  public class ReflectTest {

  private static final String BASE_OBJECT_PATH = "com.reflect.test.BaseObject";

  private static final String SUB_OBJECT_PATH = "com.reflect.test.SubObject";

  public static void main(String[] args) throws Exception{

  Class bClazz = Class.forName(BASE_OBJECT_PATH);

  Class sClazz = Class.forName(SUB_OBJECT_PATH);

  Object bObj = bClazz.newInstance();//父類實例

  Object sObj = sClazz.newInstance();//子類實例

  //1.反射調用子類父類的重載方法

  //多態+動態綁定

  Method bMethod = bClazz.getDeclaredMethod("getObjectName");

  bMethod.invoke(bObj);//父類的bMethod調用父類的getObjectName()

  bMethod.invoke(sObj);//父類的bMethod調用子類的getObjectName();

  Method sMethod = sClazz.getDeclaredMethod("getObjectName");

  //不符合多態和動態綁定

  //sMethod.invoke(bObj);//sMethod調用父類的getObjectName(),會報錯:java.lang.IllegalArgumentException: object is not an instance of declaring class

  sMethod.invoke(sObj);

  //2.反射調用可變參數的方法

  Method changeMethod = sClazz.getDeclaredMethod("getParamsLength", String[].class);

  //可變參數必須這樣封裝,由於java反射內部實現作了參數個數爲1的判斷,若是參數長度不爲1,則會拋出異常

  String[] strParams = {"a","b","c"};

  Object[] cParams = {strParams};

  changeMethod.invoke(sObj, cParams);

  //3.反射調用固定長度參數的方法

  Method unChangeMethod1 = sClazz.getDeclaredMethod("getParamsLength", String.class,String.class);

  unChangeMethod1.invoke(sObj, "Hello","Java");

  //也能夠寫成這樣

  Class[] clazzs = {String.class,String.class};

  Method unChangeMethod2 = sClazz.getDeclaredMethod("getParamsLength", clazzs);

  unChangeMethod2.invoke(sObj, "Hello","Java");

  //下面的這種調用形式也是能夠的,不過會報警告

  //String[] params1 = {"Hello","Java"};

  //unChangeMethod1.invoke(sObj, params1);

  }

  }

  下面是JDK裏面Method 的invoke方法的源碼

  從代碼中能夠看出,先檢查 AccessibleObject的override屬性是否爲true(override屬性默認爲false)。AccessibleObject是Method,Field,Constructor的父類,可調用setAccessible方法改變,若是設置爲true,則表示能夠忽略訪問權限的限制,直接調用。

  若是不是ture,則要進行訪問權限檢測。用Reflection的quickCheckMemberAccess方法先檢查是否是public的,若是不是再用Reflection.getCallerClass()方法得到到調用這個方法的Class,而後作是否有權限訪問的校驗,校驗以後緩存一次,以便下次若是仍是這個類來調用就不用去作校驗了,直接用上次的結果。

  [java] view plain copy print?

  @CallerSensitive

  public Object invoke(Object obj, Object... args)

  throws IllegalAccessException, IllegalArgumentException,

  InvocationTargetException

  {

  if (!override) {

  if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {

  // Until there is hotspot @CallerSensitive support

  // can't call Reflection.getCallerClass() here

  // Workaround for now: add a frame getCallerClass to

  // make the caller at stack depth 2

  Class caller = getCallerClass();

  checkAccess(caller, clazz, obj, modifiers);

  }

  }

  MethodAccessor ma = methodAccessor; // read volatile

  if (ma == null) {

  ma = acquireMethodAccessor();

  }

  return ma.invoke(obj, args);

  }

  /驗證的代碼,securityCheckCache就是JDK作的緩存

  volatile Object securityCheckCache;

  void checkAccess(Class caller, Class clazz, Object obj, int modifiers)

  throws IllegalAccessException

  {

  if (caller == clazz) { // quick check

  return; // ACCESS IS OK

  }

  Object cache = securityCheckCache; // read volatile

  Class targetClass = clazz;

  if (obj != null

  && Modifier.isProtected(modifiers)

  && ((targetClass = obj.getClass()) != clazz)) {

  // Must match a 2-list of { caller, targetClass }.

  if (cache instanceof Class[]) {

  Class[] cache2 = (Class[]) cache;

  if (cache2[1] == targetClass &&

  cache2[0] == caller) {

  return; // ACCESS IS OK

  }

  // (Test cache[1] first since range check for [1]

  // subsumes range check for [0].)

  }

  } else if (cache == caller) {

  // Non-protected case (or obj.class == this.clazz).

  return; // ACCESS IS OK

  }

  // If no return, fall through to the slow path.

  slowCheckMemberAccess(caller, clazz, obj, modifiers, targetClass);

  }

  而後就是調用MethodAccessor的invoke方法了。

  調用MethodAccessor的invoke方法。每一個Method對象包含一個root對象,root對象裏持有一個MethodAccessor對象。這個對象由ReflectionFactory方法生成,ReflectionFactory對象在Method類中是static final的由native方法實例化。代碼片斷以下;

  [java] view plain copy print?

  //Method類中的代碼片斷,生成MethodAccessor

  private volatile MethodAccessor methodAccessor;

  private Method root;

  private MethodAccessor acquireMethodAccessor() {

  // First check to see if one has been created yet, and take it

  // if so

  MethodAccessor tmp = null;

  if (root != null) tmp = root.getMethodAccessor();

  if (tmp != null) {

  methodAccessor = tmp;

  } else {

  // Otherwise fabricate one and propagate it up to the root

  tmp = reflectionFactory.newMethodAccessor(this);

  setMethodAccessor(tmp);

  }

  return tmp;

  }

  // reflectionFactory在父類AccessibleObject中定義,代碼片斷以下:

  static final ReflectionFactory reflectionFactory =

  AccessController.doPrivileged(

  new sun.reflect.ReflectionFactory.GetReflectionFactoryAction());

  ReflectionFactory生成MethodAccessor:若是noInflation的屬性爲true則直接返回MethodAccessorGenerator建立的一個MethodAccessor,不然返回DelegatingMethodAccessorImpl,並將他與一個NativeMethodAccessorImpl互相引用。但DelegatingMethodAccessorImpl執行invoke方法的時候又委託給NativeMethodAccessorImpl了。代碼片斷以下:

  [java] view plain copy print?

  public MethodAccessor newMethodAccessor(Method paramMethod) {

  checkInitted();

  if (noInflation) {

  return new MethodAccessorGenerator().generateMethod(paramMethod.getDeclaringClass(), paramMethod.getName(), paramMethod.getParameterTypes(), paramMethod.getReturnType(), paramMethod.getExceptionTypes(), paramMethod.getModifiers());

  }

  NativeMethodAccessorImpl localNativeMethodAccessorImpl = new NativeMethodAccessorImpl(paramMethod);

  DelegatingMethodAccessorImpl localDelegatingMethodAccessorImpl = new DelegatingMethodAccessorImpl(localNativeMethodAccessorImpl);

  localNativeMethodAccessorImpl.setParent(localDelegatingMethodAccessorImpl);

  return localDelegatingMethodAccessorImpl;

  }

  MethodAccessor實現有兩個版本,一個是Java實現的,另外一個是native code實現的。Java實現的版本在初始化時須要較多時間,但長久來講性能較好;native版本正好相反,啓動時相對較快,但運行時間長了以後速度就比不過Java版了。這是HotSpot的優化方式帶來的性能特性,同時也是許多虛擬機的共同點:跨越native邊界會對優化有阻礙做用,它就像個黑箱同樣讓虛擬機難以分析也將其內聯,因而運行時間長了以後反而是託管版本的代碼更快些。 爲了權衡兩個版本的性能,Sun的JDK使用了「inflation」的技巧:讓Java方法在被反射調用時,開頭若干次使用native版,等反射調用次數超過閾值時則生成一個專用的MethodAccessor實現類,生成其中的invoke()方法的字節碼,之後對該Java方法的反射調用就會使用Java版。

  看下NativeMethodAccessorImpl 中的invoke方法:

  代碼片斷以下:

  [java] view plain copy print?

  package sun.reflect;

  import java.lang.reflect.InvocationTargetException;

  import java.lang.reflect.Method;

  class NativeMethodAccessorImpl extends MethodAccessorImpl

  {

  private Method method;

  private DelegatingMethodAccessorImpl parent;

  private int numInvocations;

  NativeMethodAccessorImpl(Method paramMethod)

  {

  this.method = paramMethod;

  }

  public Object invoke(Object paramObject, Object[] paramArrayOfObject)

  throws IllegalArgumentException, InvocationTargetException

  {

  if (++this.numInvocations > ReflectionFactory.inflationThreshold()) {

  MethodAccessorImpl localMethodAccessorImpl = (MethodAccessorImpl)new MethodAccessorGenerator().generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());

  this.parent.setDelegate(localMethodAccessorImpl);

  }

  return invoke0(this.method, paramObject, paramArrayOfObject);

  }

  void setParent(DelegatingMethodAccessorImpl paramDelegatingMethodAccessorImpl) {

  this.parent = paramDelegatingMethodAccessorImpl;

  }

  private static native Object invoke0(Method paramMethod, Object paramObject, Object[] paramArrayOfObject);

  }

  調用natiave方法invoke0執行方法調用.

  注意這裏有一個計數器numInvocations,每調用一次方法+1,當比 ReflectionFactory.inflationThreshold(15)大的時候,用MethodAccessorGenerator建立一個MethodAccessor,並把以前的DelegatingMethodAccessorImpl引用替換爲如今新建立的。下一次DelegatingMethodAccessorImpl就不會再交給NativeMethodAccessorImpl執行了,而是交給新生成的java字節碼的MethodAccessor

  每次NativeMethodAccessorImpl.invoke()方法被調用時,都會增長一個調用次數計數器,看超過閾值沒有;一旦超過,則調用MethodAccessorGenerator.generateMethod()來生成Java版的MethodAccessor的實現類,而且改變DelegatingMethodAccessorImpl所引用的MethodAccessor爲Java版。後續經由DelegatingMethodAccessorImpl.invoke()調用到的就是Java版的實現了。

  注意到關鍵的invoke0()方法是個native方法。它在HotSpot VM裏是由JVM_InvokeMethod()函數所支持的,是用C寫的

  爲了驗證這個結論,我故意寫出一個非法參數,循環調用16次並catch下異常,結果以下:從結果中看出,前15次都是調用NativeMethodAccessorImpl,第16次開始就是調用DelegatingMethodAccessorImpl了。

  [java] view plain copy print?

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException: wrong number of arguments

  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  java.lang.IllegalArgumentException

  at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)

  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

  at java.lang.reflect.Method.invoke(Method.java:606)

  at com.reflect.test.ReflectTest.main(ReflectTest.java:44)

  下面看看java版的DelegatingMethodAccessorImpl的實現:

  [java] view plain copy print?

  package sun.reflect;

  import java.lang.reflect.InvocationTargetException;

  class DelegatingMethodAccessorImpl extends MethodAccessorImpl

  {

  private MethodAccessorImpl delegate;

  DelegatingMethodAccessorImpl(MethodAccessorImpl paramMethodAccessorImpl)

  {

  setDelegate(paramMethodAccessorImpl);

  }

  public Object invoke(Object paramObject, Object[] paramArrayOfObject)

  throws IllegalArgumentException, InvocationTargetException

  {

  return this.delegate.invoke(paramObject, paramArrayOfObject);

  }

  void setDelegate(MethodAccessorImpl paramMethodAccessorImpl) {

  this.delegate = paramMethodAccessorImpl;

  }

  package sun.reflect;

  public class GeneratedMethodAccessor1 extends MethodAccessorImpl {

  public GeneratedMethodAccessor1() {

  super();

  }

  public Object invoke(Object obj, Object[] args)

  throws IllegalArgumentException, InvocationTargetException {

  // prepare the target and parameters

  if (obj == null) throw new NullPointerException();

  try {

  A target = (A) obj;

  if (args.length != 1) throw new IllegalArgumentException();

  String arg0 = (String) args[0];

  } catch (ClassCastException e) {

  throw new IllegalArgumentException(e.toString());

  } catch (NullPointerException e) {

  throw new IllegalArgumentException(e.toString());

  }

  // make the invocation

  try {

  target.foo(arg0);

  } catch (Throwable t) {

  throw new InvocationTargetException(t);

  }

  }

  }

  if (args.length != 1) throw new IllegalArgumentException();這一句就能解釋我以前的疑問了,這塊會判斷參數數組的長度,若是長度不等於1,就會拋出非法參數的異常。

  並且MethodAccessor會作強制類型轉換再進行方法調用,但父類強制轉化成子類的的時候就會報錯類型不匹配錯誤了,因此若是變量的引用聲明是父但實際指向的對象是子,那麼這種調用也是能夠的。現貨重油 娛樂及時看

  http://bj.bqqm.com/licai/z746373.htm

  http://bj.bqqm.com/licai/z746380.htm

  http://bj.bqqm.com/licai/z746385.htm

  http://blog.chinaunix.net/uid-30065054-id-5753598.html

  http://blog.chinaunix.net/uid-30065054-id-5753619.html

  http://blog.csdn.net/sinat_36394053/article/details/52857375

  http://blog.itpub.net/30065054/viewspace-2126715/

  http://blog.itpub.net/30065054/viewspace-2126747/

  http://run.gmw.cn/blog-1873077-177613.html

  http://site.leshou.com/s/33563826.html

  http://site.leshou.com/s/33563870.html

  http://site.leshou.com/s/33563896.html

  http://site.leshou.com/s/33563950.html

  http://site.leshou.com/s/33564004.html

  http://site.leshou.com/s/33564069.html

  http://site.leshou.com/s/33564112.html

  http://site.leshou.com/s/33564134.html

  http://site.leshou.com/s/33564165.html

  http://site.leshou.com/s/33564197.html

  http://www.365128.com/user/myx2/39.html

  http://www.365128.com/user/myx2/40.html

  http://www.365128.com/user/myx2/41.html

  http://www.365128.com/user/myx2/43.html

  http://www.365128.com/user/myx2/46.html

  http://www.fwol.cn/xinxishow.php?xid=4084018

  http://www.fwol.cn/xinxishow.php?xid=4084024

  http://www.fwol.cn/xinxishow.php?xid=4084028

  http://www.fwol.cn/xinxishow.php?xid=4084032

  http://www.fwol.cn/xinxishow.php?xid=4084048

  http://www.niuche.com/article/1140677.html

  http://www.togv.net/guanlipeixun/j73tzgggg9a7d5neldji.htm

  http://www.togv.net/guanlipeixun/m0e3b9999hgzdusvk43t.htm

  http://www.wangchao.net.cn/hi/detail_232429.html

  http://www.wangchao.net.cn/hi/detail_232433.html

  http://www.wangchao.net.cn/hi/detail_232437.html

  http://www.wangchao.net.cn/hi/detail_232438.html

  http://www.wangchao.net.cn/hi/detail_232441.html

  http://www.wangchao.net.cn/hi/detail_232591.html

  http://www.wangchao.net.cn/hi/detail_232592.html

  http://www.wangchao.net.cn/hi/detail_232599.html

  http://www.wangchao.net.cn/hi/detail_232606.html

  http://www.wangchao.net.cn/hi/detail_232607.html

  http://www.yl1001.com/article/3151476866647599.htm

  http://mingjia.cngold.org/expert/1304176/news/c800377.htm

  http://mingjia.cngold.org/expert/1304176/news/c800383.htm

  http://mingjia.cngold.org/expert/1304176/news/c800390.htm

  http://mingjia.cngold.org/expert/1304176/news/c800397.htm

  http://mingjia.cngold.org/expert/1304176/news/c800406.htm

  http://mingjia.cngold.org/expert/1304176/news/c800410.htm

  http://www.cnblogs.com/huqingchen/p/5979936.html

相關文章
相關標籤/搜索