2015-12-24 11 views
8

Ho incontrato il codice di script di Groovy nel libro. E ha generato alcune uscite strane per me.Groovy: this.metaClass Versus instance.metaClass

class Person{ 
    def work(){ 
    println "work()" 
    } 
    def sports=['basketball','football','voleyball'] 
    def methodMissing(String name, args){ 
    if(name in sports){ 
     println "injected ${name} into Person class" 
     Person instance=this 
     println "this.metaClass:\t\t${this.metaClass}" 
     println "instance.metaClass:\t${instance.metaClass}" 
     assert this.metaClass==instance.metaClass 
    }else{ 
     println "no such method:${name}() in Person class" 
    } 
    } 
} 
def jack=new Person() 
jack.football() 

il suo output è il seguente:

injected football into Person class 
this.metaClass:  [email protected][class Person] 
instance.metaClass: [email protected][[email protected][class Person]] 
Caught: Assertion failed: 
//I did not paste the detailed assertion here for simplicity 

, quindi sono abbastanza confuso:

  1. perché è this.metaClass non è uguale a instance.metaClass?
  2. ulteriore, non posso usare this.metaClass per iniettare nuovi metodi; groovy mi ha detto che this.metaClass non ha tale proprietà, che intendevo iniettare.
  3. Che cosa significa "[email protected] [[email protected] [class Person]]" significa? So che "245b4bdc" potrebbe essere il puntatore dell'oggetto. Ma perché HandleMetaClass e MetaClassImpl hanno lo stesso valore di puntatore "245b4bdc"?

Attualmente, ho capito che @ 245b4bdc non è il "riferimento oggetto", così HandleMetaClass @ 245b4bdc non è necessariamente la stessa istanza come MetaClassImpl @ 245b4bdc. Siamo in grado di utilizzare il metodo Object.is() per giudicare se sono la stessa. (Ho fatto, è risultato falso )

+1

Se si modifica a 'valere this.class. metaClass == instance.metaClass', passa. – bdkosher

+0

Perché? Dovrebbe this.class.metaClass == Person.metaClass? – Guocheng

+0

Trovato una risposta migliore qui, https://stackoverflow.com/a/45407488/42769, in realtà, sono io. –

risposta

3
  1. perché this.metaClass! = Instance.metaClass?

    Comprende l'accesso di groove ai campi.

    • Quando accede a un campo di istanza da "fuori", scanalato chiama effettivamente la funzione RicavaNomeCampo(). Nel mio esempio, quando uso "istanza", sono allo all'esterno dello; Quindi instance.metaClass chiamerà instance.getMetaClass().

    • Quando accede a un campo di istanza da "dentro", scanalato semplicemente accedere direttamente sul campo, RicavaNomeCampo() non viene chiamato. Nel nostro esempio, quando uso "questo", sono al "all'interno di"; Quindi "this.metaClass" accederà direttamente a "metaClass".

    • Infine, getMetaClass() restituisce un oggettoHandleMetaClass mentre la metaclasse interna è un oggettoMetaClassImpl. Quindi this.metaClass! = Instance.metaClass.

  2. Perché this.metaClass.say = {-> println "dire"} sarà getta MissingPropertyException?Tipo

    • this.metaClass della partita è MetaClassImpl

    • MetaClassImpl è una classe di basso livello, che supporta le classi di livello superiore (ad es. HandleMetaClass) iniettabile. Non è pensato per lo Sviluppatore per l'uso diretto, quindi non supporta il modo di iniezione: xxxx.say = {-> println "say"}.

codice di esempio (per la domanda 1):

class Person{ 
    def work(){ 
    println "work()" 
    } 
    def sports=['basketball','football','voleyball'] 
    def methodMissing(String name, args){ 
    if(name in sports){ 
     Person instance=this 

     println "this.metaClass:\n\t${this.metaClass}" 
     println "instance.metaClass:\n\t${instance.metaClass}" 
     //output: false 
     println "this.metaClass.is(instance.metaClass):\n\t${this.metaClass.is(instance.metaClass)}" 

     //output: true 
     println "this.getMetaClass().is(instance.getMetaClass()):\n\t${this.getMetaClass().is(instance.getMetaClass())}" 

    }else{ 
     println "no such method:${name}() in Person class" 
    } 
    } 
} 
def jack=new Person() 
jack.football() 
jack.football() 

codice di esempio (per la domanda 2):

class Cat{} 
    def a=new groovy.lang.MetaClassImpl(Cat) 
try{ 
    a.say={->println "say"} 
}catch(MissingPropertyException e){ 
    println "[Fail]\n\tcan not inject method say() into MetaClassImpl class.\n" 
} 

def b=new org.codehaus.groovy.runtime.HandleMetaClass(a) 
println b 
b.say={->println "[say]"} 
println "[OK]\n\tcan inject method say() into HandleMetaClass class\n" 
def method=b.getMetaMethod("say") 
method.invoke(this) 
+0

Quindi, come sta facendo l'accesso al campo a "metaClass' quando non è stato definito nella classe corrente? Forse il modificatore di accesso è protetto nella sua superclasse 'Object' forse? Ma in ogni caso, per ottenere l'accesso al campo, è necessario accedere alla proprietà all'interno della classe che lo definisce, secondo il documento groovy. 'metaClass' non è definito nella sottoclasse Persona, quindi mi chiedo come viene eseguito l'accesso al campo. – solstice333

+0

No, è una risposta sbagliata. Vedi qui, https://stackoverflow.com/a/45407488/42769. –