Long Luo's Life Notes

每一天都是奇迹

翻译 By Long Luo

下面这些问题Stackoverflow上关于Java collections提问和讨论最多的问题。在你阅读这些问题之前,有必要先阅读下这篇文章3分钟速读:图解Java Collections的接口以及类层级关系

1. 什么时候用LinkedList?什么时候用ArrayList?

ArrayList本质上是一个数组。它的元素可以直接通过索引值直接访问。但是如果数组已经满了,那么需要重新分配一个更大的数组并且将全部的元素移动到新的数组需要花费O(n)的时间。当然从现有的数组中增加或者删除一个元素都需要移动现有的元素。这个可能是使用ArrayList中最大的不便之处。

LinkedList是一个双端链表。正因为如此,如果要获取一个链表中间的元素,需要从链表的头部开始查找。另一方面,增加或者删除链表中的元素将会很快,因为只需要在本地修改即可。

下表总结了最快情况下的比较需要耗费时间:

MethodArraylistLinkedList
get(index)O(1)O(n)
add(E)O(n)O(1)
add(E, index)O(n)O(n)
remove(index)O(n)O(n)
Iterator.remove()O(n)O(1)
Iterator.add(E)O(n)O(1)

不管运行时间,当大型列表需要额外考虑内存占用。LinkedList每个node至少需要2个额外的指针用于连接前后2个node。而在ArrayList中只需要数组存储元素值即可。

2. 当遍历容器时,高效等价于移除元素的操作?

最正确的方式就是在遍历容器时用Iterator.remove()去修改一个容器,如下代码所示:

1
2
3
4
5
Iterator<Integer> itr = list.iterator();
while(itr.hasNext()) {
// do something
itr.remove();
}

另外一个非常高频的使用但是不正确的代码是这样的:

1
2
3
for(Integer i: list) {
list.remove(i);
}

运行上面的代码时你会得到一个ConcurrentModificationException。原因是因为一个迭代器自生成之后(在for循环中),用于横贯这个列表。与此同时,这个列表同时也被Iterator.remove()修改了。在Java语言中,当一个线程在修改一个容器时而另外一个线程在遍历它是不允许的。

3. 如何将List转换成int[]?

最快捷的方式可能是用Apache Commons Lang库中的ArrayUtils

1
int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));

在JDK中,没有快捷方式。请注意你不能使用List.toArray(),因为那会将列表转换成Integer[]。正确的方式应该是这样的:

1
2
3
4
int[] array = new int[list.size()];
for(int i=0; i < list.size(); i++) {
array[i] = list.get(i);
}
阅读全文 »

本文将展示Java Array的最重要的10个方法:

0. 声明一个数组

1
2
3
String[] aArray = new String[5];
String[] bArray = {"a","b","c", "d", "e"};
String[] cArray = new String[]{"a","b","c","d","e"};

1. 打印数组

1
2
3
4
5
6
7
8
9
int[] intArray = { 1, 2, 3, 4, 5 };
String intArrayString = Arrays.toString(intArray);

// print directly will print reference value
System.out.println(intArray);
// [I@7150bd4d

System.out.println(intArrayString);
// [1, 2, 3, 4, 5]

2. 从一个数组中创建一个ArrayList

1
2
3
4
String[] stringArray = { "a", "b", "c", "d", "e" };
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(stringArray));
System.out.println(arrayList);
// [a, b, c, d, e]

3. 判断数组中是否包含一个特定的值

1
2
3
4
String[] stringArray = { "a", "b", "c", "d", "e" };
boolean b = Arrays.asList(stringArray).contains("a");
System.out.println(b);
// true

4. 连接2个数组

1
2
3
4
int[] intArray = { 1, 2, 3, 4, 5 };
int[] intArray2 = { 6, 7, 8, 9, 10 };
// Apache Commons Lang library
int[] combinedIntArray = ArrayUtils.addAll(intArray, intArray2);

5. 声明一个inline数组

1
method(new String[]{"a", "b", "c", "d", "e"});

6. 将一个数组中元素变成一个字符串

1
2
3
4
5
// containing the provided list of elements
// Apache common lang
String j = StringUtils.join(new String[] { "a", "b", "c" }, ", ");
System.out.println(j);
// a, b, c
阅读全文 »

Java语言中,String一直很基础,但很多人都很多概念还是很模糊。这里我们选取了网络上最常见的10个问题,希望通过这篇文章让大家对Java String有更深刻的认识。

1. 如何对字符串进行比较?用“==” 还是equals()

简单来说,如果引用是否相同那么使用==, 判断值是否相等则用equals()。除非你想判断2个字符串是否是同一对象,否则你都应该使用equals()

2. 为什么在安全敏感信息场合应该用char[]而不是string?

String具有不可变的特性,当字符串一旦被创建,那么知道垃圾收集器处理之前他们都是不可变的。如果使用数组,那么你可以明确地改变其内部单元数据。因此,安全敏感的信息例如密码不应该在系统中任何时候都存在。

3. 我们可以在switch语句中使用string吗?

是的,在Java 7中可以!JDK7中,我们可以在switch中使用string。但是之前的Java版本是不可以的。

1
2
3
4
5
6
7
8
9
10
// java 7 only!
switch(str.toLowerCase()){
case "a":
value = 1;
break;

case "b":
value = 2 ;
break;
}

4. 如何将字符转成Int类型?

1
int n = Integer.parseInt("10");

就是这样简单!

5. 如何用白色空格字符分离一个字符串?

可以使用正则表达式分离字符串。““表示白色空格字符比如” “,”“。

1
String [] strArray = aString.split("\\s+");

6. substring()这个方法起什么作用?

在JDK6中,substring()方法并不会创建一个新的字符数组,而是给现存的字符串一个窗口用于表示当前字符串。如果想用一个新的字符数组来表示新的字符串,你可以加一个空支付串来实现,如下所示:

1
str.substring(m, n) + ""

使用上述方法,会创建一个新的字符数组来表示新的字符串。有时候可以让你的代码更快,因为垃圾收集器会收集一些没有使用的大字符串但子字符串确实保留的。

JDK7中,substring()会创建一个新的字符数组,而不是使用现在的这个。

阅读全文 »

By Long Luo

Android中自定义控件一直都是Android开发中的一个难点。

最近看大牛 @Tomcat的猫 写的 《Android群英传》 里面的第六章Android绘图机制及处理技巧,里面通过Canvas实现了一个如下所示的仪表盘:

仪表盘

在书中详细描述了如何实现这个仪表盘,这里就不赘述了,可以参考其 具体实现代码

但是这个表盘的指针是静止不动的,如果我们能让这个表盘的指针展示当前时间,随着时间而转动,那么我们就可以一款模拟时钟了。

那么,问题就来了:

如何才能让时钟的指针动起来呢?

这个问题,我们可以考虑分为2步去实现,第一步先绘制出当前的时间,第二部再让指针动起来。通过这样我们就可以实现一款模拟时钟

一、绘制当前时间

1.1 获取当前时间

要绘制当前时间,我们要先获取当前时间。

1
mTime.setToNow();

1.2 获取指针角度

当前时间可分为时,分,秒

我们最终要获取的是时分秒3个指针对应的精确角度

秒针角度:最简单,直接乘以6即可获得。 分针角度:当前分钟 * 6 + 6 * 秒 / 60F 时针角度:(当前小时 % 12) * 30 + 30 * 当前分钟角度 / 360F;

1.3 绘制指针

获取到指针角度之后,接下来就是在表盘绘制指针了。这里我们要利用canvas.rotate()这个方法来实现绘制指针,具体实现代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private void drawTime(Canvas canvas) {
// 当前时间
mTime.setToNow();

// 当前时间对应的角度
float secRot = mTime.second * 6;
float minRot = mTime.minute * 6 + 6 * mTime.second / 60F;
float hrRot = (mTime.hour % 12) * 30 + 30 * minRot / 360F;

Log.d(TAG, "hrRot=" + hrRot + ",minRot=" + minRot + ",secRot=" + secRot);

// 画指针
Paint paintHour = new Paint();
paintHour.setStrokeWidth(20);
Paint paintMinute = new Paint();
paintMinute.setStrokeWidth(10);
Paint paintSecond = new Paint();
paintSecond.setStrokeWidth(5);

canvas.save();

// 时针
canvas.rotate(hrRot, mWidth / 2, mHeight / 2);
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 320,
paintHour);
canvas.rotate(-hrRot, mWidth / 2, mHeight / 2);

// 分针
canvas.rotate(minRot, mWidth / 2, mHeight / 2);
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 230,
paintMinute);
canvas.rotate(-minRot, mWidth / 2, mHeight / 2);

// 秒针
canvas.rotate(secRot, mWidth / 2, mHeight / 2);
canvas.drawLine(mWidth / 2, mHeight / 2, mWidth / 2, mHeight / 2 - mWidth / 2 + 150,
paintSecond);
canvas.rotate(-secRot, mWidth / 2, mHeight / 2);

canvas.restore();
}
阅读全文 »

By Long Luo

前言

随着 VR 产业渐渐进入人们的视线,VR热潮正处于爆发前期。纵观国内几家VR领域的尖端企业,中国的VR硬件与国际水准相比并不低。如果以“国际标准”Oculus的VR硬件来说,可以说与其基本持平。对于过国内广大普通产品使用者来说无疑是个好消息,国内的VR团队在保持硬件的技术过关的前提下,性价比颇高。

然而,就算是最尖端的VR产品,目前依旧有致命的“硬伤”:晕眩感太强

很多VR体验者表示,在一段时间使用VR产品后,会出现不适,恶心,甚至呕吐。这成为了VR前进的最大的一个绊脚石,解决晕眩问题成为VR的燃眉之急

因此我们有必要对VR晕眩有一个更深入的了解,那么下面我们将详细讲解VR晕眩及目前市场上解决晕眩的一些技术

一、为什么会产生VR晕眩?

VR眩晕感根本原因是视觉大脑对运动的认知不同步,具体点就是眼睛看到的(VR)画面与从耳朵接收到的(真实位置)信息不匹配,导致脑负担加大,从而产生晕眩感。

VR眩晕有硬件引起的晕眩和软件引起的晕眩。

1. 硬件晕眩

VR硬件带来的晕眩主要是4个地方:GPU、感应器、显示屏、芯片成像透镜,以及瞳距和距离调整结构

解决硬件晕眩也很简单,使用最好的硬件就可以尽可能减少解决硬件层面的晕眩。但是现阶段消费者认为众多VR硬件是不成熟的呢?原因是因为厂商从成本的角度考虑,将VR设备的“性价比”做得更高一些。

如果从硬件层面着手试图消除眩晕的问题,一方面需要硬件市场降低成本,另外一方面还需要产业链的供给。    从设备的角度来说,硬件和软件设计的不合理造成了晕眩,那么解决方案也是从这两方面入手。目前来看,各大厂商都提出了自己的办法。硬件能发挥的作用更大一些,但也绝不能孤立来看。    ## 2. 软件晕眩

软件晕眩的概念就比较大了。

VR晕眩有以下几大原因:

<1>. 游戏内容

很多VR游戏,本身的内容就会产生晕眩。比如说你在坐“VR 过山车”时,视觉上你正处于画面中的状态,在做剧烈的高速运动,但是前庭系统却表示你并没有在运动,这时就会导致头晕。

<2>. 画面与现实世界的差异

VR显示器给出的画面变形严重、视野小,这些都与现实世界有差异,时间长了就会感觉头晕。

<3>. 画面滞后于动作

VR硬件的延迟造成时间上的不同步,当人转动视角或是移动的时候,画面呈现的速度跟不上,在VR这样全视角的屏幕中,这样的延迟是造成晕眩的最大问题,目前降低延迟是当下减弱VR眩晕的主要手段。

在VR这样全视角的屏幕中,这样的延迟是造成晕眩的最大问题。

<4>. 瞳距不一

由于每个人的瞳距不一,对某些人来说,人眼瞳孔中心、透镜中心、画面中心三点并非一线,从而出现重影现象,看久了人也会非常容易头晕。

<5>. 景深不同步

景深不同步,也是眩晕的原因之一。比如说,在你的面前,有一张桌子,在桌子上,近处放了一个杯子,远处放了一个玩偶。你看着近处的杯子,按理来说远处的玩偶应该模糊不清,但是现在,远处的玩偶也看的非常清晰。

总的来说,VR 设备对现实的模拟不够真实,还无法真正地欺骗到大脑,受到困扰的大脑不堪重负,才会造成眩晕的问题。

阅读全文 »
0%