java反射代碼講解,java反射代碼實(shí)現(xiàn)

Java Reflection (JAVA反射)機(jī)制詳解

反射機(jī)制:所謂的反射機(jī)制就是java語(yǔ)言在運(yùn)行時(shí)擁有一項(xiàng)自觀的能力。通過(guò)這種能力可以徹底的了解自身的情況為下一步的動(dòng)作做準(zhǔn)備。下面具體介紹一下java的反射機(jī)制。這里你將顛覆原來(lái)對(duì)java的理解。

創(chuàng)新互聯(lián)長(zhǎng)期為1000多家客戶(hù)提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為??谄髽I(yè)提供專(zhuān)業(yè)的網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì),??诰W(wǎng)站改版等技術(shù)服務(wù)。擁有10多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

Java的反射機(jī)制的實(shí)現(xiàn)要借助于4個(gè)類(lèi):class,Constructor,F(xiàn)ield,Method;其中class代表的時(shí)類(lèi)對(duì) 象,Constructor-類(lèi)的構(gòu)造器對(duì)象,F(xiàn)ield-類(lèi)的屬性對(duì)象,Method-類(lèi)的方法對(duì)象。通過(guò)這四個(gè)對(duì)象我們可以粗略的看到一個(gè)類(lèi)的各個(gè)組 成部分。

Class:程序運(yùn)行時(shí),java運(yùn)行時(shí)系統(tǒng)會(huì)對(duì)所有的對(duì)象進(jìn)行運(yùn)行時(shí)類(lèi)型的處理。這項(xiàng)信息記錄了每個(gè)對(duì)象所屬的類(lèi),虛擬機(jī)通常使用運(yùn)行時(shí)類(lèi)型信息選擇正 確的方法來(lái)執(zhí)行(摘自:白皮書(shū))。但是這些信息我們?cè)趺吹玫桨?,就要借助于class類(lèi)對(duì)象了啊。在Object類(lèi)中定義了getClass()方法。我 們可以通過(guò)這個(gè)方法獲得指定對(duì)象的類(lèi)對(duì)象。然后我們通過(guò)分析這個(gè)對(duì)象就可以得到我們要的信息了。

比如:ArrayList arrayList;

Class clazz = arrayList.getClass();

然后我來(lái)處理這個(gè)對(duì)象clazz。

當(dāng)然了Class類(lèi)具有很多的方法,這里重點(diǎn)將和Constructor,F(xiàn)ield,Method類(lèi)有關(guān)系的方法。

Reflection 是 Java 程序開(kāi)發(fā)語(yǔ)言的特征之一,它允許運(yùn)行中的 Java 程序?qū)ψ陨磉M(jìn)行檢查,或者說(shuō)“自審”,并能直接操作程序的內(nèi)部屬性。Java 的這一能力在實(shí)際應(yīng)用中也許用得不是很多,但是個(gè)人認(rèn)為要想對(duì)java有個(gè)更加深入的了解還是應(yīng)該掌握的。

1.檢測(cè)類(lèi):

reflection的工作機(jī)制

考慮下面這個(gè)簡(jiǎn)單的例子,讓我們看看 reflection 是如何工作的。

import java.lang.reflect.*;

public class DumpMethods {

public static void main(String args[]) {

try {

Class c = Class.forName(args[0]);

Method m[] = c.getDeclaredMethods();

for (int i = 0; i m.length; i++)

System.out.println(m[i].toString());

} catch (Throwable e) {

System.err.println(e);

}

}

}

按如下語(yǔ)句執(zhí)行:

java DumpMethods java.util.ArrayList

這個(gè)程序使用 Class.forName 載入指定的類(lèi),然后調(diào)用 getDeclaredMethods 來(lái)獲取這個(gè)類(lèi)中定義了的方法列表。java.lang.reflect.Methods 是用來(lái)描述某個(gè)類(lèi)中單個(gè)方法的一個(gè)類(lèi)。

Java類(lèi)反射中的主要方法

對(duì)于以下三類(lèi)組件中的任何一類(lèi)來(lái)說(shuō) -- 構(gòu)造函數(shù)、字段和方法 -- java.lang.Class 提供四種獨(dú)立的反射調(diào)用,以不同的方式來(lái)獲得信息。調(diào)用都遵循一種標(biāo)準(zhǔn)格式。以下是用于查找構(gòu)造函數(shù)的一組反射調(diào)用:

Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數(shù)類(lèi)型的公共構(gòu)造函數(shù),

Constructor[] getConstructors() -- 獲得類(lèi)的所有公共構(gòu)造函數(shù)

Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數(shù)類(lèi)型的構(gòu)造函數(shù)(與接入級(jí)別無(wú)關(guān))

Constructor[] getDeclaredConstructors() -- 獲得類(lèi)的所有構(gòu)造函數(shù)(與接入級(jí)別無(wú)關(guān))

獲得字段信息的Class 反射調(diào)用不同于那些用于接入構(gòu)造函數(shù)的調(diào)用,在參數(shù)類(lèi)型數(shù)組中使用了字段名:

Field getField(String name) -- 獲得命名的公共字段

Field[] getFields() -- 獲得類(lèi)的所有公共字段

Field getDeclaredField(String name) -- 獲得類(lèi)聲明的命名的字段

Field[] getDeclaredFields() -- 獲得類(lèi)聲明的所有字段

用于獲得方法信息函數(shù):

Method getMethod(String name, Class[] params) -- 使用特定的參數(shù)類(lèi)型,獲得命名的公共方法

Method[] getMethods() -- 獲得類(lèi)的所有公共方法

Method getDeclaredMethod(String name, Class[] params) -- 使用特寫(xiě)的參數(shù)類(lèi)型,獲得類(lèi)聲明的命名的方法

Method[] getDeclaredMethods() -- 獲得類(lèi)聲明的所有方法

使用 Reflection:

用于 reflection 的類(lèi),如 Method,可以在 java.lang.relfect 包中找到。使用這些類(lèi)的時(shí)候必須要遵循三個(gè)步驟:第一步是獲得你想操作的類(lèi)的 java.lang.Class 對(duì)象。在運(yùn)行中的 Java 程序中,用 java.lang.Class 類(lèi)來(lái)描述類(lèi)和接口等。

下面就是獲得一個(gè) Class 對(duì)象的方法之一:

Class c = Class.forName("java.lang.String");

這條語(yǔ)句得到一個(gè) String 類(lèi)的類(lèi)對(duì)象。還有另一種方法,如下面的語(yǔ)句:

Class c = int.class;

或者

Class c = Integer.TYPE;

它們可獲得基本類(lèi)型的類(lèi)信息。其中后一種方法中訪(fǎng)問(wèn)的是基本類(lèi)型的封裝類(lèi) (如 Intege ) 中預(yù)先定義好的 TYPE 字段。

第二步是調(diào)用諸如 getDeclaredMethods 的方法,以取得該類(lèi)中定義的所有方法的列表。

一旦取得這個(gè)信息,就可以進(jìn)行第三步了——使用 reflection API 來(lái)操作這些信息,如下面這段代碼:

Class c = Class.forName("java.lang.String");

Method m[] = c.getDeclaredMethods();

System.out.println(m[0].toString());

它將以文本方式打印出 String 中定義的第一個(gè)方法的原型。

處理對(duì)象:

a.創(chuàng)建一個(gè)Class對(duì)象

b.通過(guò)getField 創(chuàng)建一個(gè)Field對(duì)象

c.調(diào)用Field.getXXX(Object)方法(XXX是Int,Float等,如果是對(duì)象就省略;Object是指實(shí)例).

例如:

import java.lang.reflect.*;

import java.awt.*;

class SampleGet {

public static void main(String[] args) {

Rectangle r = new Rectangle(100, 325);

printHeight(r);

}

static void printHeight(Rectangle r) {

Field heightField;

Integer heightValue;

Class c = r.getClass();

try {

heightField = c.getField("height");

heightValue = (Integer) heightField.get(r);

System.out.println("Height: " + heightValue.toString());

} catch (NoSuchFieldException e) {

System.out.println(e);

} catch (SecurityException e) {

System.out.println(e);

} catch (IllegalAccessException e) {

System.out.println(e);

}

}

}

安全性和反射:

在處理反射時(shí)安全性是一個(gè)較復(fù)雜的問(wèn)題。反射經(jīng)常由框架型代碼使用,由于這一點(diǎn),我們可能希望框架能夠全面接入代碼,無(wú)需考慮常規(guī)的接入限制。但是,在其它情況下,不受控制的接入會(huì)帶來(lái)嚴(yán)重的安全性風(fēng)險(xiǎn),例如當(dāng)代碼在不值得信任的代碼共享的環(huán)境中運(yùn)行時(shí)。

由于這些互相矛盾的需求,Java編程語(yǔ)言定義一種多級(jí)別方法來(lái)處理反射的安全性?;灸J绞菍?duì)反射實(shí)施與應(yīng)用于源代碼接入相同的限制:

從任意位置到類(lèi)公共組件的接入

類(lèi)自身外部無(wú)任何到私有組件的接入

受保護(hù)和打包(缺省接入)組件的有限接入

不過(guò)至少有些時(shí)候,圍繞這些限制還有一種簡(jiǎn)單的方法。我們可以在我們所寫(xiě)的類(lèi)中,擴(kuò)展一個(gè)普通的基本類(lèi) java.lang.reflect.AccessibleObject 類(lèi)。這個(gè)類(lèi)定義了一種setAccessible方法,使我們能夠啟動(dòng)或關(guān)閉對(duì)這些類(lèi)中其中一個(gè)類(lèi)的實(shí)例的接入檢測(cè)。唯一的問(wèn)題在于如果使用了安全性管理 器,它將檢測(cè)正在關(guān)閉接入檢測(cè)的代碼是否許可了這樣做。如果未許可,安全性管理器拋出一個(gè)例外。

下面是一段程序,在TwoString 類(lèi)的一個(gè)實(shí)例上使用反射來(lái)顯示安全性正在運(yùn)行:

public class ReflectSecurity {

public static void main(String[] args) {

try {

TwoString ts = new TwoString("a", "b");

Field field = clas.getDeclaredField("m_s1");

// field.setAccessible(true);

System.out.println("Retrieved value is " +

field.get(inst));

} catch (Exception ex) {

ex.printStackTrace(System.out);

}

}

}

如果我們編譯這一程序時(shí),不使用任何特定參數(shù)直接從命令行運(yùn)行,它將在field .get(inst)調(diào)用中拋出一個(gè)IllegalAccessException異常。如果我們不注釋 field.setAccessible(true)代碼行,那么重新編譯并重新運(yùn)行該代碼,它將編譯成功。最后,如果我們?cè)诿钚刑砑恿薐VM參數(shù) -Djava.security.manager以實(shí)現(xiàn)安全性管理器,它仍然將不能通過(guò)編譯,除非我們定義了ReflectSecurity類(lèi)的許可權(quán) 限。

反射性能:(轉(zhuǎn)錄別人的?。?/p>

反射是一種強(qiáng)大的工具,但也存在一些不足。一個(gè)主要的缺點(diǎn)是對(duì)性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿(mǎn)足我們的要求。這類(lèi)操作總是慢于只直接執(zhí)行相同的操作。

下面的程序是字段接入性能測(cè)試的一個(gè)例子,包括基本的測(cè)試方法。每種方法測(cè)試字段接入的一種形式 -- accessSame 與同一對(duì)象的成員字段協(xié)作,accessOther 使用可直接接入的另一對(duì)象的字段,accessReflection 使用可通過(guò)反射接入的另一對(duì)象的字段。在每種情況下,方法執(zhí)行相同的計(jì)算 -- 循環(huán)中簡(jiǎn)單的加/乘順序。

程序如下:

public int accessSame(int loops) {

m_value = 0;

for (int index = 0; index loops; index++) {

m_value = (m_value + ADDITIVE_VALUE) *

MULTIPLIER_VALUE;

}

return m_value;

}

public int acces

sReference(int loops) {

TimingClass timing = new TimingClass();

for (int index = 0; index loops; index++) {

timing.m_value = (timing.m_value + ADDITIVE_VALUE) *

MULTIPLIER_VALUE;

}

return timing.m_value;

}

public int accessReflection(int loops) throws Exception {

TimingClass timing = new TimingClass();

try {

Field field = TimingClass.class.

getDeclaredField("m_value");

for (int index = 0; index loops; index++) {

int value = (field.getInt(timing) +

ADDITIVE_VALUE) * MULTIPLIER_VALUE;

field.setInt(timing, value);

}

return timing.m_value;

} catch (Exception ex) {

System.out.println("Error using reflection");

throw ex;

}

}

在上面的例子中,測(cè)試程序重復(fù)調(diào)用每種方法,使用一個(gè)大循環(huán)數(shù),從而平均多次調(diào)用的時(shí)間衡量結(jié)果。平均值中不包括每種方法第一次調(diào)用的時(shí)間,因此初始化時(shí)間不是結(jié)果中的一個(gè)因素。下面的圖清楚的向我們展示了每種方法字段接入的時(shí)間:

圖 1:字段接入時(shí)間 :

我們可以看出:在前兩副圖中(Sun JVM),使用反射的執(zhí)行時(shí)間超過(guò)使用直接接入的1000倍以上。通過(guò)比較,IBM JVM可能稍好一些,但反射方法仍舊需要比其它方法長(zhǎng)700倍以上的時(shí)間。任何JVM上其它兩種方法之間時(shí)間方面無(wú)任何顯著差異,但I(xiàn)BM JVM幾乎比Sun JVM快一倍。最有可能的是這種差異反映了Sun Hot Spot JVM的專(zhuān)業(yè)優(yōu)化,它在簡(jiǎn)單基準(zhǔn)方面表現(xiàn)得很糟糕。反射性能是Sun開(kāi)發(fā)1.4 JVM時(shí)關(guān)注的一個(gè)方面,它在反射方法調(diào)用結(jié)果中顯示。在這類(lèi)操作的性能方面,Sun 1.4.1 JVM顯示了比1.3.1版本很大的改進(jìn)。

如果為為創(chuàng)建使用反射的對(duì)象編寫(xiě)了類(lèi)似的計(jì)時(shí)測(cè)試程序,我們會(huì)發(fā)現(xiàn)這種情況下的差異不象字段和方法調(diào)用情況下那么顯著。使用newInstance()調(diào) 用創(chuàng)建一個(gè)簡(jiǎn)單的java.lang.Object實(shí)例耗用的時(shí)間大約是在Sun 1.3.1 JVM上使用new Object()的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1 JVM上的兩部。使用Array.newInstance(type, size)創(chuàng)建一個(gè)數(shù)組耗用的時(shí)間是任何測(cè)試的JVM上使用new type[size]的兩倍,隨著數(shù)組大小的增加,差異逐步縮小。隨著jdk6.0的推出,反射機(jī)制的性能也有了很大的提升。期待中….

總結(jié):

Java語(yǔ)言反射提供一種動(dòng)態(tài)鏈接程序組件的多功能方法。它允許程序創(chuàng)建和控制任何類(lèi)的對(duì)象(根據(jù)安全性限制),無(wú)需提前硬編碼目標(biāo)類(lèi)。這些特性使得反射 特別適用于創(chuàng)建以非常普通的方式與對(duì)象協(xié)作的庫(kù)。例如,反射經(jīng)常在持續(xù)存儲(chǔ)對(duì)象為數(shù)據(jù)庫(kù)、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使類(lèi)和數(shù)據(jù)結(jié)構(gòu)能按名稱(chēng)動(dòng)態(tài)檢索相關(guān)信息,并允許在運(yùn)行著的程序中操作這些信息。Java 的這一特性非常強(qiáng)大,并且是其它一些常用語(yǔ)言,如 C、C++、Fortran 或者 Pascal 等都不具備的。

但反射有兩個(gè)缺點(diǎn)。第一個(gè)是性能問(wèn)題。用于字段和方法接入時(shí)反射要遠(yuǎn)慢于直接代碼。性能問(wèn)題的程度取決于程序中是如何使用反射的。如果它作為程序運(yùn)行中相 對(duì)很少涉及的部分,緩慢的性能將不會(huì)是一個(gè)問(wèn)題。即使測(cè)試中最壞情況下的計(jì)時(shí)圖顯示的反射操作只耗用幾微秒。僅反射在性能關(guān)鍵的應(yīng)用的核心邏輯中使用時(shí)性 能問(wèn)題才變得至關(guān)重要。

許多應(yīng)用中更嚴(yán)重的一個(gè)缺點(diǎn)是使用反射會(huì)模糊程序內(nèi)部實(shí)際要發(fā)生的事情。程序人員希望在源代碼中看到程序的邏輯,反射等繞過(guò)了源代碼的技術(shù)會(huì)帶來(lái)維護(hù)問(wèn) 題。反射代碼比相應(yīng)的直接代碼更復(fù)雜,正如性能比較的代碼實(shí)例中看到的一樣。解決這些問(wèn)題的最佳方案是保守地使用反射——僅在它可以真正增加靈活性的地方 ——記錄其在目標(biāo)類(lèi)中的使用。

一下是對(duì)應(yīng)各個(gè)部分的例子:

具體的應(yīng)用:

1、 模仿instanceof 運(yùn)算符號(hào)

class A {}

public class instance1 {

public static void main(String args[])

{

try {

Class cls = Class.forName("A");

boolean b1

= cls.isInstance(new Integer(37));

System.out.println(b1);

boolean b2 = cls.isInstance(new A());

System.out.println(b2);

}

catch (Throwable e) {

System.err.println(e);

}

}

}

2、 在類(lèi)中尋找指定的方法,同時(shí)獲取該方法的參數(shù)列表,例外和返回值

import java.lang.reflect.*;

public class method1 {

private int f1(

Object p, int x) throws NullPointerException

{

if (p == null)

throw new NullPointerException();

return x;

}

public static void main(String args[])

{

try {

Class cls = Class.forName("method1");

Method methlist[]

= cls.getDeclaredMethods();

for (int i = 0; i methlist.length;

i++)

Method m = methlist[i];

System.out.println("name

= " + m.getName());

System.out.println("decl class = " +

m.getDeclaringClass());

Class pvec[] = m.getParameterTypes();

for (int j = 0; j pvec.length; j++)

System.out.println("

param #" + j + " " + pvec[j]);

Class evec[] = m.getExceptionTypes();

for (int j = 0; j evec.length; j++)

System.out.println("exc #" + j

+ " " + evec[j]);

System.out.println("return type = " +

m.getReturnType());

System.out.println("-----");

}

}

catch (Throwable e) {

System.err.println(e);

}

}

}

3、 獲取類(lèi)的構(gòu)造函數(shù)信息,基本上與獲取方法的方式相同

import java.lang.reflect.*;

public class constructor1 {

public constructor1()

{

}

protected constructor1(int i, double d)

{

}

public static void main(String args[])

{

try {

Class cls = Class.forName("constructor1");

Constructor ctorlist[]

= cls.getDeclaredConstructors();

for (int i = 0; i ctorlist.length; i++) {

Constructor ct = ctorlist[i];

System.out.println("name

= " + ct.getName());

System.out.println("decl class = " +

ct.getDeclaringClass());

Class pvec[] = ct.getParameterTypes();

for (int j = 0; j pvec.length; j++)

System.out.println("param #"

+ j + " " + pvec[j]);

Class evec[] = ct.getExceptionTypes();

for (int j = 0; j evec.length; j++)

System.out.println(

"exc #" + j + " " + evec[j]);

System.out.println("-----");

}

}

catch (Throwable e) {

System.err.println(e);

}

}

}

4、 獲取類(lèi)中的各個(gè)數(shù)據(jù)成員對(duì)象,包括名稱(chēng)。類(lèi)型和訪(fǎng)問(wèn)修飾符號(hào)

import java.lang.reflect.*;

public class field1 {

private double d;

public static final int i = 37;

String s = "testing";

public static void main(String args[])

{

try {

Class cls = Class.forName("field1");

Field fieldlist[]

= cls.getDeclaredFields();

for (int i

= 0; i fieldlist.length; i++) {

Field fld = fieldlist[i];

System.out.println("name

= " + fld.getName());

System.out.println("decl class = " +

fld.getDeclaringClass());

System.out.println("type

= " + fld.getType());

int mod = fld.getModifiers();

System.out.println("modifiers = " +

Modifier.toString(mod));

System.out.println("-----");

}

}

catch (Throwable e) {

System.err.println(e);

}

}

}

5、 通過(guò)使用方法的名字調(diào)用方法

import java.lang.reflect.*;

public class method2 {

public int add(int a, int b)

{

return a + b;

}

public static void main(String args[])

{

try {

Class cls = Class.forName("method2");

Class partypes[] = new Class[2];

partypes[0] = Integer.TYPE;

partypes[1] = Integer.TYPE;

Method meth = cls.getMethod(

"add", partypes);

method2 methobj = new method2();

Object arglist[] = new Object[2];

arglist[0] = new Integer(37);

arglist[1] = new Integer(47);

Object retobj

= meth.invoke(methobj, arglist);

Integer retval = (Integer)retobj;

System.out.println(retval.intValue());

}

catch (Throwable e) {

System.err.println(e);

}

}

}

6、 創(chuàng)建新的對(duì)象

import java.lang.reflect.*;

public class constructor2 {

public constructor2()

{

}

public constructor2(int a, int b)

{

System.out.println(

"a = " + a + " b = " + b);

}

public static void main(String args[])

{

try {

Class cls = Class.forName("constructor2");

Class partypes[] = new Class[2];

partypes[0] = Integer.TYPE;

partypes[1] = Integer.TYPE;

Constructor ct

= cls.getConstructor(partypes);

Object arglist[] = new Object[2];

arglist[0] = new Integer(37);

arglist[1] = new Integer(47);

Object retobj = ct.newInstance(arglist);

}

catch (Throwable e) {

System.err.println(e);

}

}

}

7、 變更類(lèi)實(shí)例中的數(shù)據(jù)的值

import java.lang.reflect.*;

public class field2 {

public double d;

public static void main(String args[])

{

try {

Class cls = Class.forName("field2");

Field fld = cls.getField("d");

field2 f2obj = new field2();

System.out.println("d = " + f2obj.d);

fld.setDouble(f2obj, 12.34);

System.out.println("d = " + f2obj.d);

}

catch (Throwable e) {

System.err.println(e);

}

}

}

使用反射創(chuàng)建可重用代碼:

1、 對(duì)象工廠(chǎng)

Object factory(String p) {

Class c;

Object o=null;

try {

c = Class.forName(p);// get class def

o = c.newInstance(); // make a new one

} catch (Exception e) {

System.err.println("Can't make a " + p);

}

return o;

}

public class ObjectFoundry {

public static Object factory(String p)

throws ClassNotFoundException,

InstantiationException,

IllegalAccessException {

Class c = Class.forName(p);

Object o = c.newInstance();

return o;

}

}

2、 動(dòng)態(tài)檢測(cè)對(duì)象的身份,替代instanceof

public static boolean

isKindOf(Object obj, String type)

throws ClassNotFoundException {

// get the class def for obj and type

Class c = obj.getClass();

Class tClass = Class.forName(type);

while ( c!=null ) {

if ( c==tClass ) return true;

c = c.getSuperclass();

}

return false;

}

java編程中,常提到的反射代碼指的是什么?

反射的概念是由Smith在1982年首次提出的,主要是指程序可以訪(fǎng)問(wèn)、檢測(cè)和修改它本身狀態(tài)或行為的一種能力。這一概念的提出很快引發(fā)了計(jì)算機(jī)科學(xué)領(lǐng)域關(guān)于應(yīng)用反射性的研究。它首先被程序語(yǔ)言的設(shè)計(jì)領(lǐng)域所采用,并在Lisp和面向?qū)ο蠓矫嫒〉昧顺煽?jī)。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射機(jī)制的語(yǔ)言。最近,反射機(jī)制也被應(yīng)用到了視窗系統(tǒng)、操作系統(tǒng)和文件系統(tǒng)中。

反射本身并不是一個(gè)新概念,它可能會(huì)使我們聯(lián)想到光學(xué)中的反射概念,盡管計(jì)算機(jī)科學(xué)賦予了反射概念新的含義,但是,從現(xiàn)象上來(lái)說(shuō),它們確實(shí)有某些相通之處,這些有助于我們的理解。在計(jì)算機(jī)科學(xué)領(lǐng)域,反射是指一類(lèi)應(yīng)用,它們能夠自描述和自控制。也就是說(shuō),這類(lèi)應(yīng)用通過(guò)采用某種機(jī)制來(lái)實(shí)現(xiàn)對(duì)自己行為的描述(self-representation)和監(jiān)測(cè)(examination),并能根據(jù)自身行為的狀態(tài)和結(jié)果,調(diào)整或修改應(yīng)用所描述行為的狀態(tài)和相關(guān)的語(yǔ)義??梢钥闯?,同一般的反射概念相比,計(jì)算機(jī)科學(xué)領(lǐng)域的反射不單單指反射本身,還包括對(duì)反射結(jié)果所采取的措施。所有采用反射機(jī)制的系統(tǒng)(即反射系統(tǒng))都希望使系統(tǒng)的實(shí)現(xiàn)更開(kāi)放。可以說(shuō),實(shí)現(xiàn)了反射機(jī)制的系統(tǒng)都具有開(kāi)放性,但具有開(kāi)放性的系統(tǒng)并不一定采用了反射機(jī)制,開(kāi)放性是反射系統(tǒng)的必要條件。一般來(lái)說(shuō),反射系統(tǒng)除了滿(mǎn)足開(kāi)放性條件外還必須滿(mǎn)足原因連接(Causally-connected)。所謂原因連接是指對(duì)反射系統(tǒng)自描述的改變能夠立即反映到系統(tǒng)底層的實(shí)際狀態(tài)和行為上的情況,反之亦然。開(kāi)放性和原因連接是反射系統(tǒng)的兩大基本要素。13700863760

Java中,反射是一種強(qiáng)大的工具。它使您能夠創(chuàng)建靈活的代碼,這些代碼可以在運(yùn)行時(shí)裝配,無(wú)需在組件之間進(jìn)行源代表鏈接。反射允許我們?cè)诰帉?xiě)與執(zhí)行時(shí),使我們的程序代碼能夠接入裝載到JVM中的類(lèi)的內(nèi)部信息,而不是源代碼中選定的類(lèi)協(xié)作的代碼。這使反射成為構(gòu)建靈活的應(yīng)用的主要工具。但需注意的是:如果使用不當(dāng),反射的成本很高。

二、Java中的類(lèi)反射:

Reflection 是 Java 程序開(kāi)發(fā)語(yǔ)言的特征之一,它允許運(yùn)行中的 Java 程序?qū)ψ陨磉M(jìn)行檢查,或者說(shuō)“自審”,并能直接操作程序的內(nèi)部屬性。Java 的這一能力在實(shí)際應(yīng)用中也許用得不是很多,但是在其它的程序設(shè)計(jì)語(yǔ)言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒(méi)有辦法在程序中獲得函數(shù)定義相關(guān)的信息。

1.檢測(cè)類(lèi):

1.1 reflection的工作機(jī)制

考慮下面這個(gè)簡(jiǎn)單的例子,讓我們看看 reflection 是如何工作的。

import java.lang.reflect.*;

public class DumpMethods {

public static void main(String args[]) {

try {

Class c = Class.forName(args[0]);

Method m[] = c.getDeclaredMethods();

for (int i = 0; i m.length; i++)

System.out.println(m[i].toString());

} catch (Throwable e) {

System.err.println(e);

}

}

}

按如下語(yǔ)句執(zhí)行:

java DumpMethods java.util.Stack

它的結(jié)果輸出為:

public java.lang.Object java.util.Stack.push(java.lang.Object)

public synchronized java.lang.Object java.util.Stack.pop()

public synchronized java.lang.Object java.util.Stack.peek()

public boolean java.util.Stack.empty()

public synchronized int java.util.Stack.search(java.lang.Object)

這樣就列出了java.util.Stack 類(lèi)的各方法名以及它們的限制符和返回類(lèi)型。

這個(gè)程序使用 Class.forName 載入指定的類(lèi),然后調(diào)用 getDeclaredMethods 來(lái)獲取這個(gè)類(lèi)中定義了的方法列表。java.lang.reflect.Methods 是用來(lái)描述某個(gè)類(lèi)中單個(gè)方法的一個(gè)類(lèi)。

1.2 Java類(lèi)反射中的主要方法

對(duì)于以下三類(lèi)組件中的任何一類(lèi)來(lái)說(shuō) -- 構(gòu)造函數(shù)、字段和方法 -- java.lang.Class 提供四種獨(dú)立的反射調(diào)用,以不同的方式來(lái)獲得信息。調(diào)用都遵循一種標(biāo)準(zhǔn)格式。以下是用于查找構(gòu)造函數(shù)的一組反射調(diào)用:

l Constructor getConstructor(Class[] params) -- 獲得使用特殊的參數(shù)類(lèi)型的公共構(gòu)造函數(shù),

l Constructor[] getConstructors() -- 獲得類(lèi)的所有公共構(gòu)造函數(shù)

l Constructor getDeclaredConstructor(Class[] params) -- 獲得使用特定參數(shù)類(lèi)型的構(gòu)造函數(shù)(與接入級(jí)別無(wú)關(guān))

l Constructor[] getDeclaredConstructors() -- 獲得類(lèi)的所有構(gòu)造函數(shù)(與接入級(jí)別無(wú)關(guān))

獲得字段信息的Class 反射調(diào)用不同于那些用于接入構(gòu)造函數(shù)的調(diào)用,在參數(shù)類(lèi)型數(shù)組中使用了字段名:

l Field getField(String name) -- 獲得命名的公共字段

l Field[] getFields() -- 獲得類(lèi)的所有公共字段

l Field getDeclaredField(String name) -- 獲得類(lèi)聲明的命名的字段

l Field[] getDeclaredFields() -- 獲得類(lèi)聲明的所有字段

用于獲得方法信息函數(shù):

l Method getMethod(String name, Class[] params) -- 使用特定的參數(shù)類(lèi)型,獲得命名的公共方法

l Method[] getMethods() -- 獲得類(lèi)的所有公共方法

l Method getDeclaredMethod(String name, Class[] params) -- 使用特寫(xiě)的參數(shù)類(lèi)型,獲得類(lèi)聲明的命名的方法

l Method[] getDeclaredMethods() -- 獲得類(lèi)聲明的所有方法

1.3開(kāi)始使用 Reflection:

用于 reflection 的類(lèi),如 Method,可以在 java.lang.relfect 包中找到。使用這些類(lèi)的時(shí)候必須要遵循三個(gè)步驟:第一步是獲得你想操作的類(lèi)的 java.lang.Class 對(duì)象。在運(yùn)行中的 Java 程序中,用 java.lang.Class 類(lèi)來(lái)描述類(lèi)和接口等。

下面就是獲得一個(gè) Class 對(duì)象的方法之一:

Class c = Class.forName("java.lang.String");

這條語(yǔ)句得到一個(gè) String 類(lèi)的類(lèi)對(duì)象。還有另一種方法,如下面的語(yǔ)句:

Class c = int.class;

或者

Class c = Integer.TYPE;

它們可獲得基本類(lèi)型的類(lèi)信息。其中后一種方法中訪(fǎng)問(wèn)的是基本類(lèi)型的封裝類(lèi) (如 Integer) 中預(yù)先定義好的 TYPE 字段。

第二步是調(diào)用諸如 getDeclaredMethods 的方法,以取得該類(lèi)中定義的所有方法的列表。

一旦取得這個(gè)信息,就可以進(jìn)行第三步了——使用 reflection API 來(lái)操作這些信息,如下面這段代碼:

Class c = Class.forName("java.lang.String");

Method m[] = c.getDeclaredMethods();

System.out.println(m[0].toString());

它將以文本方式打印出 String 中定義的第一個(gè)方法的原型。

2.處理對(duì)象:

如果要作一個(gè)開(kāi)發(fā)工具像debugger之類(lèi)的,你必須能發(fā)現(xiàn)filed values,以下是三個(gè)步驟:

a.創(chuàng)建一個(gè)Class對(duì)象

b.通過(guò)getField 創(chuàng)建一個(gè)Field對(duì)象

c.調(diào)用Field.getXXX(Object)方法(XXX是Int,Float等,如果是對(duì)象就省略;Object是指實(shí)例).

例如:

import java.lang.reflect.*;

import java.awt.*;

class SampleGet {

public static void main(String[] args) {

Rectangle r = new Rectangle(100, 325);

printHeight(r);

}

static void printHeight(Rectangle r) {

Field heightField;

Integer heightValue;

Class c = r.getClass();

try {

heightField = c.getField("height");

heightValue = (Integer) heightField.get(r);

System.out.println("Height: " + heightValue.toString());

} catch (NoSuchFieldException e) {

System.out.println(e);

} catch (SecurityException e) {

System.out.println(e);

} catch (IllegalAccessException e) {

System.out.println(e);

}

}

}

三、安全性和反射:

在處理反射時(shí)安全性是一個(gè)較復(fù)雜的問(wèn)題。反射經(jīng)常由框架型代碼使用,由于這一點(diǎn),我們可能希望框架能夠全面接入代碼,無(wú)需考慮常規(guī)的接入限制。但是,在其它情況下,不受控制的接入會(huì)帶來(lái)嚴(yán)重的安全性風(fēng)險(xiǎn),例如當(dāng)代碼在不值得信任的代碼共享的環(huán)境中運(yùn)行時(shí)。

由于這些互相矛盾的需求,Java編程語(yǔ)言定義一種多級(jí)別方法來(lái)處理反射的安全性?;灸J绞菍?duì)反射實(shí)施與應(yīng)用于源代碼接入相同的限制:

n 從任意位置到類(lèi)公共組件的接入

n 類(lèi)自身外部無(wú)任何到私有組件的接入

n 受保護(hù)和打包(缺省接入)組件的有限接入

不過(guò)至少有些時(shí)候,圍繞這些限制還有一種簡(jiǎn)單的方法。我們可以在我們所寫(xiě)的類(lèi)中,擴(kuò)展一個(gè)普通的基本類(lèi)java.lang.reflect.AccessibleObject 類(lèi)。這個(gè)類(lèi)定義了一種setAccessible方法,使我們能夠啟動(dòng)或關(guān)閉對(duì)這些類(lèi)中其中一個(gè)類(lèi)的實(shí)例的接入檢測(cè)。唯一的問(wèn)題在于如果使用了安全性管理器,它將檢測(cè)正在關(guān)閉接入檢測(cè)的代碼是否許可了這樣做。如果未許可,安全性管理器拋出一個(gè)例外。

下面是一段程序,在TwoString 類(lèi)的一個(gè)實(shí)例上使用反射來(lái)顯示安全性正在運(yùn)行:

public class ReflectSecurity {

public static void main(String[] args) {

try {

TwoString ts = new TwoString("a", "b");

Field field = clas.getDeclaredField("m_s1");

// field.setAccessible(true);

System.out.println("Retrieved value is " +

field.get(inst));

} catch (Exception ex) {

ex.printStackTrace(System.out);

}

}

}

如果我們編譯這一程序時(shí),不使用任何特定參數(shù)直接從命令行運(yùn)行,它將在field .get(inst)調(diào)用中拋出一個(gè)IllegalAccessException異常。如果我們不注釋field.setAccessible(true)代碼行,那么重新編譯并重新運(yùn)行該代碼,它將編譯成功。最后,如果我們?cè)诿钚刑砑恿薐VM參數(shù)-Djava.security.manager以實(shí)現(xiàn)安全性管理器,它仍然將不能通過(guò)編譯,除非我們定義了ReflectSecurity類(lèi)的許可權(quán)限。

四、反射性能:

反射是一種強(qiáng)大的工具,但也存在一些不足。一個(gè)主要的缺點(diǎn)是對(duì)性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿(mǎn)足我們的要求。這類(lèi)操作總是慢于只直接執(zhí)行相同的操作。

下面的程序是字段接入性能測(cè)試的一個(gè)例子,包括基本的測(cè)試方法。每種方法測(cè)試字段接入的一種形式 -- accessSame 與同一對(duì)象的成員字段協(xié)作,accessOther 使用可直接接入的另一對(duì)象的字段,accessReflection 使用可通過(guò)反射接入的另一對(duì)象的字段。在每種情況下,方法執(zhí)行相同的計(jì)算 -- 循環(huán)中簡(jiǎn)單的加/乘順序。

程序如下:

public int accessSame(int loops) {

m_value = 0;

for (int index = 0; index loops; index++) {

m_value = (m_value + ADDITIVE_VALUE) *

MULTIPLIER_VALUE;

}

return m_value;

}

public int accessReference(int loops) {

TimingClass timing = new TimingClass();

for (int index = 0; index loops; index++) {

timing.m_value = (timing.m_value + ADDITIVE_VALUE) *

MULTIPLIER_VALUE;

}

return timing.m_value;

}

public int accessReflection(int loops) throws Exception {

TimingClass timing = new TimingClass();

try {

Field field = TimingClass.class.

getDeclaredField("m_value");

for (int index = 0; index loops; index++) {

int value = (field.getInt(timing) +

ADDITIVE_VALUE) * MULTIPLIER_VALUE;

field.setInt(timing, value);

}

return timing.m_value;

} catch (Exception ex) {

System.out.println("Error using reflection");

throw ex;

}

}

在上面的例子中,測(cè)試程序重復(fù)調(diào)用每種方法,使用一個(gè)大循環(huán)數(shù),從而平均多次調(diào)用的時(shí)間衡量結(jié)果。平均值中不包括每種方法第一次調(diào)用的時(shí)間,因此初始化時(shí)間不是結(jié)果中的一個(gè)因素。下面的圖清楚的向我們展示了每種方法字段接入的時(shí)間:

圖 1:字段接入時(shí)間 :

我們可以看出:在前兩副圖中(Sun JVM),使用反射的執(zhí)行時(shí)間超過(guò)使用直接接入的1000倍以上。通過(guò)比較,IBM JVM可能稍好一些,但反射方法仍舊需要比其它方法長(zhǎng)700倍以上的時(shí)間。任何JVM上其它兩種方法之間時(shí)間方面無(wú)任何顯著差異,但I(xiàn)BM JVM幾乎比Sun JVM快一倍。最有可能的是這種差異反映了Sun Hot Spot JVM的專(zhuān)業(yè)優(yōu)化,它在簡(jiǎn)單基準(zhǔn)方面表現(xiàn)得很糟糕。反射性能是Sun開(kāi)發(fā)1.4 JVM時(shí)關(guān)注的一個(gè)方面,它在反射方法調(diào)用結(jié)果中顯示。在這類(lèi)操作的性能方面,Sun 1.4.1 JVM顯示了比1.3.1版本很大的改進(jìn)。

如果為為創(chuàng)建使用反射的對(duì)象編寫(xiě)了類(lèi)似的計(jì)時(shí)測(cè)試程序,我們會(huì)發(fā)現(xiàn)這種情況下的差異不象字段和方法調(diào)用情況下那么顯著。使用newInstance()調(diào)用創(chuàng)建一個(gè)簡(jiǎn)單的java.lang.Object實(shí)例耗用的時(shí)間大約是在Sun 1.3.1 JVM上使用new Object()的12倍,是在IBM 1.4.0 JVM的四倍,只是Sun 1.4.1 JVM上的兩部。使用Array.newInstance(type, size)創(chuàng)建一個(gè)數(shù)組耗用的時(shí)間是任何測(cè)試的JVM上使用new type[size]的兩倍,隨著數(shù)組大小的增加,差異逐步縮小。

結(jié)束語(yǔ):

Java語(yǔ)言反射提供一種動(dòng)態(tài)鏈接程序組件的多功能方法。它允許程序創(chuàng)建和控制任何類(lèi)的對(duì)象(根據(jù)安全性限制),無(wú)需提前硬編碼目標(biāo)類(lèi)。這些特性使得反射特別適用于創(chuàng)建以非常普通的方式與對(duì)象協(xié)作的庫(kù)。例如,反射經(jīng)常在持續(xù)存儲(chǔ)對(duì)象為數(shù)據(jù)庫(kù)、XML或其它外部格式的框架中使用。Java reflection 非常有用,它使類(lèi)和數(shù)據(jù)結(jié)構(gòu)能按名稱(chēng)動(dòng)態(tài)檢索相關(guān)信息,并允許在運(yùn)行著的程序中操作這些信息。Java 的這一特性非常強(qiáng)大,并且是其它一些常用語(yǔ)言,如 C、C++、Fortran 或者 Pascal 等都不具備的。

但反射有兩個(gè)缺點(diǎn)。第一個(gè)是性能問(wèn)題。用于字段和方法接入時(shí)反射要遠(yuǎn)慢于直接代碼。性能問(wèn)題的程度取決于程序中是如何使用反射的。如果它作為程序運(yùn)行中相對(duì)很少涉及的部分,緩慢的性能將不會(huì)是一個(gè)問(wèn)題。即使測(cè)試中最壞情況下的計(jì)時(shí)圖顯示的反射操作只耗用幾微秒。僅反射在性能關(guān)鍵的應(yīng)用的核心邏輯中使用時(shí)性能問(wèn)題才變得至關(guān)重要。

許多應(yīng)用中更嚴(yán)重的一個(gè)缺點(diǎn)是使用反射會(huì)模糊程序內(nèi)部實(shí)際要發(fā)生的事情。程序人員希望在源代碼中看到程序的邏輯,反射等繞過(guò)了源代碼的技術(shù)會(huì)帶來(lái)維護(hù)問(wèn)題。反射代碼比相應(yīng)的直接代碼更復(fù)雜,正如性能比較的代碼實(shí)例中看到的一樣。解決這些問(wèn)題的最佳方案是保守地使用反射——僅在它可以真正增加靈活性的地方——記錄其在目標(biāo)類(lèi)中的使用。

利用反射實(shí)現(xiàn)類(lèi)的動(dòng)態(tài)加載

Bromon原創(chuàng) 請(qǐng)尊重版權(quán)

最近在成都寫(xiě)一個(gè)移動(dòng)增值項(xiàng)目,俺負(fù)責(zé)后臺(tái)server端。功能很簡(jiǎn)單,手機(jī)用戶(hù)通過(guò)GPRS打開(kāi)Socket與服務(wù)器連接,我則根據(jù)用戶(hù)傳過(guò)來(lái)的數(shù)據(jù)做出響應(yīng)。做過(guò)類(lèi)似項(xiàng)目的兄弟一定都知道,首先需要定義一個(gè)類(lèi)似于MSNP的通訊協(xié)議,不過(guò)今天的話(huà)題是如何把這個(gè)系統(tǒng)設(shè)計(jì)得具有高度的擴(kuò)展性。由于這個(gè)項(xiàng)目本身沒(méi)有進(jìn)行過(guò)較為完善的客戶(hù)溝通和需求分析,所以以后肯定會(huì)有很多功能上的擴(kuò)展,通訊協(xié)議肯定會(huì)越來(lái)越龐大,而我作為一個(gè)不那么勤快的人,當(dāng)然不想以后再去修改寫(xiě)好的程序,所以這個(gè)項(xiàng)目是實(shí)踐面向?qū)ο笤O(shè)計(jì)的好機(jī)會(huì)。

首先定義一個(gè)接口來(lái)隔離類(lèi):

package org.bromon.reflect;

public interface Operator

{

public java.util.List act(java.util.List params)

}

根據(jù)設(shè)計(jì)模式的原理,我們可以為不同的功能編寫(xiě)不同的類(lèi),每個(gè)類(lèi)都繼承Operator接口,客戶(hù)端只需要針對(duì)Operator接口編程就可以避免很多麻煩。比如這個(gè)類(lèi):

package org.bromon.reflect.*;

public class Success implements Operator

{

public java.util.List act(java.util.List params)

{

List result=new ArrayList();

java中的反射,invoke方法詳解

就是調(diào)用類(lèi)中的方法,最簡(jiǎn)單的用法是可以把方法參數(shù)化,invoke(class, method)比如你Test類(lèi)里有一系列名字相似的方法setValue1、setValue2等等??梢园逊椒孢M(jìn)數(shù)組v[],然后循環(huán)里invoke(test,v[i]),就順序調(diào)用了全部setValue

如:public?class? MyTest{?public?static?void?main(String[]?args) {?String?[]?names?={"tom","tim","allen","alice"};

Class??clazz?=?Test.class;?try ? Method?method?=?clazz.getMethod("sayHi",?String.class);for(String?name:names)method.invoke(clazz.newInstance(),name);}?catch?(NoSuchMethodException?e)?e.printStackTrace();?}?catch?(IllegalAccessExcepti?e.printStackTrace(?}?catch?(IllegalArgumentException??{e.printStackTrace();}?catch?(InvocationTargetException?e)e.printStackTrace();?}?catch?(InstantiationException?e?{e.printStackTrace(?}class?Test{public?void?sayHi(String?name){?System.out.println("Hi?"+name);?}

java課程分享Java的反射機(jī)制

Java反射機(jī)制是一個(gè)非常強(qiáng)大的功能,在很多大型項(xiàng)目比如Spring,Mybatis都可以看見(jiàn)反射的身影。通過(guò)反射機(jī)制我們可以在運(yùn)行期間獲取對(duì)象的類(lèi)型信息,利用這一特性我們可以實(shí)現(xiàn)工廠(chǎng)模式和代理模式等設(shè)計(jì)模式,同時(shí)也可以解決Java泛型擦除等令人苦惱的問(wèn)題。下面java課程就從實(shí)際應(yīng)用的角度出發(fā),來(lái)應(yīng)用一下Java的反射機(jī)制。

反射基礎(chǔ)

p.s:本文需要讀者對(duì)反射機(jī)制的API有一定程度的了解,如果之前沒(méi)有接觸過(guò)的話(huà),建議先看一下官方文檔的QuickStart。

在應(yīng)用反射機(jī)制之前,首先我們先來(lái)看一下如何獲取一個(gè)對(duì)象對(duì)應(yīng)的反射類(lèi)Class,在Java中我們有三種方法可以獲取一個(gè)對(duì)象的反射類(lèi)。

通過(guò)getClass方法

在Java中,每一個(gè)Object都有一個(gè)getClass方法,通過(guò)getClass方法我們可以獲取到這個(gè)對(duì)象對(duì)應(yīng)的反射類(lèi):

Strings="ziwenxie";

Class?c=s.getClass();

通過(guò)forName方法

我們也可以調(diào)用Class類(lèi)的靜態(tài)方法forName:

Class?c=Class.forName("java.lang.String");

使用.class

或者我們也可以直接使用.class:

Class?c=String.class;

獲取類(lèi)型信息

在文章開(kāi)頭我們就提到反射的一大好處就是可以允許我們?cè)谶\(yùn)行期間獲取對(duì)象的類(lèi)型信息,下面我們通過(guò)一個(gè)例子來(lái)具體看一下。

首先我們?cè)趖ypeinfo.interfacea包下面新建一個(gè)接口A:

packagetypeinfo.interfacea;

publicinterfaceA{voidf();}

接著我們?cè)趖ypeinfo.packageaccess包下面新建一個(gè)接口C,接口C繼承自接口A,并且我們還另外創(chuàng)建了幾個(gè)用于測(cè)試的方法,注意下面幾個(gè)方法的權(quán)限都是不同的。

網(wǎng)頁(yè)題目:java反射代碼講解,java反射代碼實(shí)現(xiàn)
網(wǎng)頁(yè)鏈接:http://muchs.cn/article48/phgoep.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供手機(jī)網(wǎng)站建設(shè)定制開(kāi)發(fā)、關(guān)鍵詞優(yōu)化營(yíng)銷(xiāo)型網(wǎng)站建設(shè)、全網(wǎng)營(yíng)銷(xiāo)推廣、軟件開(kāi)發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化