Java 春招知识点总结

2019-03-22  本文已影响0人  月小水长

TCP 三次握手和四次挥手

三次握手
  1. 第一次
    第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
  2. 第二次
    第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
  3. 第三次
    第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
  4. 完成三次握手,客户端与服务器开始传送数据,在上述过程中,还有一些重要的概念:未连接队列。

在三次握手协议中,服务器维护一个未连接队列,该队列为每个客户端的SYN包(syn=j)开设一个条目,该条目表明服务器已收到SYN包,并向客户发出确认,正在等待客户的确认包。这些条目所标识的连接在服务器处于 Syn_RECV状态,当服务器收到客户的确认包时,删除该条目,服务器进入ESTABLISHED状态。

四次挥手
  1. TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
  2. 服务器收到这个FIN,它发回一个ACK,确认序号为收到的序号加1。和SYN一样,一个FIN将占用一个序号。
  3. 服务器关闭客户端的连接,发送一个FIN给客户端。
  4. 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
关于为什么要三次握手和四次分手

参考一
参考二

== 和 equals 的区别是什么?

  1. == 的作用
  1. equals 的作用
  1. 测试代码 1
public class Test {
    private static class Demo{
        private int val;
        private Demo(int v){
            val = v;
        }
    }
    public  static void main(String [] args){
        int i1 = 5;
        int i2 = 5;
        System.out.println(i1 == i2);
        // int 不是引用类型的实例(对象),所以没有 equals

        Demo d1 = new Demo(5);
        Demo d2 = new Demo(5);
        System.out.println(d1 == d2);
        System.out.println(d1.equals(d2));
        // equals() 默认是引用比较。

        String s1 = new String("666");
        String s2 = new String("666");
        System.out.println(s1 == s2);
        System.out.println(s1.equals(s2));
        // 但是 String 重写了 equals方法,使之成为了值比较。
    }
}

测试 1 的输出为:

true
false
false
false
true
  1. 测试代码2
public class Test {
    public static void main(String [] args){
        String info = "b";
        String A = "abc";
        String B = "a"+info+"c";
        String C = "a"+"b"+"c";
        // == 在引用类型下比较的是引用是否相同
        System.out.println(A==B);
        System.out.println(A==C);
    }
}

其输出如下:

false
true

最开始,我对这样的结果也很讶异,我预测的是两个输出都是 false, 因为 String 的 + 语法糖底层是通过 new StringBuffer(),然后调用 append() 和 toString() 实现的,明显引用不一样了,应该都输出 false,但是这里还有更深层次的知识。
对象 info 和 A 均使用的字符串字面量,说白话点,就是直接把字符串写死,在编译期间,这种字面量会直接放入 class 文件的常量池中,从而实现复用。C 虽然是动态拼接出来的字符串,但是所有参与拼接的部分都是已知的字面量,在编译期间,这种拼接会被优化,编译器直接帮你拼好,因此String C = "a" + "b" + "c";在class文件中被优化成String C = "abc",A、C指向的是同一个内存地址所以A == C成立,但是 B 的拼接过程中除了拼接字符串字面量,还有 info 这个对象的参与,因此无法在编译期间做优化,B 指向了和 A 不同的内存地址。

类修饰符

修饰符 类别 含义
public 访问控制符 将一个类声明为公共类,它可以被任何对象访问;每个 Java 程序有且只有一个类是 public,它被称为主类 ,其他外部类无访问控制修饰符,具有包访问性。
缺省 访问控制符 缺省修饰符时,这个类只能被同一个包中的类访问或引用;这一访问特性又称为包访问性。
abstract 访问控制符 将一个类声明为抽象类,没有任何实现方法,需要子类提供方法的实现,所以不能创建该类的实例。
final 访问控制符 将一个类声明为非继承类,则表示它不能被其他类继承。

上面所说的修饰符应该是针对外部类来说的,一个类的内部类可以被其他访问控制修饰符 protected、default、private 和非访问控制符 static、final等修饰。总的来说,内部类在修饰符上的使用上,类似于类的成员(内部类可用的修饰符只是类成员可用的修饰符的一个真子集;而且具体访问权限还有细微的差别,因此只能说类似)。

(常用)成员变量/方法修饰符

修饰符 类别 含义
public 访问控制符 指定该变量/方法为公共的,它可以被任何对象访问。
private 访问控制符 指定该变量/方法只允许自己类的方法访问,其他任何类(包括子类)中的方法均不能访问此变量/方法。
protected 访问控制符 指定该变量/方法只可以被它自己的类及其子类或同一包中的其他类访问。在子类中可以覆盖此变量。
缺省 访问控制符 表示同一包中的其他类可以访问此成员变量/方法,其它包则不能。
final 访问控制符 指定该变量不能改变/该方法不能被重载
static 访问控制符 指定该变量被所有实例共享/指定不需要实例化一个对象就能调用该方法

注意,无论什么修饰符,某类的所有成员总是对该类的方法和实例可见!

接口和抽象类的联系与区别

联系
  1. 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其他类实现和继承。

  2. 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。

区别
  1. 接口里只能包含抽象方法,静态方法和默认方法,不能为普通方法提供方法实现,抽象类则完全可以包含普通方法。

  2. 接口里只能定义静态常量,不能定义普通成员变量,抽象类里则既可以定义普通成员变量,也可以定义静态常量。

  3. 接口不能包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。

  4. 接口里不能包含初始化块,但抽象类里完全可以包含初始化块。

  5. 一个类最多只能有一个直接父类,包括抽象类,但一个类可以直接实现多个接口,通过实现多个接口可以弥补 Java 单继承的不足。

String、StringBuilder、StringBuffer的区别

String 创建的是不可变的对象,修改字符串需要 JVM 创建、回收 String 对象,比较耗时,适用于少量操作字符串的场景。
StringBuilder 可以在原有对象上进行操作,但却是非线程安全的,适用于单线程下频繁操作字符串的场景。
StringBuffer 在 StringBuilder 的基础上对某些方法新增了synchronized锁原语,所以是线程安全的,也正是这个原因,StringBuffer 的速度要慢于 StringBuilder;适用于多线程下频繁操作字符串的场景。

上一篇下一篇

猜你喜欢

热点阅读