要学!要会!!要练!!!--程序员笔试面试知识梳理

整理自互联网, 最后更新: 2016-04-21


目录:


0 平时积累

  1. github项目
    github用户名/项目名
    • 推荐写一些字符串处理等小工具发布在github上
    • fork的项目(fork是github的一个功能, 下载你关注的项目): UML Designer, hibernate等
  2. 技术博客
    blog.csdn.net/你的CSDN博客名

1 Hardwares

1.1 地址总线、数据总线、控制总线详解

目前Windows 7 64位版最大仅能使用192GB内存,Windows 8 64位版最大仅能使用512GB内存。
使用PAE40技术的Intel x86-64 CPU是40位地址线,使用PAE48或PAE52技术的AMD x86-64 CPU是48位或52位地址线。
数据总线
(1) 是CPU与内存或其他器件之间的数据传送的通道。
(2)数据总线的宽度决定了CPU和外界的数据传送速度。
(3)每条传输线一次只能传输1位二进制数据。eg: 8根数据线一次可传送一个8位二进制数据(即一个字节)。
(4)数据总线是数据线数量之和。
地址总线
(1)CPU是通过地址总线来指定存储单元的。
(2)地址总线决定了cpu所能访问的最大内存空间的大小。eg: 10根地址线能访问的最大的内存为1024位二进制数据(1B)
(3)地址总线是地址线数量之和。
控制总线
(1)CPU通过控制总线对外部器件进行控制。
(2)控制总线的宽度决定了CPU对外部器件的控制能力。
(3)控制总线是控制线数量之和。
例题:若内存容量为4GB,字长为32,则__
A.地址总线和数据总线的宽度都为32
B.地址总线的宽度为30,数据总线的宽度为32
C.地址总线的宽度为30,数据总线的宽度为8
D.地址总线的宽度为32,数据总线的宽度为8
答案:A
内存容量为4GB,即内存单元的地址宽度为32位。字长为32位即要求数据总线的宽度为32位,因此地址总线和数据总线的宽度都为32。

1.2 通用寄存器

在 x86 指令集里,一个 CPU 有 八个通用寄存器:EAX, EDX, ECX, ESI, EDI, EBP, ESP 和 EBX
EAX 寄存器也叫做累加寄存器,除了用于存储函数的返回值外也用于执行计算的 操作。
EDX 寄存器也叫做数据寄存器。这个寄存器从本质上来说是 EAX 寄存器的延伸, 它辅助 EAX 完成更多复杂的计算操作像乘法和除法。它虽然也能当作通用寄存器使用,不 过更多的是结合 EAX 寄存器进行计算操作。
ECX 寄存器,也叫做计数寄存器,用于循环操作,比如重复的字符存储操作,或 者数字统计。有一点很重要,ECX 寄存器的计算是向下而不是向上的(简单理解就是用于 循环操作时是由大减到小的)。

counter = 0
while counter < 10:
    print "Loop number: %d" % counter 
    counter += 1

如果你把这代码转化成汇编代码,你会看到第一轮的时候 ECX 将等于 10,第二轮 的时候等于 9,如此反复知道 ECX 减少到 0。这很容易让人困惑,因为这和 Python 的循环 刚好代码相反,但是只要记得 ECX 是向下计算的就行了。
SI(source index)用于读,EDI(destination index) 用于写。
ESP 和 EBP 分别是栈指针和基指针。
EIP。这个寄存器总是指向马上要执行的指令。
最后,EBX 是唯一一个没有特殊用途的寄存器。它能够作为额外的数据储存器。

linux相关

命令

前台后台转换

在命令末尾加上 & 符号,就可以让程序在后台运行
Ctrl+z 选项把程序暂停,然后用 bg %[number]
fg %[number]
kill

文件的inode,软链接和硬链接

Unix/Linux系统内部不使用文件名,而使用inode号码来识别文件。对于系统来说,文件名只是inode号码便于识别的别称或者绰号。表面上,用户通过文件名,打开文件。实际上,系统内部这个过程分成三步:首先,系统找到这个文件名对应的inode号码;其次,通过inode号码,获取inode信息;最后,根据inode信息,找到文件数据所在的block,读出数据。

stat 命令,ls -i
Q: 允许多个文件有相同的inode吗
A: 硬链接说白了是一个指针,指向文件索引节点,系统并不为它重新分配inode。可以用:ln 已有文件 快捷方式名命令来建立硬链接;ln -s 已有文件 快捷方式名软连接
例子:已有 inode = 123 的文件fun, 硬链接新建一个快捷方式fun_hard, 则inode也是123. 软链接也是一种文件,同样占有一个Inode,创建软链接不增加链接数.
区别:
1.软链接可以跨文件系统,硬链接不可以;
2.多个硬链接占用同一个Inode编号,多个硬链接与源文件不分彼此,修改任何一个其他文件都会同步修改。软链接占用独立的Inode编号;
3.软链接可以对一个不存在的文件名进行链接;
4.软链接可以对目录进行链接。

语言特点

java

杂项

Integer x, y = 128; 等价于 Integer x = ?, y =Integer.valueOf(199);
private 不能修饰外部类,编译出错
ubuntu14.04下切换版本
$ update-alternatives --install /usr/bin/java java /usr/java/jdk1.6.0_11/bin/java 300
$ update-alternatives --config java
$ update-alternatives --install /usr/bin/javac javac /usr/java/jdk1.6.0_11/bin/javac 300
$ update-alternatives --config javac

举例说明阅读了java源码

1. IntegerCache when auto-boxing: [-127,128], Integer x=128(127), y = 128(127); x==y false
2. Eclipse ctrl 显示方法的实现,常用查看某java类有几种构造函数
3. LinkedList和ArrayList的add()和set()源码,封装了插入和修改操作,不提供next()。以至于用其实现的InsertSort的时间复杂度增大。

处理Error和Exception

try块中执行到return;会先执行finally块再返回。

异常类结构


图 java Exception Error

InterruptedException及其处理

  当一个线程处于等待,睡眠,或者占用,也就是说阻塞状态,而这时线程被中断就会抛出这类错误.
  正如Listing A中所描述的,Thread.interrupt()方法不会中断一个正在运行的线程。这一方法实际上完成的是,在线程受到阻塞时抛出一个中断信号,这样线程就得以退出阻塞的状态。更确切的说,如果线程被Object.wait, Thread.join和Thread.sleep三种方法之一阻塞,那么,它将接收到一个InterruptedException,从而提早地终结被阻塞状态。

中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。但是不正确地中断一个线程可能引发各种问题,首先,忘掉Thread.stop方法(jdk 8 仍有该方法)。以下文字引自java 7 api document:

Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath exception propagating up the stack).

以下内容来自SimonShi的博客http://www.cnblogs.com/simonshi/archive/2011/12/31/2308455.html
  一些轻率的家伙可能被另一种方法Thread.interrupt所迷惑。尽管,其名称似乎在暗示着什么,然而,这种方法并不会中断一个正在运行的线程(待会将进一步说明),正如Listing A中描述的那样。它创建了一个线程,并且试图使用Thread.interrupt方法停止该线程。Thread.sleep()方法的调用,为线程的初始化和中止提供了充裕的时间。线程本身并不参与任何有用的操作。

class Example1 extends Thread {
    boolean stop = false;

    public static void main(String args[]) throws Exception {
        Example1 thread = new Example1();
        System.out.println("Starting thread...");
        thread.start();
        Thread.sleep(3000);
        System.out.println("Interrupting thread...");
        thread.interrupt();
        Thread.sleep(3000);
        System.out.println("Stopping application...");
        // System.exit(0);
    }

    public void run() {
        while (!stop) {
            System.out.println("Thread is running...");
            long time = System.currentTimeMillis();
            while ((System.currentTimeMillis() - time < 1000)) {
            }
        }
        System.out.println("Thread exiting under request...");
    }
}

输出如下:
Starting thread…
Thread is running…
Thread is running…
Thread is running…
Interrupting thread…
Thread is running…
Thread is running…
Thread is running…
Stopping application…
Thread is running…
Thread is running…
Thread is running…
中断线程最好的,最受推荐的方式是,使用共享变量(shared variable)发出信号,告诉线程必须停止正在运行的任务。线程必须周期性的核查这一变量(尤其在冗余操作期间),然后有秩序地中止任务。Listing B描述了这一方式。

class Example2 extends Thread {

    volatile boolean stop = false;

    public static void main(String args[]) throws Exception {

        Example2 thread = new Example2();
        System.out.println("Starting thread...");
        thread.start();
        Thread.sleep(3000);
        System.out.println("Asking thread to stop...");
        thread.stop = true;
        Thread.sleep(3000);
        System.out.println("Stopping application...");
        // System.exit( 0 );
    }

    public void run() {
        while (!stop) {
            System.out.println("Thread is running...");
            long time = System.currentTimeMillis();
            while ((System.currentTimeMillis() - time < 1000) && (!stop)) {
            }
        }
        System.out.println("Thread exiting under request...");
    }
}

;引用结束

    while(!Thread.isInterrupted()){  
        try {  
         Thread.sleep(1000);  
        }catch(InterruptedException ex)  
        {  
              Thread.interrupt()  
        }   
    } 
void waitForSignal() {
    Object obj = new Object();
    // synchronized的目标与 wait() 方法的物件不相同,会有 IllegalMonitorStateException, 不过 InterruptedException先出现
    synchronized (obj) { 
        try {
            obj.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        obj.notify();
    }
}

Collection和Map结构


图 java Collection和Map和Iterator

1. LinkedList的不完美朋友ListIterator

LinkedList类封装了Node和previous(),next(),因此只能通过add(),remove()方法进行插入删除操作,内部是从头指针开始寻找位置的。在数据量很大时,时间复杂度会很高。如果需要链表的下一个元素,需要借助ListIterator 的next(), add(E e), remove(), set(E e). 注意,这几个方法的操作对象都是最后一个next()或previous()的返回值.
arrayList.listIterator(n); //跳过前面n包括第n个元素后,构建链表
由于ListIterator不提供头指针,所以只能遍历一次,而且不提供返回List类型的方法。而InsertSort要求循环地将未排序元素插入有序列表,直至列表全部有序。因此,ListIterator不能用于InsertSort。

2. ArrayList和Vector区别:

ArrayList在内存不够时默认是扩展50% + 1个,Vector是默认扩展1倍。
Vector提供indexOf(obj, start)接口,ArrayList没有。
Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。

3. Collection类和Map类不是继承关系!

Collection下属List,Set,Queue; Map接口是key-value,下属HashTable extends Dictionary<K,V> implements Map<K,V>HashMap extends AbstractMap<K,V> implements Map<K,V>
HashTable和HashMap的区别:
比较相似的类,第一步,从线程安全角度!从线程安全角度!!从线程安全角度!!!
1. HashMap不安全,但快?
2. HashMap允许将null作为一个entry的key或者value,而Hashtable不允许。
3. HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
4. 父类不同: Table extends Dictionary; Map extend AbstractMap

voliate,新建的线程中直接访问内存里的变量,但是没阮用

多线程,同步变量。 线程为了提高效率,将成员变量(如A)某拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A) ,但是不能用其来进行多线程同步控制

 Q:为什么volatile不能保证原子性而Atomic可以

public class Counter {  
    public volatile  static int count = 0;  

    public static void inc() {  
        //这里延迟5毫秒,使得结果明显  
        try {  
            Thread.sleep(5);  //sleep来自Thread类,和wait来自Object类。
        } catch (InterruptedException e) {  
        }  
        //synchronized(Counter.class) {  //注释以后程序结果不稳定
            count ++;  
        //}  
    }

虽然该方法要求一些编码,但并不难实现。同时,它给予线程机会进行必要的清理工作,这在任何一个多线程应用程序中都是绝对需要的。请确认将共享变量定义成volatile 类型或将对它的一切访问封入同步的块/方法(synchronized blocks/methods)中。

到目前为止一切顺利!但是,当线程等待某些事件发生而被阻塞,又会发生什么?当然,如果线程被阻塞,它便不能核查共享变量,也就不能停止。这在许多情况下会发生,例如调用Object.wait()、ServerSocket.accept()和DatagramSocket.receive()时,这里仅举出一些。

1.5新特点

自动装箱和拆箱
java有cache的三个封装类,IntegerCache, ShortCache, ByteCahce

Integer i01 = 59; //内部实现是 Integer.valueOf(59), 在[-128,127]内,存入IntegerCache
Integer i11 = 59; //IntegerCache有,返回i01的引用
int i02 = 59;     //保存在栈内
Integer i03 =Integer.valueOf(59); //IntegerCache有,返回i01的引用
Integer i04 = new Integer(59); //直接创建了一个新的Integer实例。
//Integer的缓存范围是[-128,-127]
Integer a = 127;
Integer b = 127; //a==b 输出true.
Integer c = 128;
Integer d = 128; //c==d 输出false 
System.out.println("i1 i2" + (i01 == i02));
System.out.println("i1 i3" + (i01 == i03)); //i03实际上是i01的引用,内存地址相同
System.out.println("i1 i4" + (i01 == i04));
System.out.println("i2 i3" + (i02 == i03)); //i03自动拆箱为int,进行值比较
System.out.println("i2 i4" + (i02 == i04)); //i04自动拆箱为int,进行值比较
System.out.println("i3 i4" + (i03 == i04));
System.out.println("i01 i11" + (i01 == i11));

1.7新特点

  1. 对try-catch块的资源的自动回收管理
  2.在数字中使用下划线并且增加0b作为二进制前缀
int binary = 0b1001_1001;
  3.字符串进行switch case
  4. new泛型时的简化表达
Vector<Integer> v = new Vector<>();

  5. 一个catch里捕捉多个异常类型,和嵌套的try-catch比较

==,equals(),instanceof

因为Object的equals方法也是用双等号(==)进行比较的,所以比较后的结果跟双等号(==)的结果相同。
child instanceof parent.Class == true

对象在内存中的位置

String str1 = “abc”,“abc”分配在内存哪个区域?
用new创建的对象在堆区
函数中的临时变量在栈去
java中的字符串在字符串常量区
CSomething a();
CSomething b(2);
CSomething c[3];
CSomething &ra = b;
CSomething d=b;
CSomething *pA = c;
CSomething *p = new CSomething(4);

内存模型

内存配置参数

泛型generic

不能定义泛型数组

由于 Java 使用擦除(erasure)实现的泛型,在运行时无法知道确切的类型信息,因此不能创建相应类型的数组。
擦除:为了兼容之前并未使用泛型的类库和代码,不得不让编译器擦除掉代码中有关于泛型类型信息的部分,这样最后生成出来的代码其实是『泛型无关』的。编译器层面的“擦除”使得Java的泛型先天都存在一个让人非常难受的缺点:在泛型代码内部,无法获得任何有关泛型参数类型的信息。
来自findingsea@github的擦除补偿–通过显示传类型参数生成“泛型数组”的方法:(显示传递类型让人不爽,新的泛型可能在java10中得到解决)

public class Main<T> {
    public T[] create(Class<T> type) {
        return (T[]) Array.newInstance(type, 10);
    }

    public static void main(String[] args) {
        Main<String> m = new Main<String>();
        String[] strings = m.create(String.class);
    }
}

另外think in java这本书中,对泛型数组的处理通过四个小程序对其进行了比较完整的描述

不能定义泛型static方法和域:

  以下精妙解释来自newacct@Stackoverflow的大作

For static fields and static methods, they are shared among all instances of the class, even instances of different type parameters, so obviously they cannot depend on a particular type parameter.

  因此,一个采用单例模式的class Fun<T>不能用private static Fun<T> fun = null;而是要采用Map来保存每个类的实例。
需求: 我需要为int和string写两个排序函数。
实现: 泛型class和泛型method
JVM机制: 和C++的泛型不同,java并不会为每个类型生成一份代码,他的策略是使用Object(或者限制类型)替换所有的泛型类型,然后在需要对时候进行强制转换。

和泛型class不同的,泛型method的T是编译器自动推算出来的。、

public static <T> T getMiddle(T[] a) 
    { 
        return a[a.length / 2]; 
    } 

getMiddle(2.1,2,5)
然而上面的用法将会让你会收到一个错误“found:….,required:….”这是因为编译器自动将参数转变成对象,并寻找这些对象公共的父类,而Integer和Double的公共父类之一comparable本身是一个泛型。问题是comparale和Comparable是两个类型,也就是说编译器无法找到一个公共的父类,因此编译器报错。
有时我们希望能限制泛型参数的类型,如下所示:
public static Pair minmax(T[] a)
这样做的好处是,只有Comparable的子类才能作为参数传入,同时我们可以调用T的compareTo方法而不需要强制转换。值得注意的是T可以extends多个类型,但是和extends的语法类似,只能有一个class,其他的都是interface。

咋一看Pair

内部类nested class

成员内部类

以下内容引自forestqqqq@iteye的大作http://forestqqqq.iteye.com/blog/1906653
1. 成员内部类中不能存在static关键字,即,不能声明静态属性、静态方法、静态代码块等。
2. 在成员内部类中访问外部类的成员方法和属性,要使用“外部类名.this.成员方法”和“外部类名.this.成员属性”的形式
3. 创建成员内部类的实例使用“外部类名.内部类名 实例名 = 外部类实例名.new 内部类构造方法(参数)”的形式。在创建内部类实例之前需要先创建外部类的实例对象。
5. 内部类在编译之后生成一个单独的class文件,里面包含该类的定义,所以内部类中定义的方法和变量可以跟父类的方法和变量相同。例如上面定义的三个类的class文件分别是:MyTest.classOuter.classOuter$Inner.class三个文件。内部类的定义文件名形式是“外部类定义名$内部类定义名”.
7. 与外部类平级的类继承内部类时,其构造方法中需要传入父类的实例对象。且在构造方法的第一句调用“外部类实例名.super(内部类参数)”。

public class MyTest {  
    public static void main(String[] args) {  
       Outer outer = new Outer("test");  
       new Extender(outer,10);  
    }  
}  

class Outer{  
    Outer(String str){}  
    protected class Inner{  
       public Inner(int a){  
       }  
    }  
}  

class Extender extends Outer.Inner{  
    public Extender(Outer outer,int a){  
       //外部类实例名.super(内部类参数列表)  
       outer.super(a);  
    }  
}  

;引用结束

静态内部类(有static修饰符的成员内部类)

以下内容引自forestqqqq@iteye的大作http://forestqqqq.iteye.com/blog/1906653
1静态内部类更外部类没有任何关系,只是在生成类名和类定义时有影响。静态内部类可以看做是与外部类平级的类。使用方式与外部类平级的类完全相同。
2静态内部类不能访问外部类的非静态的属性和方法。外部类不能访问内部类的非静态的属性和方法。
3静态内部类创建实例的形式:外部类名.内部类名 实例名 = new外部类名.内部类名(参数)
;引用结束

若有static修饰符,可以通过外部类直接访问成员内部类,不然需要生成外部的对象后才能访问。一个常见的应用场景是为了方便访问数据,将内部类设为static。注意:静态内部类访问的外部类数据必须用静态修饰。

class Outer3 {
    private static int num2 = 100;

    public static class Inner {
        public void show() {
            // System.out.println(num);
            System.out.println(num2);
        }
    }
}

局部内部类

以下内容引自forestqqqq@iteye的大作http://forestqqqq.iteye.com/blog/1906653
2. 局部内部类访问外部类的属性和方法的语法和成员内部类的语法相同。
3. 局部内部类访问作用域内的局部变量,该局部变量需要使用final修饰。
;引用结束

匿名内部类

四种内部类能否被abstract修饰

只有匿名内部类不行,因为匿名内部类马上创建一个且仅一个实例。同理,匿名内部类内部不能定义static方法或者属性。

Error和Exception的区别

Error是错误,可捕获,但是不可以处理,打个比方:就像电脑蓝屏
Exception是异常,可以捕获也可以处理,打个比方:就像电脑中了病毒后可以查杀病毒。
这里有一个测试,看看你真的懂try-catch-finally了吗。

垃圾回收

请参考成富@infoq的大作http://www.infoq.com/cn/articles/cf-java-garbage-references

数据结构

排序平均和最坏时间复杂度

名字 平均时间复杂 最坏时间复杂
插入排序 O(n2) O(n2)
选择排序
冒泡排序
快速排序
希尔排序
堆排序
归并排序

B树

二叉搜索树,AVL树和红黑树仍然是二叉搜索树并且努力平衡左右子树的高度。B+,B-不是二叉的,但是仍然在为“平衡”而努力

二叉堆,二项堆各种操作的事件复杂度

操作名 二叉堆 二项堆 Fibonacci
构造 O(nlogn)
插入 在最后插入,往上调整直至根节点,O(logn)
合并 最优方法是把两个二叉堆首尾相连放在一个数组中。O(log n log k),另一说O(N) O(logN)
查找最小关键字
删除最小关键字

2分查找最多比较次数公式

向上取整(lg(n+1))

快排的堆栈实现


题外话,java的Stack类是泛型类,如果不是必要,请指定变量类型。不然javac时会出现警告。
If there is indeed a usecase where you’d like to store both 5 and “dog” in your stack, you should define your stack with the greatest common denominator between the two - Object:
Stack<Object> s = new Stack<>();
Q: How it will be if parent and child are stored in one Stack?


function qsort_with_loop(arr) {
  let stack = [];

  stack.push([0, arr.length - 1]);

  while (stack.length) {
    let _ = stack.pop();
    let i = l = _[0];
    let j = r = _[1];
    let mid = arr[(i + j) >> 1];

    do {
      while (arr[i] < mid) ++i;
      while (arr[j] > mid) --j;
      if (i <= j) {
        let t = arr[i];
        arr[i] = arr[j];
        arr[j] = t;
        ++i;
        --j;
      }
    } while (i <= j);

    if (i < r) stack.push([i, r]);
    if (l < j) stack.push([l, j]);
  }
}

多维数组指针混搭

如果对全部元素都赋初值(即提供全部初始数据),则定义数组时对第一维的长度可以不指定,但第二维的长度不能省。如:
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
可以写成
int a[][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int n[][3] = {10,20,30,40,50,60};
int (*p)[3];
p=n;
p是一维指针数组,p[0]指向n[0][0]的地址,

*(p[0]+1)=取值(p数组第一个元素的值(n[0][0]的地址)+1个int的长度)=取值(n[0][1]的地址)

本质上a[i]操作被编译器解释为(a+i)操作,即[]运算符是通过数组名指针实现的,因而&a[0]的含义即&(*a),显然对一个指针先(解引用),再&(引用),等价于什么都没做,还是这个指针本身,因而a完全等价于&a[o]。

java二维数组初始化

type arrayName[ ][ ]; == type [ ][ ]arrayName;
java二维数组可以动态初始化,如下,程序会报错

int a[ ][ ] = new int[2][];
a[0] = new int[1];
a[1] = new int[5];
System.out.println(a[0][1]);

Java语言中,所谓的“二维数组”是一个数组之中嵌套着一个数组

指针

int *p1, p2;即p1是指针型的,而p2却是整型的。
在定义之外的地方,*(地址)是取值,&(变量)是取地址.

64bit指针和结构体对齐

struct A{
 long a1;
 short a2;
 int a3;
 int *a4;
};
64位编译器下用sizeof(struct A)计算出的大小

字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
1. 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
2. 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍(注意是此成员大小的整数倍,而不是最宽成员),如有需要编译器会在成员之间加上填充字节(internal adding);
3. 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)
long 64b short 16b int 32b int型指针64b=64+16+32+64<64*3b=24B(sizeof()返回值以B为单位)

concurrent

Hashmap

hashmap代码实现

递归

递归格雷码

格雷码(Gray Code)是一个数列集合,每个数使用二进位来表示,假设使用n位元来表示每个数字,任两个数之间只有一个位元值不同。
例如以下为3位元的格雷码: 000 001 011 010 110 111 101 100 。
如果要生成4位元格雷码,我们只需要在3位元格雷码上再加一层0,1就可以了: 0000,0001,0011,0010,0110,0111,0101,0100,1100,1101,1110,1010,0111,1001,1000.
如果要产生n位元的格雷码,那么格雷码的个数为2^n.

n位元格雷码是基于n-1位元格雷码产生的。

网络编程

cgi(Common Gateway Interface) vs serverlet

Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法,service方法自动派遣运行与请求对应的doXXX方法(doGet,doPost)等,当服务器决定将实例销毁的时候调用其destroy方法。

与cgi的区别在于servlet处于服务器进程中,它通过多线程方式运行其service方法,一个实例可以服务于多个请求,并且其实例一般不会销毁,而CGI对每个请求都产生新的进程,服务完成后就销毁,所以效率上低于servlet。

JSP

内置对象

JSP分页代码

总页数=总记录数/每页显示的条数(每页显示的条数是人为规定的)
1、count(*)得到总记录数
2、计算总页数
3、获取所有记录
4、过滤显示本页数据

因此总页数要根据总记录数确定,因此要首先获取总记录数

Httpserverlet方法

HttpServlet容器响应Web客户请求流程如下:
 简易版本:
三阶段:
1.初始化阶段 调用init()方法
2.响应客户请求阶段  调用service()方法
3.终止阶段  调用destroy()方法
 响应请求阶段详细版本:## 标题 ##
1)Web客户向Servlet容器发出Http请求;
2)Servlet容器解析Web客户的Http请求;
3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息;
4)Servlet容器创建一个HttpResponse对象;
5)Servlet容器调用HttpServlet的service(),这个方法中会根据request的Method来判断具体是执行doGet还是doPost,把HttpRequest和HttpResponse对象作为service()的参数传给HttpServlet对象;
6)HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息;
7)HttpServlet调用HttpResponse的有关方法,生成响应数据;
8)Servlet容器把HttpServlet的响应结果传给Web客户。

doGet() 或 doPost() 是创建HttpServlet时需要覆盖的方法.

Java Web 框架 - 从SSH 到 SH

如果你还没学Java Web开发, 恭喜你! 千万别学了, 现在是2016年, 不说nodejs了, Ruby on Rails, PHP 甚至是 Python都比Java Web发展得好. Java Web一般只有大公司的老项目还在用.

SSH(Structs + Spring + Hibernate)过时了, 现在是2016年, Java Web 只用Spring MVC + Hibernate 就够了

如果你一定要学Java Web, 那就只学Spring MVC框架, 别碰Struct框架.

Structs框架过时了, 请出门右转找 Spring MVC

过去,我们用jsp和servlet搭配,实现展现时,答题的过程是:

  1 jsp出发action
  2 servlet接受action,交给后台class处理
  3 后台class跳转到其他的jsp,实现数据展现

  现在有了struts2,实现过程变为

  1 jsp出发action
  2 struts2拦截请求,调用后台action
  3 action返回结果,由不同的jsp展现数据
  
Struct框架架构图

图1 Struct框架架构图

Struct遵循了Model-View-Controller的思想.
Model JavaBean

Spring MVC框架

请自行搜索

ICMP,IP位于哪一层?

网络层协议

ssh

stand for Secure Shell.

TCP3次握手各个阶段,四次挥手各个阶段

背出来

linux缓冲技术

rabbitMQ

jvm集中成熟的垃圾回收算法

多线程多进程

java的synchronized

1 fork()

  1. fork()是一个分叉函数,返回值: 若成功调用一次则返回两个值,子进程返回0, 父进程返回子进程标记;否则,出错返回-1。由fork()创立的子进程代码和父进程完全一致,唯一区别是从fork()处开始执行,且这个fork()的返回值为0.

  2. A&&B||C分析
    因为在这句之前的fork()命令会让最后的进程数量翻倍,所以只要知道这句执行后的进程数量再乘以2就容易得到答案。
    &&“逻辑与”也叫做“短路与”,||“逻辑或”也叫“短路或”。A&&B,如果A=0,就没有必要继续执行&&B了;A||B,如果A非0,就没有必要继续执行||B了。c++和java中|和&都是位运算,需要判断运算符两侧,不存在短路。
    特别的,C||A&&B==A&&B||C,“官大一级压死人”。因为优先级从高到低为:&,|,&&,||,?:.

java中的fork:ForkJoinPool since 1.7, ExecutorService in 1.6(Q:deprecated or not?)

java首次提供多核的硬件层面的支持

java.lang.Object
  |-java.util.concurrent.AbstractExecutorService
    |-java.util.concurrent.ForkJoinPool

实例:网络爬虫
recursion程序特别适合fork/join

c中的fork()

2 concurrent包

Semaphore信号量

问:请写出一个简单的例子?

ReentranLock低级实用程序类 – 锁定和原子类

CAS(compare-and-swap) 是一种低级别的、细粒度的技术,它允许多个线程更新一个内存位置,同时能够检测其他线程的冲突并进行恢复。在 JDK 5.0 之前,Java 用于协调线程之间的访问的惟一原语是同步,同步是更重量级和粗粒度的。
使用 CAS 作为并发原语,ReentrantLock 类提供与 synchronized 原语相同的锁定和内存语义,然而这样可以更好地控制锁定(如计时的锁定等待、锁定轮询和可中断的锁定等待)和提供更好的可伸缩性(竞争时的高性能)。大多数开发人员将不再直接使用 ReentrantLock 类,而是使用在 ReentrantLock 类上构建的高级类。
问:请写出一个简单的例子?

Callable和Future

它俩很有意思的,一个产生结果,一个拿到结果。
背景:并发编程时,一般把runnable扔给线程池完事,不需要线程的结果。所以run的返回值是void类型。 如果是一个多线程协作程序,比如菲波拉切数列,1,1,2,3,5,8…使用多线程来计算。 但后者需要前者的结果,就需要用callable接口了。
问:请写出一个简单的例子?

CountDownLatch原子操作的计数器(同时只能被一个线程操作)

问:请写出一个简单的例子?

Cloud Computing

golang

  Go语言是谷歌2009发布,1.5版本从Go代码库中完全移除C代码,当前(2016年3月)版本号为1.6beta2。源代码托管在 GitHub 上. golang支持交叉编译,也就是说你在32位平台的机器上开发,可以编译生成64位平台上的可执行程序。甚至还能在win上编译linux。某些确实性能过于关键的场合,也可以通过cgo让Go和C搭配。
  go语言有自己的特色:Goroutine,简化的不会引起内存问题的指针

  Q&A:

  为什么编译语言比动态语言容易发现错误?
  答:有些隐蔽bug到某些条件分支才会触发,一旦在运行中途出问题,改起来也麻烦。Go语言就如同C和Python中间的完美结合,如果你是Python爱好者,又追求代码的速度和并行化,那么简单说,Go语言就是为你设计的。

  为什么说go语言缺少高级语言特性,请举例说明。
  答:这个说法是错误的。事实上,go也有GC,1.1版本以后的gc越发完善。也支持Clousure,Unicode,函数是一等公民。
  Go语言和c++,java等语言不同的,没有独立的OO体系,一切以struct为中心,没有exceptions(Oh yes!),仍然有指针,等等。在go里不需要class,仍然可以继承和多态,但是速度却快得多。因为OO在Go语言中,就是普通的struct操作。

  Go适合用来做什么
  答:服务器编程,以前你如果使用C或者C++做的那些事情,用Go来做很合适,例如处理日志、数据打包、虚拟机处理、文件系统等。
  分布式系统,数据库代理器等
  网络编程,这一块目前应用最广,包括Web应用、API应用、下载应用、
  内存数据库,前一段时间google开发的groupcache,couchbase的部分组建
  云平台,目前国外很多云平台在采用Go开发,CloudFoundy的部分组建,前VMare的技术总监自己出来搞的apcera云平台。docker项目:基于lxc的一个虚拟打包工具,能够实现PAAS平台的组建。

例子

package main
import "fmt"
func main(){
    fmt.Printf("hello\n")
}

go run hello.go

Docker

Docker是PaaS供应商dotCloud开源的一个基于LXC(Linux Containers since linux kernal 2.6, Ubuntu14.04.3-3.19/15.10-4.2)的高级容器引擎, 本质是一个操作系统级虚拟化工具. 源代码托管在 GitHub 上
云计算时代的到来:IaaS–AWS(Amazon Web Services):Netflix、Quora、Intergram等公司。SMB中小企业.
Docker从一开始使用Ubuntu版本作为开发环境,主要是Ubuntu上支持aufs(advanced multi layered unification filesystem)文件系统。所以,Docker对Ubuntu的支持是最好的。
GCE(Google Computer Engine)
容器编排管理系统 Kubernetes。Kubernetes开源项目版本更新频繁,对于初次使用者来说其定义大量的技术术语并且随时会有新术语出现。在这种不稳定的技术框架之下,对使用者来说确实带来了一定的技术门槛。

Docker vs VMs:
Docker.vs.VMs

kernel namespace。其中pid、net、ipc、mnt、uts、user等namespace将container的进程、网络、消息、文件系统、UTS(“UNIX Time-sharing System”)和用户空间隔离开。

我的cnblog用户名vegetable92 [email protected]

猜你喜欢

转载自blog.csdn.net/caib1109/article/details/51064889