因此,您应避免创建不需要的对象实例。一些可以帮助你理解的事例:
-
如果你有一个方法返回一个字符串,并且你知道它的结果总是被附加到一个StringBuffer,改变你的方法和实现,使函数直接追加,而不是创建一个短命的临时对象。
-
从一组输入数据中提取字符串时,尝试返回原始数据的子字符串,而不是创建副本。您将创建一个新的String对象,但它将与数据共享char []。 (如果您仅使用原始输入的一小部分,那么您的权衡将会在内存中保持一切,如果您使用这种方式)。
一个更激进的想法是将多维数组分解成并行的单维数组:
-
一个int数组比一个Integer对象的数组要好得多,但这也概括为两个并行的int数组也比一个(int,int)对象的数组更有效率。原始类型的任何组合也是如此。
-
如果您需要实现一个存储(Foo,Bar)对象的元组的容器,请尝试记住两个并行的Foo []和Bar []数组通常比单个数组的自定义(Foo,Bar)对象要好得多。 (当然,这是例外,当您为其他代码设计一个API时,在这种情况下,为了实现良好的API设计,通常情况下要做到一个小小的妥协,最好是在你的自己的内部代码,你应该尝试尽可能高效。)
一般来说,如果可以,避免创建短期临时对象。创建的对象越少意味着垃圾收集越少,直接影响用户体验。
2. Prefer Static Over Virtual
如果您不需要访问对象的字段,请使您的方法成为静态方式。 调用速度将快15%-20%。 这也是很好的做法,因为你可以从方法签名中得知调用该方法不能改变对象的状态。
3. 对于常量请使用:static final
考虑以下声明在一个类的顶部:
static int intVal = 42;
static String strVal =“Hello,world!”;
编译器生成一个类初始化方法,称为<clinit>
,它是在类首次使用时执行的。该方法将值42存储到intVal中,并从strfile的类文件字符串常量表中提取引用。当这些值稍后引用时,它们将通过字段查找进行访问。
我们可以通过“final”关键字改善这种方式:
static final int intVal = 42;
static final String strVal =“Hello,world!”;
该类不再需要一个<clinit>
方法,因为这些常量进入dex文件中的静态字段初始化器。引用intVal的代码将直接使用整数值42,并且对strVal的访问将使用相对便宜的“字符串常量”指令而不是字段查找。
注意:此优化仅适用于原始类型和字符串常量,而不适用于任意引用类型。不过,尽可能地声明常量static final
是个好习惯。
4.使用增强型循环语法
增强的for循环(有时也称为“for-each”循环)可用于实现Iterable接口和数组的集合。 使用集合,分配一个迭代器来对hasNext()和next()进行接口调用。 使用ArrayList,手写的计数循环速度大约比for-each快3倍(有或没有JIT),但对于其他集合,增强型循环语法将完全等同于显式迭代器使用。
有几种方法来迭代数组:
static class Foo {
int mSplat;
}
Foo[] mArray = …
public void zero() {
int sum = 0;
for (int i = 0; i < mArray.length; ++i) {
sum += mArray[i].mSplat;
}
}
public void one() {
int sum = 0;
Foo[] localArray = mArray;
int len = localArray.length;
for (int i = 0; i < len; ++i) {
sum += localArray[i].mSplat;
}
}
public void two() {
int sum = 0;
for (Foo a : mArray) {
sum += a.mSplat;
}
}
-
zero()是最慢的,因为JIT不能优化通过循环的每次迭代获得数组长度一次的成本。
-
one()更快。 它将所有内容都拉到局部变量中,避免查找。 只有阵列长度提供了性能优势。
-
对于没有JIT的设备,two()是最快的,并且对于具有JIT的设备与one()不可区分。 它使用Java编程语言
1.5
版中引入的增强型for循环语法。
所以,您应该默认使用增强型for循环,但考虑一个手写的计数循环,用于性能关键的ArrayList迭代(因为ArrayList的手写的计数循环比for-each快)。
5. Consider Package Instead of Private Access with Private Inner Classes
考虑以下类定义:
public class Foo {
private class Inner {
void stuff() {
Foo.this.doStuff(Foo.this.mValue);
}
}
private int mValue;
public void run() {
Inner in = new Inner();
mValue = 27;
in.stuff();
}
private void doStuff(int value) {
System.out.println("Value is " + value);
}
}
这里重要的是我们定义一个私有内部类(Foo $ Inner),它直接访问外部类中的私有方法和私有实例字段。 这是合法的,代码按预期打印“Value is 27”。
问题是VM考虑从Foo Inner直接访问Foo的私有成员是非法的,因为Foo和Foo Inner直接访问Foo的私有成员是非法的,因为Foo和Foo Inner是不同的类,尽管Java语言允许内部类访问外部类的私有成员。 为了弥合差距,编译器生成一些合成方法:
/package/ static int Foo.access$100(Foo foo) {
return foo.mValue;
}
/package/ static void Foo.access$200(Foo foo, int value) {
foo.doStuff(value);
}
内部类代码只要需要访问mValue字段或调用外部类中的doStuff()方法,就会调用这些静态方法。 这意味着上面的代码真的归结为通过访问器方法访问成员字段的情况。 早些时候我们讨论了访问者比直接访问访问速度慢,所以这是某种语言习语的一个例子,导致“看不见”的性能命中。
如果您在性能热点中使用这样的代码,则可以通过声明内部类访问的字段和方法来获取包访问权限而不是私有访问来避免开销。 不幸的是,这意味着可以在同一个包中的其他类直接访问这些字段,因此您不应该在公共API中使用。
6.避免使用float
Android核心知识点
面试成功其实是必然的,因为我做足了充分的准备工作,包括刷题啊,看一些Android核心的知识点,看一些面试的博客吸取大家面试的一些经验。
下面这份PDF是我翻阅了差不多3个月左右一些Android大博主的博客从他们那里取其精华去其糟泊所整理出来的一些Android的核心知识点,全部都是精华中的精华,我能面试到现在2-2资深开发人员跟我整理的这本Android核心知识点有密不可分的关系,在这里本着共赢的心态分享给各位朋友。
不管是Android基础还是Java基础以及常见的数据结构,这些是无原则地必须要熟练掌握的,尤其是非计算机专业的同学,面试官一上来肯定是问你基础,要是基础表现不好很容易被扣上基础不扎实的帽子,常见的就那些,只要你平时认真思考过基本上面试是没太大问题的。
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
参考docs.qq.com/doc/DSkNLaERkbnFoS0ZF
无原则地必须要熟练掌握的**,尤其是非计算机专业的同学,面试官一上来肯定是问你基础,要是基础表现不好很容易被扣上基础不扎实的帽子,常见的就那些,只要你平时认真思考过基本上面试是没太大问题的。
最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上我搜集整理的2019-2021BAT 面试真题解析,我把大厂面试中常被问到的技术点整理成了PDF,包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
参考docs.qq.com/doc/DSkNLaERkbnFoS0ZF