0005: return-void
在这里我们通过 SYNTHETIC
标签可以确定 lambda$main$0
方法是由系统自动生成的,并且看到了 lambda
实现的方法体 System.out.println
。
通过上面的流程分析,我们可以推测出:lambda
的实现保持在原来的主类中,并且是私有的,别的类无法直接访问。
4. Source Transformation(源码模拟实现)
为了更好的理解脱糖是如何工作的,我们可以在源码的层面模拟实现,注意这里的模拟仅仅是为了加深理解,脱糖实际工作比这个要复杂的多。
class Java8 {
interface Logger {
void log(String s);
}
public static void main(String… args) {
sayHi(s -> System.out.println(s));
}
private static void sayHi(Logger logger) {
logger.log(“Hello!”);
}
}
第一步将 lambda
表达式移到同级的包私有方法。
public static void main(String… args) {
- sayHi(s -> System.out.println(s));
- sayHi(s -> lambda$main$0(s));
} - static void lambda$main$0(String s) {
- System.out.println(s);
- }
第二步生成一个内部类实现 Logger
接口,并且它的方法体调用刚才实现的 lambda
方法。
public static void main(String… args) {
- sayHi(s -> lambda$main$0(s));
- sayHi(new Java8$1());
}
@@
}
+class Java8$1 implements Java8.Logger {
- @Override public void log(String s) {
- Java8.lambda$main$0(s);
- }
+}
最后,因为 lambda
方法并没有依赖外部的任何类,所以我们在 Java8$1
内部创建一个单例对象来避免每次调用 lambda
方法都生成一个新对象。
public static void main(String… args) {
- sayHi(new Java8$1());
- sayHi(Java8$1.INSTANCE);
}
@@
class Java8$1 implements Java8.Logger { - static final Java8$1 INSTANCE = new Java8$1();
@Override public void log(String s) {
最终我们经过脱糖生成的文件适用与所有 APIs
。
class Java8 {
interface Logger {
void log(String s);
}
public static void main(String… args) {
sayHi(Java8$1.INSTANCE);
}
static void lambda$main$0(String s) {
System.out.println(s);
}
private static void sayHi(Logger logger) {
logger.log(“Hello!”);
}
}
class Java8$1 implements Java8.Logger {
static final Java8$1 INSTANCE = new Java8$1();
@Override public void log(String s) {
Java8.lambda$main$0(s);
}
}
实际上你在查看 lambda
表达式生成的 Dalvik
字节码时可能看到不是类似 Java8$1
的名称,而是像这样的 -$$Lambda$Java8$QkyWJ8jlAksLjYziID4cZLvHwoY
名称,这是由于命名规范不恰当引起的。
5. Native Lambdas
在上面我们通过 dx
工具编译 dex
文件时,错误信息提示我们最低的支持版本是 API 26。
$ $ANDROID_HOME/build-tools/28.0.2/dx --dex --output . *.class
Uncaught translation error: com.android.dx.cf.code.SimException:
ERROR in Java8.main:([Ljava/lang/String;)V:
invalid opcode ba - invokedynamic requires --min-sdk-version >= 26
(currently 13)
1 error; aborting
所以如果我们在使用 D8
的时候指定 --min-api 26
版本,应该就不会报错了。
$ java -jar d8.jar
–lib $ANDROID_HOME/platforms/android-28/android.jar
–release
–min-api 26
–output .
*.class
同样为了查看 D8
如何工作,我们还是查看 Java8
类的字节码。
$ javap -v Java8.class
class Java8 {
public static void main(java.lang.String…);
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:log:()LJava8KaTeX parse error: Expected 'EOF', got '#' at position 26: … invokestatic #̲3 // Metho…Logger;)V
8: return
}
…
为了阅读方便我只截取了部分代码,但是我们同样可以在 main
方法中看到这里使用了 InvokeDynamic
指令,在 Code
表的 0
位置上,我们可以看到第二个参数是 0
,对应着 bootstrap method(引导方法)
。 bootstrap method
(引导方法)是当字节码第一次执行时首先被执行的一小段代码。
…
BootstrapMethods:
0: #27 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(
Ljava/lang/invoke/MethodHandlesKaTeX parse error: Expected 'EOF', got '#' at position 194: …hod arguments: #̲28 (Ljava/lang/…main$0:(Ljava/lang/String;)V
#28 (Ljava/lang/String;)V
在上面的代码中,bootstrap method
(引导方法)对应的是 java.lang.invoke.LambdaMetafactory 类中的 metafactory
方法。LambdaMetafactory
类在运行时为 lambda
表达式生成匿名类,而 D8
是在编译时生成。
如果我们查看 Android documentation for java.lang.invoke 和 AOSP source code for java.lang.invoke 的文档,我们可以注意到这个类在 Android Runtime
中不存在,这也是为什么脱糖在编译时要求最小版本的原因。VM
环境支持 invokedynamic
指令,但是 JDK 在编译 LambdaMetafactory 中却不可用。
6. Method References(方法引用)
除了 lambda
表达式,方法引用也是 Java 8
的语言特性,当 lambda
的实现是一个已经存在的方法,此时使用方法引用会很方便。
public static void main(String… args) {
- sayHi(s -> System.out.println(s));
- sayHi(System.out::println);
}
这与 javac
和 dexes
与 D8
的编译是相同的,与 lambda
版本有一个显著的区别。在编译为 dalvik
字节码时,生成的 lambda
类的主体已更改。
[000268] -KaTeX parse error: Can't use function '$' in math mode at position 7: Lambda$̲1Osqr2Z9OSwjseX…Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM;.f$0:Ljava/io/PrintStream;
0002: invoke-virtual {v0, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V
0005: return-void
不是通过生成 Java8.lambda$main$0
方法然后调用 System.out.println
的方式实现,而是直接调用 System.out.println
方法。lambda
表达式调用类也不是一个静态单例,而是直接使用 PrintStream
类实例引用,即 System.out
,它的调用如下。
[0002bc] Java8.main:([Ljava/lang/String;)V
0000: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream;
0003: new-instance v0, L-KaTeX parse error: Can't use function '$' in math mode at position 7: Lambda$̲1Osqr2Z9OSwjseX…Lambda
1
O
s
q
r
2
Z
9
O
S
w
j
s
e
X
0
F
M
Q
J
c
C
G
u
M
;
.
<
i
n
i
t
>
:
(
L
j
a
v
a
/
i
o
/
P
r
i
n
t
S
t
r
e
a
m
;
)
V
0008
:
i
n
v
o
k
e
−
s
t
a
t
i
c
v
0
,
L
J
a
v
a
8
;
.
s
a
y
H
i
:
(
L
J
a
v
a
8
1Osqr2Z9OSwjseX_0FMQJcCG_uM;.<init>:(Ljava/io/PrintStream;)V 0008: invoke-static {v0}, LJava8;.sayHi:(LJava8
1Osqr2Z9OSwjseX0FMQJcCGuM;.<init>:(Ljava/io/PrintStream;)V0008:invoke−staticv0,LJava8;.sayHi:(LJava8Logger;)V
同样我们也可以在源码级层面进行模拟。
public static void main(String… args) {
- sayHi(System.out::println);
- sayHi(new -$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM(System.out));
}
@@
}
+class -$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM implements Java8.Logger {
- private final PrintStream ps;
- -$$Lambda$1Osqr2Z9OSwjseX_0FMQJcCG_uM(PrintStream ps) {
- this.ps = ps;
- }
- @Override public void log(String s) {
- ps.println(s);
- }
+}
7. Interface Methods(接口中的方法)
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
如何成为Android高级架构师!
架构师必须具备抽象思维和分析的能力,这是你进行系统分析和系统分解的基本素质。只有具备这样的能力,架构师才能看清系统的整体,掌控全局,这也是架构师大局观的形成基础。 你如何具备这种能力呢?一是来自于经验,二是来自于学习。
架构师不仅要具备在问题领域上的经验,也需要具备在软件工程领域内的经验。也就是说,架构师必须能够准确得理解需求,然后用软件工程的思想,把需求转化和分解成可用计算机语言实现的程度。经验的积累是需要一个时间过程的,这个过程谁也帮不了你,是需要你去经历的。
但是,如果你有意识地去培养,不断吸取前人的经验的话,还是可以缩短这个周期的。这也是我整理架构师进阶此系列的始动力之一。
成为Android架构师必备知识技能
对应导图的学习笔记(由阿里P8大牛手写,我负责整理成PDF笔记)
部分内容展示
《设计思想解读开源框架》
- 目录
- 热修复设计
- 插件化框架设计
《360°全方面性能优化》
- 设计思想与代码质量优化
- 程序性能优化
jMg-1710851315437)]
- 插件化框架设计
[外链图片转存中…(img-9JazXoua-1710851315437)]
《360°全方面性能优化》
[外链图片转存中…(img-xf37droz-1710851315438)] - 设计思想与代码质量优化
[外链图片转存中…(img-rPkFdQQA-1710851315438)] - 程序性能优化
[外链图片转存中…(img-XjrNYbRU-1710851315438)]
本文在开源项目:【GitHub 】中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…