public static void man

_hope is a good thing

iOS Programming 4(Views and the View Hierarchy)

| Comments

View Basics

在iOS中,每一个应用都有一个UIWindow的对象,他是应用中所有view的容器(container),其实UIWindow自己也只是一个view,只不过他的职责不是显示view,而是作为容器存放view。当应用启动的时候,这个对象就被创建,我们可以往这个容器里面添加其他的view。那么什么是view呢?他是在屏幕上被显示的元素,例如button。每一个view都是UIView或UIView的子类的一个实例,每一个view都有一个对应的layer,view在其对应的那样儿上显示自己,我们可以想象成每个view都自带了一块画板,在画板上作画然后贴到最大的canvas(UIWindow)上去。view还能handle屏幕上的一些事件,例如button能handle touch事件。view之间存在层级关系(hierarchy),一个view可以包含另一个view,我们可以把其中的关系想象成一棵树,根结点就是UIWindow。

iOS Programming 3(Managing Memory Wih ARC)

| Comments

栈和堆

当一个方法被执行的时候,系统会从栈中分配出一定的内存让代码在其中运行,这一块专门分配出来的内存叫做frame,每一个方法都有一个frame。当方法从main方法中开始执行的时候,main方法的frame被放到了栈上,然后如果在main方法中有其他方法的调用,就会有不断的frame被加到栈上,下图就是在一个栈上不断调用和结束调用方法的对应的frame结构:

iOS Programming 2(objective-c)

| Comments

Objective-c中的方法调用其实是一种消息传送的机制,例如下面这段代码:

1
[partyInstance addAttendee:somePerson]

他表达的意思是发送addAttendee:消息给partyInstance对象,然后这个对象再去调用他的类中的addAttendee方法,somePerson在这里是参数。在运行时,消息被发送到对象,然后对象会向创建自己的那个类寻求帮助,并告诉这个类去运行消息中指定的方法(e.g. addAttendee)(这里需要注意的是,一切都是发生在运行时,而不是一些其他语言在编译时进行检查)。那么一个对象又是怎么知道自己属于哪个类呢?其实每个对象都有一个叫做’isa’的instance variable,当这个对象被创建的时候,这个isa就自动被初始化为指向创建他的那个类。这个instance variable叫做’isa’是有道理的,因为他是创建他的类的一个实例。他们的关系如下:

iOS Programming 1(A Simple iOS Application)

| Comments

最近在学习iOS开发,虽然课上也有讲,但是还是不如自己看书学得更实在,今天就从最基础的iOS开发说起。值得注意的是,我在这类博客里所讲到的内容,完全是按照iOS Programming: The Big Nerd Ranch Guide第四版里面来的。

快速排序(Quicksort)

| Comments

Quick Sort即快速排序,它是对归并排序的一种补充,采用的也是分治策略。基本思想是在整个数组中选择第一个数作为一个基准,然后分别从第二个数向后和最后一个数向前开始扫描。如果在向后扫描的过程中如果遇到比基准大的数字(我们这里假设默认为升序排列),同时在从后向前扫描的过程中遇到比基准小的数字,那么这两个数字就交换。这个过程一直持续下去直到从左扫描的下标大于从右开始扫描的下标作为结束。最后,把基准和右边下标指向的数交换,这样基准左边的数字都小于该基准,基准右边的数字都大于它。不断地递归这个过程就是快速排序。我们可以看看下面这个图帮助理解:

归并排序(Mergesort)

| Comments

Merge sort即归并排序,它的中心思想是分而治之(divide and conquer),即将一个原来很大的待排序数列分成若干个小的数列然后分别对他们进行排序,最后把小的排好序的数列合并起来。这个过程可以分为三个步骤:

第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.

第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作。

第三, 合并: 合并两个排好序的子序列,生成排序结果。

在我看来,归并排序中最重要的还是‘合并’,因为在多次递归分解之后,剩下的大小为2的数组都是通过‘合并’过程达到排序的目的。合并的过程很简单,从下面这张图就能大概看出来:

选择排序(Selection sort)插入排序(Insertion sort)与希尔排序(Shellsort)

| Comments

一、选择排序

选择排序之所以被称为选择排序是因为在每一次的迭代过程中,总是‘选择’最小的一个元素到数组的最左边。下面是一个选择排序的实例:

1
2
3
4
5
6
7
8
9
10
11
12
private static void sort(String[] a) {
    int N = a.length;
    for (int i = 0; i < N; i++) {
        int min = i;
        for (int j = i + 1; j < N; j++) {
            if (a[j] < a[min]) {
                min = j;
            }
        }
        exchange(i, min);
    }
}

理解Java中的重排序

| Comments

重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段。重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境。

在并发程序中,程序员会特别关注不同进程或线程之间的数据同步,特别是多个线程同时修改同一变量时,必须采取可靠的同步或其它措施保障数据被正确地修改,这里的一条重要原则是:不要假设指令执行的顺序,你无法预知不同线程之间的指令会以何种顺序执行。

但是在单线程程序中,通常我们容易假设指令是顺序执行的,否则可以想象程序会发生什么可怕的变化。理想的模型是:各种指令执行的顺序是唯一且有序的,这个顺序就是它们被编写在代码中的顺序,与处理器或其它因素无关,这种模型被称作顺序一致性模型,也是基于冯·诺依曼体系的模型。当然,这种假设本身是合理的,在实践中也鲜有异常发生,但事实上,没有哪个现代多处理器架构会采用这种模型,因为它是在是太低效了。而在编译优化和CPU流水线中,几乎都涉及到指令重排序。

在java中复写equals和hashCode

| Comments

首先我们必须得知道什么是hash code。总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。如果详细讲解哈希算法,那需要更多的文章篇幅,我在这里就不介绍了。初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是)。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。所以,Java对于eqauls方法和hashCode方法是这样规定的:1、如果两个对象相同,那么它们的hashCode值一定要相同;2、如果两个对象的hashCode相同,它们并不一定相同。

如何在Java中创建Immutable的类

| Comments

首先,我们需要明白什么是Immutable的类。顾名思义,就是在对象创建后,它的状态不能改变。你首先也许会想到final这个关键字,因为它会使被修饰者要么不能被继承(修饰类),要么不能被重新赋值(修饰字段)。下面我们来看一个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
final class ImmutableClass_1 {
    private final int i = 0;
    private final double j = 1;

    int getI() {
        return i;
    }

    double getJ() {
        return j;
    }
}