掌握Gradle,还需要掌握这些知识--Groovy MOP,算法题+JVM+自定义View

def demo = new Demo4()

println demo.foo(“a”)

println demo.bar(“A”, “B”)

}

}

Task :Demo4.main()

unknown method foo(a)

unknown method bar(A,B)

动态处理类的属性

一个有关的题外话

一个传统的 简单JavaBean,在很多场景下又称为 POJO ,大家对此不会陌生,它包含了属性和属性的Getter、Setter并且不包含任意逻辑。

我们知道, POJO需要添加Getter、Setter,哪怕通过IDE生成,并且编译时如果可能,会被inline优化,为此,还有 是否该使用Lombok之争

但是,对于 “应当有Getter、Setter,但是不应当由编写者处理,而是应该由编译器处理” 是多数人认同的

Groovy中对此进行了尝试,提供了 GPath机制:通过编译器直接生成Getter、Setter,编码时形如属性访问,用"."符 foo.bar,实际却相对复杂。

kotlin中也有类似的机制。

class GpathDemo {

static class Foo {

String bar

def getBaz() {

return “baz”

}

}

static void main(String[] args) {

Foo foo = new Foo(bar:“bar”)

foo.bar = “bar 2”

println(foo.bar)

println(foo.baz)

}

}

我们可以发现,生成的类:

public static class Foo implements GroovyObject {

private String bar;

@Generated

public Foo() {

CallSite[] var1 = $getCallSiteArray();

super();

MetaClass var2 = this.$getStaticMetaClass();

this.metaClass = var2;

}

public Object getBaz() {

CallSite[] var1 = $getCallSiteArray();

return “baz”;

}

@Generated

public String getBar() {

return this.bar;

}

@Generated

public void setBar(String var1) {

this.bar = var1;

}

}

public static void main(String… args) {

CallSite[] var1 = $getCallSiteArray();

GpathDemo.Foo foo = (GpathDemo.Foo)ScriptBytecodeAdapter

.castToType(var1[0].callConstructor(GpathDemo.Foo.class,

ScriptBytecodeAdapter.createMap(new Object[]{“bar”, “bar”})),

GpathDemo.Foo.class);

String var3 = “bar 2”;

ScriptBytecodeAdapter.setProperty(var3, (Class)null, foo, (String)“bar”);

var1[1].callStatic(GpathDemo.class, var1[2].callGetProperty(foo));

var1[3].callStatic(GpathDemo.class, var1[4].callGetProperty(foo));

}

读者可能已经注意到了,通过手动添加Getter,也可以利用GPath机制,用"."访问;

另外,读者可能也注意到:设置bar属性时,并未直接访问Setter,此处,我们可以动态的添加属性!

class GpathDemo {

static class Bar {

}

static void main(String[] args) {

Bar.metaClass.“getBaz” = { ->

return “baz”

}

Bar bar = new Bar()

println(bar.baz)

}

}

从编译结果看:

public static class Bar implements GroovyObject {

@Generated

public Bar() {

CallSite[] var1 = $getCallSiteArray();

super();

MetaClass var2 = this.$getStaticMetaClass();

this.metaClass = var2;

}

}

// main:

public static void main(String… args) {

CallSite[] var1 = $getCallSiteArray();

final class _main_closure1 extends Closure implements GeneratedClosure {

public _main_closure1(Object _outerInstance, Object _thisObject) {

CallSite[] var3 = $getCallSiteArray();

super(_outerInstance, _thisObject);

}

public Object doCall() {

CallSite[] var1 = $getCallSiteArray();

return “baz”;

}

}

_main_closure1 var4 = new _main_closure1(GpathDemo.class, GpathDemo.class);

ScriptBytecodeAdapter.setProperty(var4, (Class)null,

var1[5].callGetProperty(GpathDemo.Bar.class), (String)“getBaz”);

GpathDemo.Bar bar = (GpathDemo.Bar)ScriptBytecodeAdapter.castToType(

var1[6].callConstructor(GpathDemo.Bar.class),

GpathDemo.Bar.class);

var1[7].callStatic(GpathDemo.class, var1[8].callGetProperty(bar));

}

此时,在运行期增加了属性!

如果对Kotlin的扩展和代理比较熟悉,此处应该不难理解

但Groovy的设计更加有趣:

追踪:

  • org.codehaus.groovy.runtime.InvokerHelper#getProperty

  • org.codehaus.groovy.runtime.InvokerHelper#setProperty

发现会进入:GroovyObject,前面已经接触过

public interface GroovyObject {

Object invokeMethod(String var1, Object var2);

Object getProperty(String var1);

void setProperty(String var1, Object var2);

MetaClass getMetaClass();

void setMetaClass(MetaClass var1);

}

那么借助集合,如 Map ,并复写 getPropertysetProperty,就可以做一些有趣的事情

特殊的Expando类

哈哈,这个有趣的事情Groovy已经做了,这就是 Expando 类。

class ExpandoDemo {

static void main(String[] args) {

Expando expando = new Expando()

expando.foo = “foo”

println(expando.foo)

expando.bar = “bar”

println(expando.bar)

expando.properties.forEach(new BiConsumer() {

@Override

void accept(Object o, Object o2) {

println(“key: o , v a l u e : o,value: o,value:o2”)

}

})

}

}

Task :ExpandoDemo.main()

foo

bar

key:bar,value:bar

key:foo,value:foo

利用ExpandoMetaClass实现Mixin机制

Mixin 即 Mix In,混合, 我们可以笼统地认为:Mixin 即为 在一个类中混入其他类的内容

  • 对于支持多继承的语言,往往是在讨论 多继承 的问题;

  • 对于单继承的语言,Java是利用 接口 制造多继承的表现,基于 组合委托 等方式在目标类中 混入

规格继承 变相解决问题;Ruby 等语言则引入 Minin实现继承 变相解决问题。

我们不再对此概念进行纠缠,可以认为 “多继承语言可以解决很多问题并带来更多的关联问题,单继承语言想要好处又要规避坏处,部分语言提出了Minin机制”

而Groovy的Minin,除了 编译期 要能混入,还要 运行期混入

看个例子,虽然它的场景很不合理,你一定有一万种理由劝说我使用各类设计模式,但不要较真

class MixinDemo {

static class Paint {

def draw(Drawable drawable) {

println(“paint ${drawable.name}”)

}

}

static class Drawable {

String name

}

static void main(String[] args) {

def paint = new Paint()

Drawable.metaClass.draw = paint.&“draw”

def drawable = new Drawable(name: “test”)

drawable.draw(drawable)

}

}

例子中,我们动态的给Drawable添加了draw方法

如果我们将这一过程适当的封装:

class MixinDemo2 {

static class MixinDelegate {

private targetClass

MixinDelegate(targetClass) {

this.targetClass = targetClass

}

def mixin(String asMethodName, Closure closure) {

targetClass.metaClass.“$asMethodName” = closure

}

}

static void main(String[] args) {

def mixin = new MixinDelegate(MixinDemo.Drawable)

mixin.mixin(“draw”,new MixinDemo.Paint().&“draw”)

def drawable = new MixinDemo.Drawable(name: “test”)

drawable.draw(drawable)

}

}

这将会变得很有趣!!!

假设我们有一套 控制协议 ,在此之前,我们只能在编译期决定好 指令的执行 – 即控制协议实现,即使运用一些巧妙的设计模式,自由程度也很低, 但现在可以在运行时更为自由地扩展、修改

当然,结合前面的知识,我们可以让它更加的酷炫:

class MixinDemo3 {

static class MixinDsl implements GroovyInterceptable{

private targetClass

MixinDsl(targetClass) {

this.targetClass = targetClass

}

def invokeMethod(String s, o) {

if (s.startsWith(“mixinFun”) && s.length() > 8 && o[0] instanceof Closure) {

def methodName = s[8].toLowerCase() + s[9…-1]

targetClass.metaClass.“$methodName” = o[0]

return null

} else {

println(“cannot handle”)

}

}

}

static void main(String[] args) {

(new MixinDsl(MixinDemo.Drawable)).mixinFunDraw new MixinDemo.Paint().&“draw”

def drawable = new MixinDemo.Drawable(name: “test”)

drawable.draw(drawable)

}

}

此时,添加方法的写法呈现出 DSL的风格

运行时的其他修改

前面我们已经学习了在运行时给类添加方法,接下来再了解更多的内容:

添加构造器

这个例子要和Java进行对比

class RuntimeDemo {

static class Bean {

String a

String b

String c

String d

@Override

public String toString() {

return “Bean{” +

“a='” + a + ‘’’ +

“, b='” + b + ‘’’ +

“, c='” + c + ‘’’ +

“, d='” + d + ‘’’ +

‘}’;

}

}

static class ConstructorDemo {

void main() {

Bean.metaClass.constructor = { String a ->

new Bean(a: a, b: “b”, c: “c”, d: “d”)

}

def bean = new Bean(“a”)

println(bean)

}

}

static void main(String[] args) {

def bean = new Bean(a: “a”, b: “b”, c: “c”)

println(bean)

new ConstructorDemo().main()

}

}

本身Groovy允许我们在构造时设置属性值,但这并不是有重载的构造器!如果没有这个机制,我们就不得不建立一系列重载的构造器,或者老老实实赋值。

但Groovy可以添加构造器

添加静态方法

类比前面提到的添加方法,我们只需要添加关键字 static 就可以添加静态方法。

static void main(String[] args) {

GpathDemo.Foo.metaClass.‘static’.hello = { args1 ->

return “RuntimeDemo:hello,${args1}”

}

println GpathDemo.Foo.hello(“foo”)

}

为对象添加方法

前文已经介绍过给类添加方法,不再赘述。这里注意,我们可以单独给对象添加方法,而不累及该类的其他实例。

static void main(String[] args) {

def bean = new Bean(a: “a”, b: “b”, c: “c”)

//为对象添加方法

try {

bean.hello()

} catch(Exception e) {

println(e.message)

}

def emc = new ExpandoMetaClass(Bean.class, false)

emc.hello = { println “hello” }

emc.initialize()

bean.metaClass = emc

bean.hello()

try {

new Bean().hello()

} catch(Exception e) {

println(e.message)

}

}

很显然,第一次得到Exception,第二次正常打印hello,第三次得到Exception

自省

前文讲了如此之多的运行时修改,很显然,Groovy可以自省,我们简单了解一下以下知识,毕竟这些内容使用不多。

反射

Groovy承袭了Java,那么自然可以使用Java的反射,但是注意:

基于MOP添加的内容,均无法通过Java反射获知

respondsTo 和 hasProperty

class ResponseToDemo {

static class Demo {

def p = “p”

def foo() {

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
img

最后

有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~

偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!

深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-nPBB8VqH-1711871976678)]
[外链图片转存中…(img-QOfo3P4m-1711871976680)]
[外链图片转存中…(img-Hx0fm1Qm-1711871976681)]
[外链图片转存中…(img-dPiQ9HSW-1711871976682)]
[外链图片转存中…(img-yBhng9Sr-1711871976683)]
[外链图片转存中…(img-DqSw8WSY-1711871976684)]
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-ZvB0EYS2-1711871976684)]

最后

有任何问题,欢迎广大网友一起来交流,分享高阶Android学习视频资料和面试资料包~

偷偷说一句:群里高手如云,欢迎大家加群和大佬们一起交流讨论啊!

[外链图片转存中…(img-1osTvbTE-1711871976685)]

本文已被CODING开源项目:《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》收录

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值