后端知识点总结

后端知识点总结

Java

Java内存堆栈

  • 栈主要储存简单的变量,如int, string等基本类型,而函数和对象和数组存在堆中,使用引用赋值。
  • 使用new的对象直接保存在堆中
  • 栈由系统分配,程序员分配堆,JVM垃圾回收机制回收堆内存,栈使用完成立即释放。
  • 引用传递function(ref int a)直接传递内存地址,局部变量a的操作会改变内存,数组char[n]传递为引用传递
  • int a = 1; b = a; unset(a) b依然存在,因为先开辟了“1”的内存空间然后使a指向“1”的空间,然后使b指向“1”的内存空间,当unset(a)时,b仍然指向1。

Final关键字

final变量:

  • final 变量能被显式地初始化并且只能初始化一次。被声明为 final 的对象的引用不能指向不同的对象。但是 final 对象里的数据可以被改变。也就是说 final 对象的引用不能改变,但是里面的值可以改变。

  • final 修饰符通常和 static 修饰符一起使用来创建类常量。

final 方法:

  • 类中的 final 方法可以被子类继承,但是不能被子类修改。

  • 声明 final 方法的主要目的是防止该方法的内容被修改。

final 类:

  • final 类不能被继承,没有类能够继承 final 类的任何特性。

当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。

==用法

==强调栈中的比较,可以理解为地址比较
,equals强调对象的内容比较

类初始化顺序

无继承情况:

  1. 静态变量
  2. 静态初始化块
  3. 变量
  4. 初始化块
  5. 构造器

继承情况:

  1. 父类–静态变量
  2. 父类–静态初始化块
  3. 子类–静态变量
  4. 子类–静态初始化块
  5. 父类–变量
  6. 父类–初始化块
  7. 父类–构造器
  8. 子类–变量
  9. 子类–初始化块
  10. 子类–构造器

子类的构造方法总是先调用父类的构造方法,如果子类的构造方法没有明显地指明使用父类的哪个构造方法,子类就调用父类不带参数的构造方法。子类的构造方法的第一行隐式的默认调用父类的无参构造器即super()

多线程

线程状态

  • 新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
  • 就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
  • 运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
  • 阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

    • 等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
    • 同步阻塞 – 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
    • 其他阻塞 – 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
  • 死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。

sleep和wait的区别

  • 每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现同步方法或同步块。执行sleep()方法后正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!);wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度);
  • sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用;
  • sleep()是线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,再次获得对象锁才会进入运行状态;

线程安全

  • Vector HashTable StringBuffer statck enumeration是线程安全的.
  • ArrayList、 LinkedList、HashMap、StringBuilder 是非线程安全的。

死锁

产生死锁的原因主要是:

  1. 因为系统资源不足。

  2. 进程运行推进的顺序不合适。

  3. 资源分配不当等。

导致死锁的4个必要条件:

  1. 互斥条件。一次只有一个进程可以使用一个资源。其他进程不能访问已分配给其他进程的资源。

  2. 请求保持条件。当一个进程等待其他进程时,继续占有已经分配的资源。

  3. 不可剥夺条件。不能强行抢占进程已占有的资源。

  4. 循环等待条件。存在一个封闭的进程链,使得每个进程至少占有此链中下一个进程所需要的一个资源。

synchronized

当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。

  • 当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

  • 然而,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

  • 尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

  • 当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

HashMap

通过hash的方法,通过put和get存储和获取对象。存储对象时,我们将K/V传给put方法时,它调用hashCode计算hash从而得到bucket位置,进一步存储,HashMap会根据当前bucket的占用情况自动调整容量(超过Load Factor(负载因子)则resize为原来的2倍)。获取对象时,我们将K传给get,它调用hashCode计算hash从而得到bucket位置,并进一步调用equals()方法确定键值对。如果发生碰撞的时候,Hashmap通过链表将产生碰撞冲突的元素组织起来,在Java 8中,如果一个bucket中碰撞冲突的元素超过某个限制(默认是8),则使用红黑树来替换链表,从而提高速度。

当key出现hash冲突的时候,链表中的第一个元素都是后面最新添加进来的那个,之前的则被next变量引用着。虽然这里是插入的动作,但是由于使用了链表,所以无需像数组的插入那样,进行数组拷贝。

ArrayList与linkedList在性能上各有优缺点,都有各自的地方,

1.对ArrayList和LinkedList而言,在列表中末尾添加一个元素所花的开销是固定的

2.在ArrayList中间插入一个元素或删除一个元素意味着整个列表中剩余的元素都会移动,而LinkedList的中间插入或删除一个元素的开销是固定的

3.LinkedList不支持高效的随机访问

可以这样说:当操作是在一列数据后面添加数据而不是在前面或中间,并且是随机访问其中元素时,使用arrayList会提供比较好的性能;当你操作是在一列数据的前面或中间添加或删除数据,并不是按照顺序访问其中的元素,就应该使用LinkedList了

线程 join

主线程(我在“一”里已经命名过了)等待子线程的终止。也就是在子线程调用了join()方法后面的代码,只有等到子线程结束了才能执行。(Waits for this thread to die.)

乐观锁

总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。

悲观锁

总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中,synchronized的思想也是悲观锁。

Synchronized与ReentrantLock的区别

对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成。

美团Java2018面试模拟题经验

  • try{}语句块内不论有错误还是有return都会执行finally语句块,但下面的语句块不会再执行

  • RuntimeException 使用try{},catc{}捕获不是必须的

  • sleep()方法并不会让出cpu

  • 如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承

  • finally在异常处理时提供 finally 块来执行任何清除操作
  • Java使用 finalize() 方法在垃圾收集器象从内存中清除出去之前做必要的清理工作
  • static{}静态代码块首先执行,即,静态代码块->非静态代码块->构造器
  • Object类中没有copy方法
  • 接口只能用public修饰,并且是抽象的;其中只能是抽象方法
  • 子类不能继承父类构造方法,一个子类只能继承一个父类
  • 构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法。
  • int 和Integer在进行比较的时候,Integer会进行拆箱,转为int值与int进行比较。整Integer字面量的值在-128到127之间,那么不会new新的Integer对象,而是直接引用常量池中的Integer对象
  • Integer i01 = 59,java在编译的时候,被翻译成-> Integer i01 = Integer.valueOf(59);
  • 初始化时int类的变量初始为0.而Integer的变量则初始化为null.
  • 自动装箱:Integer字面量的值在-128到127之间, Integer a = 127;相当于Integer a = new Integer(127)
  • 方法中的局部变量,存放在栈区,类中的成员变量,存放在堆区
  • JAVA语言不允许程序员直接控制内存空间的使用。内存空间的分配和回收都是由JRE负责在后台自动进行的,尤其是无用内存空间的回收操作 (garbagecollection,也称垃圾回收),只能由运行环境提供的一个超级线程进行监测和控制。

Byte范围

是-128~127 127+1=-128

构造器

没有返回类型,并不是void

Java源程序

一个源程序只能有一个public类存在,且类名与文件名相同.

抽象类:

  • 抽象类不能实例化,因为有抽象方法未实现
  • 可以被继承。派生类可以实现抽象方法
  • 子类可以是抽象的,也可以非抽象的
  • 可以被抽象类继承,也可以被非抽象类继承

Java类成员的访问控制权限:

public > protected > 同包(default) > private

重写与重载

子类重写父类方法,调用时会调用子类重写之后的方法,包括父类构造器中调用父类的方法会变成重载后子类的方法,注意实例化顺序

包导入

Java.awt.*只能导入awt这个包中的所有类,awt中的包中的类不会导入

编译与运行

执行 Base b = new Sub();时由于多态 b编译时表现为Base类特性,运行时表现为Sub类特性,编译看左边,运行看右边。

内部类

内部类其实和类的属性没什么区别,只是在声明的时候必须是Outer.Inner a

PHP

错误控制

php 支持一个错误控制运算符:@。当将其放置在一个 php 表达式之前,该表达式可能产生的任何错误信息都被忽略掉

实例化

php实例化类无参数可不带括号

关联数组无key情况

对关联数组新增不带键的元素,若前面的元素有数字(或数字字符)键,新增元素的键为前面最大的数字加1。若前面的元素无数字键,新增元素的键为0。

empty函数

bool empty ( mixed $var )
如果 var 是非空或非零的值,则 empty() 返回 FALSE。换句话说,””、0、”0”、NULL、FALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果 var 为空,则返回 TRUE。

unset函数

unset($a)相当于对$a变量内存引用-1,如果引用为0才回收内存。

PHP final

php和Java不同,Java中类属性是可以用final修饰表示的是常量,PHP不能,因为PHP的常量只能用define定义。

  • final—用于类、方法前。
  • final类—不可被继承。
  • final方法—不可被覆盖。