应届生面试硬件工程师回问哪些问题,深入学习-Gradle-自动化构建技术(1),阿里P8大佬亲自讲解

// 代表闭包定义处的类
printlin “scriptClouser” this:" + this
// 代表闭包定义处的类或者对象
printlin “scriptClouser” this:" + owner
// 代表任意对象,默认与 ownner 一直
printlin “scriptClouser” this:" + delegate
}
innnerClouser.call()
}

// this 输出的是 nestClouser 对象,而 owner 与 delegate 输出的都是 innnerClouser 对象
nestClouser.call()

可以看到,如果我们直接在类、方法、变量中定义一个闭包,那么这三种关键变量的值都是一样的,但是,如果我们在闭包中又嵌套了一个闭包,那么,this 与 owner、delegate 的值就不再一样了。换言之,this 还会指向我们闭包定义处的类或者实例本身,而 owner、delegate 则会指向离它最近的那个闭包对象

delegate 与 this、owner 的差异

其差异代码如下代码所示:

def nestClouser = {
def innnerClouser = {
// 代表闭包定义处的类
printlin “scriptClouser” this:" + this
// 代表闭包定义处的类或者对象
printlin “scriptClouser” this:" + owner
// 代表任意对象,默认与 ownner 一致
printlin “scriptClouser” this:" + delegate
}

// 修改默认的 delegate
innnerClouser.delegate = p
innnerClouser.call()
}

nestClouser.call()

可以看到,delegate 的值是可以修改的,并且仅仅当我们修改 delegate 的值时,delegate 的值才会与 ownner 的值不一样

闭包的委托策略

其示例代码如下所示:

def stu = new Student()
def tea = new Teacher()
stu.pretty.delegate = tea
// 要想使 pretty 闭包的 delegate 修改生效,必须选择其委托策略为 Closure.DELEGATE_ONLY,默认是 Closure.OWNER_FIRST。
stu.pretty.resolveStrategy = Closure.DELEGATE_ONLY
println stu.toString()

需要注意的是,要想使上述 pretty 闭包的 delegate 修改生效,必须选择其委托策略为 Closure.DELEGATE_ONLY,默认是 Closure.OWNER_FIRST 的。

3、Groovy 数据结构

Groovy 常用的数据结构有如下 四种:

  • 1)、数组
  • 2)、List
  • 3)、Map
  • 4)、Range

数组的使用和 Java 语言类似,最大的区别可能就是定义方式的扩展,如下代码所示:

// 数组定义
def array = [1, 2, 3, 4, 5] as int[]
int[] array2 = [1, 2, 3, 4, 5]

下面,我们看看其它三种数据结构。

1、List

即链表,其底层对应 Java 中的 List 接口,一般用 ArrayList 作为真正的实现类,List 变量由[]定义,其元素可以是任何对象

链表中的元素可以通过索引存取,而且 不用担心索引越界。如果索引超过当前链表长度,List 会自动往该索引添加元素。下面,我们看看 Map 最常使用的几个操作。

1)、排序

def test = [100, “hello”, true]
// 左移位表示向List中添加新元素
test << 200
// list 定义
def list = [1, 2, 3, 4, 5]
// 排序
list.sort()
// 使用自己的排序规则
sortList.sort { a, b ->
a == b ?0 :
Math.abs(a) < Math.abs(b) ? 1 : -1
}

2)、添加

// 添加
list.add(6)
list.leftShift(7)
list << 8

3)、删除

// 删除
list.remove(7)
list.removeAt(7)
list.removeElement(6)
list.removeAll { return it % 2 == 0 }

4)、查找

// 查找
int result = findList.find { return it % 2 == 0 }
def result2 = findList.findAll { return it % 2 != 0 }
def result3 = findList.any { return it % 2 != 0 }
def result4 = findList.every { return it % 2 == 0 }

5)、获取最小值、最大值

// 最小值、最大值
list.min()
list.max(return Math.abs(it))

6)、统计满足条件的数量

// 统计满足条件的数量
def num = findList.count { return it >= 2 }

Map

表示键-值表,其 底层对应 Java 中的 LinkedHashMap

Map 变量由[:]定义,冒号左边是 key,右边是 Value。key 必须是字符串,value 可以是任何对象。另外,key 可以用 ‘’ 或 “” 包起来,也可以不用引号包起来。下面,我们看看 Map 最常使用的几个操作。

1)、存取

其示例代码如下所示:

aMap.keyName
aMap[‘keyName’]
aMap.anotherkey = “i am map”
aMap.anotherkey = [a: 1, b: 2]

2)、each 方法

如果我们传递的闭包是一个参数,那么它就把 entry 作为参数。如果我们传递的闭包是 2 个参数,那么它就把 key 和 value 作为参数。

def result = “”
[a:1, b:2].each { key, value ->
result += “ k e y key keyvalue”
}

assert result == “a1b2”

def socre = “”
[a:1, b:2].each { entry ->
result += entry
}

assert result == “a=1b=2”

3)、eachWithIndex 方法

如果闭包采用两个参数,则将传递 Map.Entry 和项目的索引(从零开始的计数器);否则,如果闭包采用三个参数,则将传递键,值和索引。

def result = “”
[a:1, b:3].eachWithIndex { key, value, index -> result += “ i n d e x ( index( index(key$value)” }
assert result == “0(a1)1(b3)”

def result = “”
[a:1, b:3].eachWithIndex { entry, index -> result += “ i n d e x ( index( index(entry)” }
assert result == “0(a=1)1(b=3)”

4)、groupBy 方法

按照闭包的条件进行分组,代码如下所示:

def group = students.groupBy { def student ->
return student.value.score >= 60 ? ‘及格’ : ‘不及格’
}

5)、findAll 方法

它有两个参数,findAll 会将 Key 和 Value 分别传进 去。并且,如果 Closure 返回 true,表示该元素是自己想要的,如果返回 false 则表示该元素不是自己要找的。

Range

表示范围,它其实是 List 的一种拓展。其由 begin 值 + 两个点 + end 值表示。如果不想包含最后一个元素,则 begin 值 + 两个点 + < + end 表示。我们可以通过 aRange.from 与 aRange.to 来获对应的边界元素

如果需要了解更多的数据结构操作方法,我们可以直接查 Groovy API 详细文档 即可。

4、Groovy 面向对象

如果不声明 public/private 等访问权限的话,Groovy 中类及其变量默认都是 public 的

1)、元编程(Groovy 运行时)

Groovy 运行时的逻辑处理流程图如下所示:

为了更好的讲解元编程的用法,我们先创建一个 Person 类并调用它的 cry 方法,代码如下所示:

// 第一个 groovy 文件中
def person = new Person(name: ‘Qndroid’, age: 26)
println person.cry()

// 第二个 groovy 文件中
class Person implements Serializable {

String name

Integer age

def increaseAge(Integer years) {
this.age += years
}

/**

  • 一个方法找不到时,调用它代替
  • @param name
  • @param args
  • @return
    */
    def invokeMethod(String name, Object args) {

return “the method is ${name}, the params is ${args}”
}

def methodMissing(String name, Object args) {

return “the method ${name} is missing”
}
}

为了实现元编程,我们需要使用 metaClass,具体的使用示例如下所示:

ExpandoMetaClass.enableGlobally()
//为类动态的添加一个属性
Person.metaClass.sex = ‘male’
def person = new Person(name: ‘Qndroid’, age: 26)
println person.sex
person.sex = ‘female’
println “the new sex is:” + person.sex
//为类动态的添加方法
Person.metaClass.sexUpperCase = { -> sex.toUpperCase() }
def person2 = new Person(name: ‘Qndroid’, age: 26)
println person2.sexUpperCase()
//为类动态的添加静态方法
Person.metaClass.static.createPerson = {
String name, int age -> new Person(name: name, age: age)
}
def person3 = Person.createPerson(‘renzhiqiang’, 26)
println person3.name + " and " + person3.age

需要注意的是通过类的 metaClass 来添加元素的这种方式每次使用时都需要重新添加,幸运的是,我们可以在注入前调用全局生效的处理,代码如下所示:

ExpandoMetaClass.enableGlobally()
// 在应用程序初始化的时候我们可以为第三方类添加方法
Person.metaClass.static.createPerson = { String name,
int age ->
new Person(name: name, age: age)
}

2)、脚本中的变量和作用域

对于每一个 Groovy 脚本来说,它都会生成一个 static void main 函数,main 函数中会调用一个 run 函数,脚本中的所有代码则包含在 run 函数之中。我们可以通过如下的 groovyc 命令用于将编译得到的 class 文件拷贝到 classes 文件夹下:

// groovyc 是 groovy 的编译命令,-d classes 用于将编译得到的 class 文件拷贝到 classes 文件夹 下
groovyc -d classes test.groovy

当我们在 Groovy 脚本中定义一个变量时,由于它实际上是在 run 函数中创建的,所以脚本中的其它方法或其他脚本是无法访问它的。这个时候,我们需要使用 @Field 将当前变量标记为成员变量,其示例代码如下所示:

import groovy.transform.Field;

@Field author = JsonChao

四、文件处理

1、常规文件处理

1)、读文件

eachLine 方法

我们可以使用 eachLine 方法读该文件中的每一行,它唯一的参数是一个 Closure,Closure 的参数是文件每一行的内容。示例代码如下所示:

def file = new File(文件名)
file.eachLine{ String oneLine ->
println oneLine
}

def text = file.getText()
def text2 = file.readLines()

file.eachLine { oneLine, lineNo ->
println “${lineNo} ${oneLine}”
}

然后,我们可以使用 ‘targetFile.bytes’ 直接得到文件的内容。

使用 InputStream

此外,我们也可以通过流的方式进行文件操作,如下代码所示:

//操作 ism,最后记得关掉
def ism = targetFile.newInputStream()
// do sth
ism.close

使用闭包操作 inputStream

利用闭包来操作 inputStream,其功能更加强大,推荐使用这种写法,如下所示:

targetFile.withInputStream{ ism ->
// 操作 ism,不用 close。Groovy 会自动替你 close
}

2)、写文件

关于写文件有两种常用的操作形式,即通过 withOutputStream/withInputStream 或 withReader/withWriter 的写法。示例代码如下所示:

通过 withOutputStream/、withInputStream copy 文件

def srcFile = new File(源文件名)
def targetFile = new File(目标文件名) targetFile.withOutputStream{ os->
srcFile.withInputStream{ ins->
os << ins //利用 OutputStream 的<<操作符重载,完成从 inputstream 到 OutputStream //的输出
}
}

通过 withReader、withWriter copy 文件

def copy(String sourcePath, String destationPath) {
try {
//首先创建目标文件
def desFile = new File(destationPath)
if (!desFile.exists()) {
desFile.createNewFile()
}

//开始copy
new File(sourcePath).withReader { reader ->
def lines = reader.readLines()
desFile.withWriter { writer ->
lines.each { line ->
writer.append(line + “\r\n”)
}
}
}
return true
} catch (Exception e) {
e.printStackTrace()
}
return false
}

此外,我们也可以通过 withObjectOutputStream/withObjectInputStream 来保存与读取 Object 对象。示例代码如下所示:

保存对应的 Object 对象到文件中

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

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

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

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

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

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

学习福利

【Android 详细知识点思维脑图(技能树)】

其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。

虽然 Android 没有前几年火热了,已经过去了会四大组件就能找到高薪职位的时代了。这只能说明 Android 中级以下的岗位饱和了,现在高级工程师还是比较缺少的,很多高级职位给的薪资真的特别高(钱多也不一定能找到合适的),所以努力让自己成为高级工程师才是最重要的。

这里附上上述的面试题相关的几十套字节跳动,京东,小米,腾讯、头条、阿里、美团等公司19年的面试题。把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节。

由于篇幅有限,这里以图片的形式给大家展示一小部分。

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

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

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

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

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值