Open creeperyang opened 6 years ago
厉害了老哥
下载 AndroidStudio,创建一个项目并编译,了解基本的流程。
Gradle 是一个基于 JVM 的构建工具,基于 groovy,有强大的依赖管理,支持多工程构建。
projects 和 tasks是 Gradle 中最重要的两个概念。
1、创建任务
1.1、创建一个最简单的task(build.gradle文件):
task hello {
doLast {
println 'Hello world!'
}
}
我们可以执行gradle -q hello
查看输出:
$ gradle -q hello
Hello world!
1.2、快速定义task:
task hello << {
println 'Hello world!'
}
// << 等同于 doLast
1.3、使用groovy
task upper << {
String someString = 'mY_nAmE'
println "Original: " + someString
println "Upper case: " + someString.toUpperCase()
}
$ gradle -q upper
Original: mY_nAmE
Upper case: MY_NAME
2、任务依赖
2.1、 在两个任务之间指明依赖关系
task hello << {
println 'Hello world!'
}
task intro(dependsOn: hello) << {
println "I'm Gradle"
}
$ gradle -q intro
Hello world!
I'm Gradle
2.2、延迟依赖
taskX 是可以在 taskY 之前定义的。
task taskX(dependsOn: 'taskY') << {
println 'taskX'
}
task taskY << {
println 'taskY'
}
3、动态任务
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
// gradle -q task1
4、任务操纵
4.1、通过 API 进行任务之间的通信 - 增加依赖
4.times { counter ->
task "task$counter" << {
println "I'm task number $counter"
}
}
task0.dependsOn task2, task3
4.2、通过 API 进行任务之间的通信 - 增加任务行为
task hello << {
println 'Hello Earth'
}
hello.doFirst {
println 'Hello Venus'
}
hello.doLast {
println 'Hello Mars'
}
hello << {
println 'Hello Jupiter'
}
doFirst 和 doLast 可以进行多次调用。他们分别被添加在任务的开头和结尾。当任务开始执行时这些动作会按照既定顺序进行。
5、短标记法
每个任务都是一个脚本的属性,你可以访问它。
以属性的方式访问任务:
task hello << {
println 'Hello world!'
}
hello.doLast {
println "Greetings from the $hello.name task."
}
// $hello.name 就是 “hello”
6、增加自定义属性
task myTask {
ext.myProperty = "myValue"
}
task printTaskProperties << {
println myTask.myProperty
}
7、调用 Ant 任务
Ant 任务是 Gradle 中的一等公民。Gradle 自带了一个 AntBuilder,可以通过它来调用一个 Ant 任务以及与 Ant 中的属性进行通信。
task loadfile << {
def files = file('../antLoadfileResources').listFiles().sort()
files.each { File file ->
if (file.isFile()) {
ant.loadfile(srcFile: file, property: file.name)
println " *** $file.name ***"
println "${ant.properties[file.name]}"
}
}
}
8、方法抽取
task checksum << {
fileList('../antLoadfileResources').each {File file ->
ant.checksum(file: file, property: "cs_$file.name")
println "$file.name Checksum: ${ant.properties["cs_$file.name"]}"
}
}
task loadfile << {
fileList('../antLoadfileResources').each {File file ->
ant.loadfile(srcFile: file, property: file.name)
println "I'm fond of $file.name"
}
}
File[] fileList(String dir) {
file(dir).listFiles({file -> file.isFile() } as FileFilter).sort()
}
9、定义默认任务
defaultTasks 'clean', 'run'
task clean << {
println 'Default Cleaning!'
}
task run << {
println 'Default Running!'
}
task other << {
println "I'm not a default task!"
}
$ gradle -q
Default Cleaning!
Default Running!
以上是一些gradle的基础小知识,下面以android项目为例,了解gradle实际是怎么工作的。
一、前置Java知识
Java 是一门强类型的面向对象的解释型语言,通过JVM可以在多平台运行。
1. 基础类型
8种内置类型,六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型:
byte
:8位,有符号整数,-128(-2^7)-- 127(2^7-1);short
:16位,有符号整数,-32768(-2^15)-- 32767(2^15 - 1);int
:32位,有符号整数,-2,147,483,648(-2^31)-- 2,147,483,647(2^31 - 1);long
:64位,有符号整数,-9,223,372,036,854,775,808(-2^63)-- 9,223,372,036,854,775,807(2^63 -1);float
:32位、单精度、符合IEEE 754标准的浮点数,不能表示精确的值,如货币;double
:64位、双精度、符合IEEE 754标准的浮点数,不能表示精确的值,如货币;boolean
:1位,只有两个取值:true和false;char
:16位,表示Unicode字符,最小值是’\u0000’(即为0),最大值是’\uffff’(即为65,535)。引用类型
对象、数组都是引用数据类型,所有引用类型的默认值都是null。
对前端而言,需要额外注意两点:
变量一旦声明,则类型确定,且不能更改(不能赋值其它类型)。
char 和 String 的区别:char是基本类型,对应一个字符;String 是引用类型,对应0或多个字符。
char a = 'a'; String x = "hi!";
2. 基本语法
MyFirstJavaClass
。public static void main(String args[])
方法开始执行。总的来说,Java基本语法和一般程序语言的语法一致。相比JS,我们可能要注意 修饰符,接口等概念。
循环
和JS基本一致;不过可以注意下增强的for循环:
for(声明语句 : 表达式)
中表达式为数组。分支
与JS一致。
3. 类和对象
对象是类的一个实例,有状态和行为。类可以看成是创建Java对象的模板。一个类可以包含以下类型变量:
每个类都有构造方法。如果没有显式为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。
源文件声明规则
Java包
包主要用来对类和接口进行分类。我们用
package pkgName
来声明包,用import java.io.*
来引入包。4. 修饰符(访问控制及其它)
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限。
默认的,也称为default,在同一包内可见,不使用任何修饰符。 接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public。
私有的,以private修饰符指定,在同一类内可见。 私有访问修饰符是最严格的访问级别,所以被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。
公有的,以public修饰符指定,对所有类可见。 被声明为public的类、方法、构造方法和接口能够被任何其他类访问。
受保护的,以protected修饰符指定,对同一包内的类和所有子类可见。 被声明为protected的变量、方法和构造器能被同一个包中的任何其他类访问,也能够被不同包中的子类访问。
protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。
子类能访问protected修饰符声明的方法和变量。
访问控制和继承
父类中声明为public的方法在子类中也必须为public。
父类中声明为protected的方法在子类中要么声明为protected,要么声明为public。不能声明为private。
父类中默认修饰符声明的方法,能够在子类中声明为private。
父类中声明为private的方法,不能够被继承。
非访问修饰符
为了实现一些其他的功能,Java也提供了许多非访问修饰符。
static修饰符,用来创建类方法和类变量。
final修饰符,用来修饰类、方法和变量,final修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
abstract修饰符,用来创建抽象类和抽象方法。
synchronized和volatile修饰符,主要用于线程的编程。
5. Java 的继承与接口
Java是完全面向对象的语言,继承是最重要的topic。Java只有单继承(相比多继承,减少复杂度和潜在的一些问题(比如函数重写)),但通过接口来保留多继承的一些优点。
典型的继承语法:
子类可以从父类继承所有的 protected/public 属性和方法。
我们知道,JS 中,基于原型链的继承机制,所有实例的方法调用的方法最终都指向原型(链)的某个方法,即方法在内存中只有一份,那在Java中一样吗?
答案是:是。
在Java中 new 一个对象时,为类的成员(包括(继承的)父类的成员)分配了内存空间,然后执行构造函数,初始化这些属性的值。
但对象并不会为方法分配内存,当调用对象的方法时,实质上是去方法区查找到对应的方法执行。
静态方法和私有方法在解析阶段确定唯一的调用版本,而其它实例方法,会去动态查找(沿继承链)。
参考:
6. Java 泛型
泛型类
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:List、Set、Map。
泛型类的定义:
例子:
泛型的类型参数只能代表引用型类型,不能是原始类型(像int,double,char等)
泛型接口
泛型方法
泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。
有界的类型参数:
可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。
7. Java 多线程编程
8. Java 内存模型
源于同事的一次分享,查阅资料了解了Java虚拟机和内存管理相关知识。利于深入了解Java,对比JS可能有更大收获。
Run-Time Data Areas
堆区:存放所有类实例(对象)和数组,虚拟机启动时创建。由GC自动管理。
方法区(Method area and runtime constant pool):存放类的结构信息,虚拟机启动时创建。类似于传统语言中存放编译后代码的地方,它存放类的 (1)run-time constant pool(类似传统语言的符号表+其它),(2)成员和方法信息,(3)静态变量,(4)方法的代码等等。
虽然逻辑上来说,方法区也是堆的一部分,不过方法区一般不被GC管理(取决于JVM的具体实现)。
JVM Stack:每个Java线程创建时都会创建一个私有的JVM Stack,存储局部变量和部分结果,参与函数调用和返回。Stack本身只负责存储(push/pop)frames,frame 对应方法,负责存数据和部分结果,执行动态链接,返回方法的值或者dispatch异常。
Native Method Stacks:线程私有,但不是所有JVM都实现了。类似JVM Stack,用于执行 Native 方法服务。
frame通常包含:
PC register:线程私有。每个JVM线程都有自己的pc register,在任意时刻,每个线程都是在执行一个方法(记作 current method)。如果这个方法不是native的,那么pc register存着当前执行的JVM指令的地址;否则pc register的值是undefined。