Java高级:面试题-1

Java高级面试题

  • 网络编程
    • 简答题
  • NIO(Netty)
  • JVM
    • 选择题
    • 简答题
      • java的四种引用,强弱软虚,用到的场景
      • OOM
      • 运行时数据区域
      • 垃圾收集
  • 多线程(并发)编程
    • 选择题
    • 填空题
    • 简答题
      • 定义类ThdTest,其父类为Thread类;并在主方法中创建一个ThdTest的对象,同时启动该线程对象。
      • 线程状态转换
      • Thread与Runable如何实现多线程**
      • 线程同步的方法有什么
      • 线程锁的等级
      • 生产者消费者模式的几种实现
      • wait()和sleep()的区别
      • IO框架主要用到什么设计模式
      • volatile变量修饰符
      • 多线程环境中安全使用集合API
      • 死锁
      • 什么是多线程
      • 说一下多线程的好处
      • 线程和进程有什么区别
      • 什么是线程同步.   异步
      • 线程之间如何同步
      • 什么是线程不安全?如何解决?
      • 如何创建一个线程?有几种方法?
      • sleep()和 wait()有什么区别?
    • 参考
  • 设计模式
  • 源码分析
  • 数据库设计
    • 简答题
      • MySQL
      • 基础知识
      • 什么是事务
      • MySQL -SQL
  • 算法
    • 简答题
    • 编程题
      • 有序数组的 Two Sum
  • 数据结构
    • 选择题
    • 填空题
    • 简答题
        • 数据结构——树——知识点总结
        • 找出两个链表的交点
      • 树的高度
      • 数组中两个数的和为给定值
    • 编程题
  • 容器
    • 选择题
    • 填空题
    • 简答题
    • 编程题
  • 协议
    • 简答题
      • TCP的三次握手和四次挥手,浏览器访问一个网址的过程
      • TCP与UDP区别
      • HTTP、HTTPS区别

网络编程

简答题

  • 网络中的每台计算机都必须有一个唯一的 IP 地址作为标识。
  • 通常IP地址写作一组有 “.”号分隔的 十 进制数。
  • IPv4规定的IP地址都是 32 位地址。
  • IPv6的地址是 48 位无符号整数。
  • 假若要编写一个网络通信程序,则需在程序最开头引用 java.net 类包。
  • 通常IP地址均有4个部分组成,每个部分的范围都是0~ 255 。
  • 在java.net包中,IP地址由一个称为 InetAddress 的特殊的类来描述。
  • 通常端口号的取值范围为0~ 65535 之间。
  • 通常0~ 1023 间的端口号作为保留端口号。
  • UDP 协议不保证数据传输的可靠性。
  • 在网络通信程序中,使用 端口号 来标识正在运行的进程。
  • 两种常用的网络通信协议是 TCP 和 UDP 。
  • TCP 是面向连接的通信协议。
  • UDP 是无连接的通信协议。
  • Transmission Control Protocol指的是 传输控制协议 。
  • UDP的英文全称为 Use Datagram Packet 。
  • TCP 协议提供的是可靠无差错的数据传输。
  • 在TCP/IP中, socket 是由IP地址与端口号组成。
  • 在建立套接字连接过程中,通常把负责监听的一方称为 服务器 。
  • 客户端使用 Socket 类建立套接字连接。
  • 编写网络服务器程序说,使用 ServerSocket 类来创建服务器端的连接。
  • Socket提供了两台不同计算机上执行的应用程序之间进行连接的功能。
  • 服务器端使用 accept 方法监听客户端发起的连接请求。
  • Socket获取输入/输出流的两个主要方法是:getInputStream()和getOutputStream() 。
  • 网络数据通信,通常采用 流式通信 模式。
  • 在服务器端程序中应用 多线程 技术同时处理多个客户端的连接请求。
  • 基于UDP网络程序设计中,使用 DatagramSocket 类来创建套接字连接。
  • DatagramSocket类的实例对象使用 send() 方法发送数据。
  • DatagramSocket类的实例对象使用 receive() 方法接收数据。
  • DatagramPacket 类用于将要发送的数据打包或将已经接收到的数据进行拆包。
  • 关闭套接字需使用 close() 方法。

NIO(Netty)

JVM

选择题

  • 下列哪些语句关于内存回收的说明是正确的? ( D )
    A.   程序员必须创建一个线程来释放内存;
    B.   内存回收程序负责释放无用内存
    C.   内存回收程序允许程序员直接释放内存
    D.   内存回收程序可以在指定的时间释放内存对象

简答题

java的四种引用,强弱软虚,用到的场景

JDK1.2之前只有强引用,其他几种引用都是在JDK1.2之后引入的.

强引用(Strong Reference) 最常用的引用类型,如Object obj = new Object(); 。只要强引用存在则GC时则必定不被回收。

软引用(Soft Reference) 用于描述还有用但非必须的对象,当堆将发生OOM(Out Of Memory)时则会回收软引用所指向的内存空间,若回收后依然空间不足才会抛出OOM。一般用于实现内存敏感的高速缓存。 当真正对象被标记finalizable以及的finalize()方法调用之后并且内存已经清理, 那么如果SoftReference object还存在就被加入到它的 ReferenceQueue.只有前面几步完成后,Soft Reference和Weak Reference的get方法才会返回null

弱引用(Weak Reference) 发生GC时必定回收弱引用指向的内存空间。 和软引用加入队列的时机相同

虚引用(Phantom Reference) 又称为幽灵引用或幻影引用,虚引用既不会影响对象的生命周期,也无法通过虚引用来获取对象实例,仅用于在发生GC时接收一个系统通知。 当一个对象的finalize方法已经被调用了之后,这个对象的幽灵引用会被加入到队列中。通过检查该队列里面的内容就知道一个对象是不是已经准备要被回收了. 虚引用和软引用和弱引用都不同,它会在内存没有清理的时候被加入引用队列.虚引用的建立必须要传入引用队列,其他可以没有

OOM

  1.   OutOfMemoryError异常

除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生OutOfMemoryError(OOM)异常的可能,

  1.   Java Heap 溢出

一般的异常信息:java.lang.OutOfMemoryError:Java heap spacess

java堆用于存储对象实例,我们只要不断的创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量达到最大堆容量限制后产生内存溢出异常。

出现这种异常,一般手段是先通过内存映像分析工具(如Eclipse Memory Analyzer)对dump出来的堆转存快照进行分析,重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链。于是就能找到泄漏对象时通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收。

如果不存在泄漏,那就应该检查虚拟机的参数(-Xmx与-Xms)的设置是否适当。

虚拟机栈和本地方法栈溢出

如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

这里需要注意当栈的大小越大可分配的线程数就越少。

  1.   运行时常量池溢出

异常信息:java.lang.OutOfMemoryError:PermGen space

如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。该方法的作用是:如果池中已经包含一个等于此String的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。由于常量池分配在方法区内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区的大小,从而间接限制其中常量池的容量。

  1.   方法区溢出

方法区用于存放Class的相关信息,如类名.   访问修饰符.   常量池.   字段描述.   方法描述等。

异常信息:java.lang.OutOfMemoryError:PermGen space

方法区溢出也是一种常见的内存溢出异常,一个类如果要被垃圾收集器回收,判定条件是很苛刻的。在经常动态生成大量Class的应用中,要特别注意这点。

运行时数据区域

Java高级:面试题-1_第1张图片
(1)程序计数器

记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)。

(2)Java 虚拟机栈

每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表.   操作数栈.   常量池引用等信息。从方法调用直至执行完成的过程,对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
Java高级:面试题-1_第2张图片
可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小,在 JDK 1.4 中默认为 256K,而在 JDK 1.5+ 默认为 1M:

java -Xss2M HackTheJava

该区域可能抛出以下异常:

  1.   当线程请求的栈深度超过最大值,会抛出 StackOverflowError 异常;

  2.   栈进行动态扩展时如果无法申请到足够内存,会抛出 OutOfMemoryError 异常。

(3)本地方法栈

本地方法栈与 Java 虚拟机栈类似,它们之间的区别只不过是本地方法栈为本地方法服务。

本地方法一般是用其它语言(C.   C++ 或汇编语言等)编写的,并且被编译为基于本机硬件和操作系统的程序,对待这些方法需要特别处理。
Java高级:面试题-1_第3张图片
(4)堆

所有对象都在这里分配内存,是垃圾收集的主要区域(“GC 堆”)。

现代的垃圾收集器基本都是采用分代收集算法,其主要的思想是针对不同类型的对象采取不同的垃圾回收算法。可以将堆分成两块:

新生代(Young Generation)

老年代(Old Generation)

堆不需要连续内存,并且可以动态增加其内存,增加失败会抛出 OutOfMemoryError 异常。

可以通过 -Xms 和 -Xmx 这两个虚拟机参数来指定一个程序的堆内存大小,第一个参数设置初始值,第二个参数设置最大值。

java -Xms1M -Xmx2M HackTheJava

(5)方法区

用于存放已被加载的类信息.   常量.   静态变量.   即时编译器编译后的代码等数据。

和堆一样不需要连续的内存,并且可以动态扩展,动态扩展失败一样会抛出 OutOfMemoryError 异常。

对这块区域进行垃圾回收的主要目标是对常量池的回收和对类的卸载,但是一般比较难实现。

HotSpot 虚拟机把它当成永久代来进行垃圾回收。但很难确定永久代的大小,因为它受到很多因素影响,并且每次 Full GC 之后永久代的大小都会改变,所以经常会抛出 OutOfMemoryError 异常。为了更容易管理方法区,从 JDK 1.8 开始,移除永久代,并把方法区移至元空间,它位于本地内存中,而不是虚拟机内存中。

方法区是一个 JVM 规范,永久代与元空间都是其一种实现方式。在 JDK 1.8 之后,原来永久代的数据被分到了堆和元空间中。元空间存储类的元信息,静态变量和常量池等放入堆中。

(6)运行时常量池

(7)直接内存

在 JDK 1.4 中新引入了 NIO 类,它可以使用 Native 函数库直接分配堆外内存,然后通过 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在堆内存和堆外内存来回拷贝数据。

垃圾收集

垃圾收集主要是针对堆和方法区进行。程序计数器.   虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后就会消失,因此不需要对这三个区域进行垃圾回收。

(1)判断一个对象是否可被回收

① 引用计数算法

为对象添加一个引用计数器,当对象增加一个引用时计数器加 1,引用失效时计数器减 1。引用计数为 0 的对象可被回收。

在两个对象出现循环引用的情况下,此时引用计数器永远不为 0,导致无法对它们进行回收。正是因为循环引用的存在,因此 Java 虚拟机不使用引用计数算法。

② 可达性分析算法

以 GC Roots 为起始点进行搜索,可达的对象都是存活的,不可达的对象可被回收。

Java 虚拟机使用该算法来判断对象是否可被回收,GC Roots 一般包含以下内容:

  1. 虚拟机栈中局部变量表中引用的对象
  2. 本地方法栈中 JNI 中引用的对象
  3. 方法区中类静态属性引用的对象
  4. 方法区中的常量引用的对象
    Java高级:面试题-1_第4张图片
    ③ 方法区的回收

因为方法区主要存放永久代对象,而永久代对象的回收率比新生代低很多,所以在方法区上进行回收性价比不高。

主要是对常量池的回收和对类的卸载。

为了避免内存溢出,在大量使用反射和动态代理的场景都需要虚拟机具备类卸载功能。

类的卸载条件很多,需要满足以下三个条件,并且满足了条件也不一定会被卸载:

  1. 该类所有的实例都已经被回收,此时堆中不存在该类的任何实例。
  2. 加载该类的 ClassLoader 已经被回收。
  3. 该类对应的 Class 对象没有在任何地方被引用,也就无法在任何地方通过反射访问该类方法。

④ finalize()

类似 C++ 的析构函数,用于关闭外部资源。但是 try-finally 等方式可以做得更好,并且该方法运行代价很高,不确定性大,无法保证各个对象的调用顺序,因此最好不要使用。

当一个对象可被回收时,如果需要执行该对象的 finalize() 方法,那么就有可能在该方法中让对象重新被引用,从而实现自救。自救只能进行一次,如果回收的对象之前调用了 finalize() 方法自救,后面回收时不会再调用该方法。

多线程(并发)编程

选择题

  • 下列关于Java线程的说法那些是正确的( D )
    A.   每一个Java线程可以看成由代码.   一个真实的CPU以及数据三部份组成。
    B.   创建线程的两种方法中,从Thread类中继承的创建方式可以防止出现多父类问题。
    C.   Thread类属于java.util程序包。
    D.   以上说法无一正确。

  • 下面哪个不是Thread类的方法?( C )
    A.   yield()
    B.   sleep(long msec)
    C.   go()
    D.   stop()

  • 运行下列程序, 会产生什么结果 ( A 应该是runnable )

      public class X extends Thread implements Runable{ 
       public void run(){ 
        System.out.println("this is run()"); 
       } 
       public static void main(String args[]) 
       { 
        Thread t=new Thread(new X()); 
        t.start(); 
       } 
      } 

  A.   第一行会产生编译错误
  B.   第六行会产生编译错误
  C.   第六行会产生运行错误
  D.   程序会运行和启动

  • 运行下列程序, 会产生什么结果 ( D )
  public class X extends Thread implements Runable{ 
    public void run(){ 
     	System.out.println("this is run()"); 
    } 
    public static void main(String args[]) { 
     	Thread t=new Thread(new X()); 
     	t.start(); 
    } 
  } 

  A.   in the Inner outer
  B.   outer
  C.   in the Inner
  D.   编译不通过

填空题

  • 实现并发机制的一种有效手段是 多线程 。
  • 一个程序具备同时执行不同任务的能力,这种能力称为 并发 。
  • 每个线程都经历创建.   就绪.   运行.   阻塞和 死亡 等5个状态。
  • 处于就绪状态的线程何时可真正的执行,取决于线程的 优先级以及队列当前状况。
  • 在Java系统中,线程调度依据优先级基础上的 抢夺式调度 原则。
  • Java提供的 监视器机制,可以避免对象在内存中的数据资源的冲突。
  • 在单线程的进程中,一个进程一次只能执行 1 个任务。
  • Java线程同步机制提供关键字 Synchronized ,用于修饰可能引起资源冲突的方法。
  • 优先级低**的线程获得CPU的机会也比较 **小。
  • 低优先级线程在较长时间内无法获得运行机会的现象就是所谓的饿死。
  • 创建多线程的途径有两种:创建Thread类的子类与实现Runnable 接口。
  • 线程是比进程更 小 的执行单位。
  • 一个进程在其执行的过程中,可以产生 多 个线程。
  • 程序的一次动态执行过程,则称为 进程 。
  • 程序是一段静态的代码,它是应用软件执行的蓝本。
  • 一个正在执行的线程由于系统或人为原因被迫让出CPU的使用权,这种现象称为 阻塞 。
  • 一个进入阻塞状态的线程,只有当引起阻塞的原因被消除时,线程才可以转入 就绪 状态。
  • 假若一个正在执行的线程被人为中断,那么该线程会暂时中止自己的执行,进入 就绪 状态。
  • 线程的优先级范围用数字表示:0~10,那么一个线程的默认优先级是 5 。
  • 线程释放分配给线程对象的内存,就是所谓的 死亡 状态。
  • 进入线程的生命周期的第一个状态是 新建 状态。
  • 假若要实现Runnable接口,就必须具体实现接口中的 run()方法。
  • 线程调用 start 方法来启动线程。
  • 当一个线程执行完run()方法时,线程进入 死亡 状态。
  • 线程调用 sleep() 方法来使自己放弃处理器资源,休眠一段时间。
  • sleep(int)方法中,休眠时间的单位为 毫秒 。
  • 判断当前正在占有CPU的线程的方法是 currentthread() 。
  • Runnable接口中只有一个 run 方法。
  • 线程同步机制中,调用 wait() 方法使线程进入等待状态。
  • 通知线程状态的变化并唤醒另一个等待线程,需应用 notify() 方法。
  • 所有等待的线程将无休止地等待下去,就是所谓的 死锁 。
  • 当两个或多个线程要同时访问共享数据时,一次只允许一个线程访问共享 资源,支持这种互斥机制称为 同步 。
  • Java多线程编程中,用 Synchronized 来标识的区域或方法为锁定的资源。
  • 在Java中,运行环境使用 监视器 来解决线程同步的问题。
  • 线程同步执行过程中,wait()方法与 notify() 方法是匹配使用,否则易造成死锁。
  • 在特定应用程序中所有的线程处在等待状态,并且相互等待其他线程唤醒,这种现象称为 死锁 。

简答题

定义类ThdTest,其父类为Thread类;并在主方法中创建一个ThdTest的对象,同时启动该线程对象。

  public class TestDemo {
      public static void main(String[] args) {
          new ThdTest().start();
  
          System.out.println(Thread.currentThread().getName());
      }
  }
  
  //声明类ThdTest,其父类为Thread类
  class ThdTest extends Thread {
      @Override
      public void run() {
          for (int i = 0; i < 10; i++) {
              Thread.currentThread().setName("第【" + i + "】线程");
              try {
                  Thread.sleep(100);
                  System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId());
              } catch (InterruptedException ex) {
                  throw new RuntimeException("因为未知原因【" + i + "】线程中断");
              }
          }
      }
  }

线程状态转换

Java高级:面试题-1_第5张图片

  1.   新建(New)

创建后尚未启动。

  1.   可运行(Runnable)

可能正在运行,也可能正在等待 CPU 时间片。

包含了操作系统线程状态中的 Running 和 Ready。

  1.   阻塞(Blocked)

等待获取一个排它锁,如果其线程释放了锁就会结束此状态。

  1.   无限期等待(Waiting)

等待其它线程显式地唤醒,否则不会被分配 CPU 时间片。

进入方法 退出方法
没有设置 Timeout 参数的 Object.wait() 方法 Object.notify() / Object.notifyAll()
没有设置 Timeout 参数的 Thread.join() 方法 被调用的线程执行完毕
LockSupport.park() 方法 LockSupport.unpark(Thread)

  1.   限期等待(Timed Waiting)

无需等待其它线程显式地唤醒,在一定时间之后会被系统自动唤醒。

调用 Thread.sleep() 方法使线程进入限期等待状态时,常常用“使一个线程睡眠”进行描述。

调用 Object.wait() 方法使线程进入限期等待或者无限期等待时,常常用“挂起一个线程”进行描述。

睡眠和挂起是用来描述行为,而阻塞和等待用来描述状态。

阻塞和等待的区别在于,阻塞是被动的,它是在等待获取一个排它锁。而等待是主动的,通过调用 Thread.sleep() 和 Object.wait() 等方法进入。

进入方法 退出方法
Thread.sleep() 方法 时间结束
设置了 Timeout 参数的 Object.wait() 方法 时间结束 / Object.notify() / Object.notifyAll()
设置了 Timeout 参数的 Thread.join() 方法 时间结束 / 被调用的线程执行完毕
LockSupport.parkNanos() 方法 LockSupport.unpark(Thread)
LockSupport.parkUntil() 方法 LockSupport.unpark(Thread)

  1.   死亡(Terminated)

可以是线程结束任务之后自己结束,或者产生了异常而结束。

Thread与Runable如何实现多线程**

Java 5以前实现多线程有两种实现方法:一种是继承Thread类;另一种是实现Runnable接口。两种方式都要通过重写run()方法来定义线程的行为,推荐使用后者,因为Java中的继承是单继承,一个类有一个父类,如果继承了Thread类就无法再继承其他类了,显然使用Runnable接口更为灵活。

实现Runnable接口相比继承Thread类有如下优势:

  1.   可以避免由于Java的单继承特性而带来的局限

  2.   增强程序的健壮性,代码能够被多个程序共享,代码与数据是独立的

  3.   适合多个相同程序代码的线程区处理同一资源的情况

线程同步的方法有什么

锁,synchronized块,信号量等。

线程锁的等级

方法锁.   对象锁.   类锁

生产者消费者模式的几种实现

阻塞队列实现,sync关键字实现,lock实现,reentrantLock等。

wait()和sleep()的区别

sleep()方法是线程类(Thread)的静态方法,导致此线程暂停执行指定时间,将执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复(线程回到就绪(ready)状态),因为调用sleep 不会释放对象锁。

wait()是Object 类的方法,对此对象调用wait()方法导致本线程放弃对象锁(线程暂停执行),进入等待此对象的等待锁定池,只有针对此对象发出notify 方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入就绪状态。

IO框架主要用到什么设计模式

JDK的I/O包中就主要使用到了两种设计模式:Adatper模式和Decorator模式。

volatile变量修饰符

在JDK1.2之前,Java的类型模型实现总是从主存(即共享内存)读取变量,是不需要进行特别的注意的。而随着JVM的成熟和优化,现在在多线程环境下volatile关键字的使用变的非常重要。

在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另一个线程还在继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。

要解决这个问题,就需要把变量声明为volatile,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。一般来说,多任务环境下,各任务间共享的变量都应该加volatile修饰符。

volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

Java语言规范中指出:为了获得最佳速度,允许线程保存成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才将私有拷贝与共享内存中的原始值进行比较。

这样当多个线程同时与某个对象交互时,就必须注意到要让线程及时的得到共享成员变量的变化。而volatile关键字就是提示JVM:对于这个成员变量,不能保存它的私有拷贝,而应直接与共享成员变量交互。

volatile是一种稍弱的同步机制,在访问volatile变量时不会执行加锁操作,也就不会执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制。

使用建议:在两个或者更多的线程需要访问的成员变量上使用volatile。当要访问的变量已在synchronized代码块中,或者为常量时,或者为常量时,没必要使用volatile。

由于使用volatile屏蔽掉了JVM中必要的代码优化,所以在效率上比较低,因此一定在必要时才使用此关键字。

多线程环境中安全使用集合API

在集合API中,最初设计的Vector和Hashtable是多线程安全的。例如:对于Vector来说,用来添加和删除元素的方法是同步的。如果只有一个线程与Vector的实例交互,那么,要求获取和释放对象锁便是一种浪费,另外在不必要的时候如果滥用同步化,也有可能会带来死锁。因此,对于更改集合内容的方法,没有一个是同步化的。集合本质上是非多线程安全的,当多个线程与集合交互时,为了使它多线程安全,必须采取额外的措施。

在Collections类 中有多个静态方法,它们可以获取通过同步方法封装非同步集合而得到的集合:

    public static Collection synchronizedCollention(Collection c)
    public static List synchronizedList(list l)
    public static Map synchronizedMap(Map m)
    public static Set synchronizedSet(Set s)
    public static SortedMap synchronizedSortedMap(SortedMap sm)
    public static SortedSet synchronizedSortedSet(SortedSet ss)

这些方法基本上返回具有同步集合方法版本的新类。比如,为了创建多线程安全且由ArrayList支持的List,可以使用如下代码:

    List list = Collection.synchronizedList(new ArrayList());

注意,ArrayList实例马上封装起来,不存在对未同步化ArrayList的直接引用(即直接封装匿名实例)。这是一种最安全的途径。如果另一个线程要直接引用ArrayList实例,它可以执行非同步修改。

这里需要注意的是:在Java语言中,大部分的线程安全类都是相对线程安全的,它能保证对这个对象单独的操作时线程安全的,我们在调用的时候不需要额外的保障措施,但是对于一些特定的连续调用,就可能需要在调用端使用额外的同步手段来保证调用的正确性。例如Vector.   HashTable.   Collections的synchronizedXxxx()方法包装的集合等。

死锁

当线程需要同时持有多个锁时,有可能产生死锁。考虑如下情形:

线程A当前持有互斥所锁lock1,线程B当前持有互斥锁lock2。接下来,当线程A仍然持有lock1时,它试图获取lock2,因为线程B正持有lock2,因此线程A会阻塞等待线程B对lock2的释放。如果此时线程B在持有lock2的时候,也在试图获取lock1,因为线程A正持有lock1,因此线程B会阻塞等待A对lock1的释放。二者都在等待对方所持有锁的释放,而二者却又都没释放自己所持有的锁,这时二者便会一直阻塞下去。这种情形称为死锁。

什么是多线程

在一个应用程序中,同时,有多个不同的执行路径。

说一下多线程的好处

提供程序效率。

线程和进程有什么区别

线程是进程的一条执行路径,而进程是线程的集合。

什么是线程同步.   异步

线程同步表示,当前线程执行完后下一个线程接着执行。

线程异步表示, 在一个应用程序中,同时,有多个不同的执行路径。例如 javaweb ajax android handler

线程之间如何同步

线程之间同步使用 synchronized.   wait 与 notify

什么是线程不安全?如何解决?

就是在多个线程共享同一个数据会受到其他线程的干扰。如何解决:使用线程同步技术, 用上锁(synchronized)。 让一个线程执行完了,在让另一个线程执行。

如何创建一个线程?有几种方法?

继承thread类, 重写run方法.   实现Runnalbe接口,重新run方法 , 启动一个线程用start();

sleep()和 wait()有什么区别?

a.   sleep是让当前线程指定休眠时间,然后继续工作 不释放锁

b.   让当前线程wait则是等待,直到有线程通知notify()唤醒他才会重新工作。释放锁

参考

多线程(一):创建线程和线程的常用方法

设计模式

源码分析

数据库设计

简答题

MySQL

  • Mysql 的存储引擎,myisam和innodb的区别?
    1.MyISAM 是非事务的存储引擎,适合用于频繁查询的应用。表锁,不会出现死锁,适合小数据,小并发。
    2.innodb是支持事务的存储引擎,合于插入和更新操作比较多的应用,设计合理的话是行锁(最大区别就在锁的级别上),适合大数据,大并发。

  • 数据表类型有哪些?
    MyISAM.   InnoDB.   HEAP.   BOB,ARCHIVE,CSV等。
    MyISAM:成熟.   稳定.   易于管理,快速读取。一些功能不支持(事务等),表级锁。
    InnoDB:支持事务.   外键等特性.   数据行锁定。空间占用大,不支持全文索引等。

  • MySQL数据库作发布系统的存储,一天五万条以上的增量,预计运维三年,怎么优化?
    a. 设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
    b. 选择合适的表字段数据类型和存储引擎,适当的添加索引。
    c. mysql库主从读写分离。
    d. 找规律分表,减少单表中的数据量提高查询速度。
    e. 添加缓存机制,比如memcached,apc等。
    f. 不经常改动的页面,生成静态页面。
    g. 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE.

  • 对于大流量的网站,您采用什么样的方法来解决各页面访问量统计问题?
    a. 确认服务器是否能支撑当前访问量。
    b. 优化数据库访问。
    c. 禁止外部访问链接(盗链), 比如图片盗链。
    d. 控制文件下载。
    e. 使用不同主机分流。
    f. 使用浏览统计软件,了解访问量,有针对性的进行优化。

  • 如何进行SQL优化?
    (1)选择正确的存储引擎
    以 MySQL为例,包括有两个存储引擎 MyISAM 和 InnoDB,每个引擎都有利有弊。
    MyISAM 适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。
    InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。但是它支持“行锁” ,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。
    (2)优化字段的数据类型
    记住一个原则,越小的列会越快。如果一个表只会有几列罢了(比如说字典表,配置表),那么,我们就没有理由使用 INT 来做主键,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 会更经济一些。如果你不需要记录时间,使用 DATE 要比 DATETIME 好得多。当然,你也需要留够足够的扩展空间。

    (3)为搜索字段添加索引
    索引并不一定就是给主键或是唯一的字段。如果在你的表中,有某个字段你总要会经常用来做搜索,那么最 好 是为其建立索引,除非你要搜索的字段是大的文本字段,那应该建立全文索引。

    (4)避免使用Select
    避免使用Select 从数据库里读出越多的数据,那么查询就会变得越慢。并且,如果你的数据库服务器和WEB服务器是两台独立的服务器的话,这还会增加网络传输的负载。即使你要查询数据表的所有字段,也尽 量不要用通配符,善用内置提供的字段排除定义也许能给带来更多的便利。

    (5)使用 ENUM 而不是 VARCHAR
    ENUM 类型是非常快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。这样一来,用 这个字段来做一些选项列表变得相当的完美。例如,性别.   民族.   部门和状态之类的这些字段的取值是有限 而且固定的,那么,你应该使用 ENUM 而不是 VARCHAR。

    (6)尽可能的使用 NOT NULL
    除非你有一个很特别的原因去使用 NULL 值,你应该总是让你的字段保持 NOT NULL。 NULL其实需要额外的 空间,并且,在你进行比较的时候,你的程序会更复杂。 当然,这里并不是说你就不能使用NULL了,现实情 况是很复杂的,依然会有些情况下,你需要使用NULL值。

    (7)固定长度的表会更快
    如果表中的所有字段都是“固定长度”的,整个表会被认为是 “static” 或 “fixed-length”。 例如,表中没有如下 类型的字段: VARCHAR,TEXT,BLOB。只要你包括了其中一个这些字段,那么这个表就不是“固定长度静态 表”了,这样,MySQL 引擎会用另一种方法来处理。

固定长度的表会提高性能,因为MySQL搜寻得会更快一些,因为这些固定的长度是很容易计算下一个数据的偏移量的,所以读取的自然也会很快。而如果字段不是定长的,那么,每一次要找下一条的话,需要程序找到主键。

并且,固定长度的表也更容易被缓存和重建。不过,唯一的副作用是,固定长度的字段会浪费一些空间,因为定长的字段无论你用不用,他都是要分配那么多的空间。

如何设计一个高并发的系统
① 数据库的优化,包括合理的事务隔离级别.   SQL语句优化.   索引的优化
② 使用缓存,尽量减少数据库 IO
③ 分布式数据库.   分布式缓存
④ 服务器的负载均衡

锁的优化策略
① 读写分离
② 分段加锁
③ 减少锁持有的时间
④ 多个线程尽量以相同的顺序去获取资源

等等,这些都不是绝对原则,都要根据情况,比如不能将锁的粒度过于细化,不然可能会出现线程的加锁和释放次数过多,反而效率不如一次加一把大锁。这部分跟面试官谈了很久

  • 索引的底层实现原理和优化
    B+树,经过优化的B+树
    主要是在所有的叶子结点中增加了指向下一个叶子节点的指针,因此InnoDB建议为大部分表使用默认自增的主键作为主索引。

  • 什么情况下设置了索引但无法使用
    ① 以“%”开头的LIKE语句,模糊匹配
    ② OR语句前后没有同时使用索引
    ③ 数据类型出现隐式转化(如varchar不加单引号的话可能会自动转换为int型)

  • SQL语句的优化
    order by要怎么处理
    alter尽量将多次合并为一次
    insert和delete也需要合并
    等等

  • 实践中如何优化MySQL
    我当时是按以下四条依次回答的,他们四条从效果上第一条影响最大,后面越来越小。
    ① SQL语句及索引的优化
    ② 数据库表结构的优化
    ③ 系统配置的优化
    ④ 硬件的优化

  • sql注入的主要特点
    变种极多,攻击简单,危害极大
    sql注入的主要危害
    未经授权操作数据库的数据
    恶意纂改网页
    私自添加系统账号或者是数据库使用者账号
    网页挂木马

  • 优化数据库的方法
    选取最适用的字段属性,尽可能减少定义字段宽度,尽量把字段设置NOTNULL,例如’省份’.   ’性别’最好适用ENUM
    使用连接(JOIN)来代替子查询
    适用联合(UNION)来代替手动创建的临时表
    事务处理
    锁定表.   优化事务处理
    适用外键,优化锁定表
    建立索引
    优化查询语句

  • 简单描述mysql中,索引,主键,唯一索引,联合索引的区别,对数据库的性能有什么影响(从读写两方面)
    索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。

    普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。
    普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个 数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。也就是说,唯一索引可以保证数据 记录的唯一性。

    主键,是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键 字 PRIMARY KEY 来创建。

    索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引,这就是联合索引。

    索引可以极大的提高数据的查询速度,但是会降低插入.   删除.   更新表的速度,因为在执行这些写操作时, 还要操作索引文件。

  • 数据库中的事务是什么?
    事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。ACID 四大特性,原子性.   隔离性.   一致性.   持久性。

  • 了解XSS攻击吗?如何防止?
    XSS是跨站脚本攻击,首先是利用跨站脚本漏洞以一个特权模式去执行攻击者构造的脚本,然后利用不安全的Activex控件执行恶意的行为。
    使用htmlspecialchars()函数对提交的内容进行过滤,使字符串里面的特殊符号实体化。

  • SQL注入漏洞产生的原因?如何防止?
    SQL注入产生的原因:程序开发过程中不注意规范书写sql语句和对特殊字符进行过滤,导致客户端可以通过全局变量POST和GET提交一些sql语句正常执行。

  • 防止SQL注入的方式:
    开启配置文件中的magic_quotes_gpc 和 magic_quotes_runtime设置
    执行sql语句时使用addslashes进行sql语句转换
    Sql语句书写尽量不要省略双引号和单引号。
    过滤掉sql语句中的一些关键词:update.   insert.   delete.   select.   * 。
    提高数据库表和字段的命名技巧,对一些重要的字段根据程序的特点命名,取不易被猜到的。
    Php配置文件中设置register_globals为off,关闭全局变量注册
    控制错误信息,不要在浏览器上输出错误信息,将错误信息写到日志文件中。

  • 为表中得字段选择合适得数据类型(物理设计)
    字段类型优先级: 整形>date,time>enum,char>varchar>blob,text
    优先考虑数字类型,其次是日期或者二进制类型,最后是字符串类型,同级别得数据类型,应该优先选择占用空间小的数据类型

  • 存储时期
    Datatime:以 YYYY-MM-DD HH:MM:SS 格式存储时期时间,精确到秒,占用8个字节得存储空间,datatime类型与时区无关
    Timestamp:以时间戳格式存储,占用4个字节,范围小1970-1-1到2038-1-19,显示依赖于所指定得时区,默认在第一个列行的数据修改时可以自动得修改timestamp列得值
    Date:(生日)占用得字节数比使用字符串.datatime.int储存要少,使用date只需要3个字节,存储日期月份,还可以利用日期时间函数进行日期间得计算
    Time:存储时间部分得数据
    注意:不要使用字符串类型来存储日期时间数据(通常比字符串占用得储存空间小,在进行查找过滤可以利用日期得函数)
    使用int存储日期时间不如使用timestamp类型

  • 对于关系型数据库而言,索引是相当重要的概念,请回答有关索引的几个问题:
    a).   索引的目的是什么?
    快速访问数据表中的特定信息,提高检索速度
    创建唯一性索引,保证数据库表中每一行数据的唯一性。
    加速表和表之间的连接
    使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间

    b).   索引对数据库系统的负面影响是什么?
    负面影响:
    创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加;索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间;当对表进行增.   删.   改.   的时候索引也要动态维护,这样就降低了数据的维护速度。

    c).   为数据表建立索引的原则有哪些?
    在最频繁使用的.   用以缩小查询范围的字段上建立索引。
    在频繁使用的.   需要排序的字段上建立索引

    d).   什么情况下不宜建立索引?
    对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引。
    对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等

  • 简述在MySQL数据库中MyISAM和InnoDB的区别
    区别于其他数据库的最重要的特点就是其插件式的表存储引擎。切记:存储引擎是基于表的,而不是数据库。

  • InnoDB与MyISAM的区别:
    InnoDB存储引擎: 主要面向OLTP(Online Transaction Processing,在线事务处理)方面的应用,是第一个完整支持ACID事务的存储引擎(BDB第一个支持事务的存储引擎,已经停止开发)。
    特点:
    行锁设计.   支持外键,支持事务,支持并发,锁粒度是支持mvcc得行级锁;
    MyISAM存储引擎: 是MySQL官方提供的存储引擎,主要面向OLAP(Online Analytical Processing,在线分析处理)方面的应用。
    特点:
    不支持事务,锁粒度是支持并发插入得表级锁,支持表所和全文索引。操作速度快,不能读写操作太频繁;

  • 解释MySQL外连接.   内连接与自连接的区别
    先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一个表的所有记录和另一个表中的所有记录一一匹配。
    内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合条件的记录不会出现在结果集中,即内连接只连接匹配的行。
    外连接 其结果集中不仅包含符合连接条件的行,而且还会包括左表.   右表或两个表中
    的所有数据行,这三种情况依次称之为左外连接,右外连接,和全外连接。
    左外连接,也称左连接,左表为主表,左表中的所有记录都会出现在结果集中,对于那些在右表中并没有匹配的记录,仍然要显示,右边对应的那些字段值以NULL来填充。右外连接,也称右连接,右表为主表,右表中的所有记录都会出现在结果集中。左连接和右连接可以互换,MySQL目前还不支持全外连接。

  • 写出三种以上MySQL数据库存储引擎的名称(提示:不区分大小写)
    MyISAM.   InnoDB.   BDB(BerkeleyDB).   Merge.   Memory(Heap).   Example.   Federated.  
    Archive.   CSV.   Blackhole.   MaxDB 等等十几个引擎

  • Myql中的事务回滚机制概述
    事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位,事务回滚是指将该事务已经完成的对数据库的更新操作撤销。

    要同时修改数据库中两个不同表时,如果它们不是一个事务的话,当第一个表修改完,可能第二个表修改过程中出现了异常而没能修改,此时就只有第二个表依旧是未修改之前的状态,而第一个表已经被修改完毕。而当你把它们设定为一个事务的时候,当第一个表修改完,第二表修改出现异常而没能修改,第一个表和第二个表都要回到未修改的状态,这就是所谓的事务回滚

  • SQL语言包括哪几部分?每部分都有哪些操作关键字?
    答:SQL语言包括数据定义(DDL).   数据操纵(DML),数据控制(DCL)和数据查询(DQL)四个部分。
    数据定义:Create Table,Alter Table,Drop Table, Craete/Drop Index等
    数据操纵:Select ,insert,update,delete,
    数据控制:grant,revoke
    数据查询:select

  • 完整性约束包括哪些?
    数据完整性(Data Integrity)是指数据的精确(Accuracy)和可靠性(Reliability)。
    分为以下四类:

    1. 实体完整性:规定表的每一行在表中是惟一的实体。
    2. 域完整性:是指表中的列必须满足某种特定的数据类型约束,其中约束又包括取值范围.   精度等规定。
    3. 参照完整性:是指两个表的主关键字和外关键字的数据应一致,保证了表之间的数据的一致性,防止了数据丢失或无意义的数据在数据库中扩散。
    4. 用户定义的完整性:不同的关系数据库系统根据其应用环境的不同,往往还需要一些特殊的约束条件。用户定义的完整性即是针对某个特定关系数据库的约束条件,它反映某一具体应用必须满足的语义要求。
      与表有关的约束:包括列约束(NOT NULL(非空约束))和表约束(PRIMARY KEY.   foreign key.   check.   UNIQUE) 。
  • 什么是事务?及其特性?
    答:事务:是一系列的数据库操作,是数据库应用的基本逻辑单位。

    事务特性:
    (1)原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。
    (2)一致性或可串性。事务的执行使得数据库从一种正确状态转换成另一种正确状态
    (3)隔离性。在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务,
    (4) 持久性。事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结 果也会得到保存。

    或者这样理解:

    事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失 败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。要将有组语句作为事务考虑,就需要通过ACID测试,即原子性,一致性,隔离性和持久性。

  • 什么是锁?
    答:数据库是一个多用户使用的共享资源。当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性。

    加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。

    基本锁类型:锁包括行级锁和表级锁

  • 什么叫视图?游标是什么?

    答:视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,视图通常是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易,相比多表查询。

    游标:是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。

  • 什么是存储过程?用什么来调用?

    答:存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。可以用一个命令对象来调用存储过程。

  • 索引的作用?和它的优点缺点是什么?

    答:索引就一种特殊的查询表,数据库的搜索引擎可以利用它加速对数据的检索。它很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。索引可以是唯一的,创建索引允许指定单个列或者是多个列。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小

  • 如何通俗地理解三个范式?

    答:第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;

    第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;

    第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。。

    范式化设计优缺点:

    优点:

    可以尽量得减少数据冗余,使得更新快,体积小

    缺点:对于查询需要多个表进行关联,减少写得效率增加读得效率,更难进行索引优化

    反范式化:

    优点:可以减少表得关联,可以更好得进行索引优化

    缺点:数据冗余以及数据异常,数据得修改需要更多的成

  • 什么是基本表?什么是视图?

    答:基本表是本身独立存在的表,在 SQL 中一个关系就对应一个表。 视图是从一个或几个基本表导出的表。视图本身不独立存储在数据库中,是一个虚表

  • 试述视图的优点?

    答:(1) 视图能够简化用户的操作 (2) 视图使用户能以多种角度看待同一数据; (3) 视图为数据库提供了一定程度的逻辑独立性; (4) 视图能够对机密数据提供安全保护。

  • NULL是什么意思

    答:NULL这个值表示UNKNOWN(未知):它不表示“”(空字符串)。对NULL这个值的任何比较都会生产一个NULL值。您不能把任何值与一个 NULL值进行比较,并在逻辑上希望获得一个答案。

    使用IS NULL来进行NULL判断

  • 主键.   外键和索引的区别?
    主键.   外键和索引的区别
    定义:
    主键–唯一标识一条记录,不能有重复的,不允许为空
    外键–表的外键是另一表的主键, 外键可以有重复的, 可以是空值
    索引–该字段没有重复值,但可以有一个空值
    作用:
    主键–用来保证数据完整性
    外键–用来和其他表建立联系用的
    索引–是提高查询排序的速度
    个数:
    主键–主键只能有一个
    外键–一个表可以有多个外键
    索引–一个表可以有多个唯一索引

  • 你可以用什么来确保表格里的字段只接受特定范围里的值?
    Check限制,它在数据库表格里被定义,用来限制输入该列的值。
    触发器也可以被用来限制数据库表格里的字段能够接受的值,但是这种办法要求触发器在表格里被定义,这可能会在某些情况下影响到性能。

  • 说说对SQL语句优化有哪些方法?(选择几条)

    (1)Where子句中:where表之间的连接必须写在其他Where条件之前,那些可以过滤掉最大数量记录的条件必须写在Where子句的末尾.HAVING最后。

    (2)用EXISTS替代IN.   用NOT EXISTS替代NOT IN。

    (3) 避免在索引列上使用计算

    (4)避免在索引列上使用IS NULL和IS NOT NULL

    (5)对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。

    (6)应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描

    (7)应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描

  • SQL语句中‘相关子查询’与‘非相关子查询’有什么区别?

    答:子查询:嵌套在其他查询中的查询称之。

    子查询又称内部,而包含子查询的语句称之外部查询(又称主查询)。

    所有的子查询可以分为两类,即相关子查询和非相关子查询

    (1)非相关子查询是独立于外部查询的子查询,子查询总共执行一次,执行完毕后将值传递给外部查询。

    (2)相关子查询的执行依赖于外部查询的数据,外部查询执行一行,子查询就执行一次。

    故非相关子查询比相关子查询效率高

  • char和varchar的区别?

    答:是一种固定长度的类型,varchar则是一种可变长度的类型,它们的区别是:

    char(M)类型的数据列里,每个值都占用M个字节,如果某个长度小于M,MySQL就会在它的右边用空格字符补足.(在检索操作中那些填补出来的空格字符将被去掉)在varchar(M)类型的数据列里,每个值只占用刚好够用的字节再加上一个用来记录其长度的字节(即总长度为L+1字节).

    varchar得适用场景:

    字符串列得最大长度比平均长度大很多 2.字符串很少被更新,容易产生存储碎片 3.使用多字节字符集存储字符串

    Char得场景:

    存储具有近似得长度(md5值,身份证,手机号),长度比较短小得字符串(因为varchar需要额外空间记录字符串长度),更适合经常更新得字符串,更新时不会出现页分裂得情况,避免出现存储碎片,获得更好的io性能

  • (考题) Mysql对大批量数据进行存储和操作,如何选择存储引擎?如何设计表?如何优化操作?事务是什么如何管理?

  考点: 5万条数据,高并发情况下?
  如何选择Mysql存储引擎?
  如何设计表(三大范式)?
  如何优化(索引)?
  并发操作时符合保证事务的一致性(事务)?
  (考题)MySQL数据库作为发布系统的存储,一天五万条以上的增量,预计运维三年,如何设计表?如何优化操作?事务如何管理?
  
  1.   设计表?
  ·	设计表需要考虑约束和三大范式,如下?
  	
  	(1)完整性约束包括哪些?
  
  		数据完整性(Data Integrity)是指数据的精确(Accuracy)和可靠性(Reliability)。
  		
  		分为以下四类:
  		
  		1) 实体完整性:规定表的每一行在表中是惟一的实体。
  		
  		2) 域完整性:是指表中的列必须满足某种特定的数据类型约束,其中约束又包括取值范围.   精度等规定。
  		
  		3) 参照完整性:是指两个表的主关键字和外关键字的数据应一致,保证了表之间的数据的一致性,防止了数据丢失或无意义的数据在数据库中扩散。
  		
  		4) 用户定义的完整性:不同的关系数据库系统根据其应用环境的不同,往往还需要一些特殊的约束条件。用户定义的完整性即是针对某个特定关系数据库的约束条件,它反映某一具体应用必须满足的语义要求。
  		
  		与表有关的约束:包括列约束(NOT NULL(非空约束))和表约束(PRIMARY KEY.   foreign key.   check.   UNIQUE) 。
  	(2)设计表必须遵循三个范式?如下
  		第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;
  		第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;  
  		第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。。
  		范式化设计优缺点:
  		
  		优点:	
  		可以尽量得减少数据冗余,使得更新快,体积小	
  		缺点:对于查询需要多个表进行关联,减少写得效率增加读得效率,更难进行索引优化	
  		反范式化:	
  		优点:可以减少表得关联,可以更好得进行索引优化	
  		缺点:数据冗余以及数据异常,数据得修改需要更多的成
  	
  2.   优化操作?
  	a设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
  	b. 选择合适的表字段数据类型和存储引擎,适当的添加索引。
  	c. mysql库主从读写分离。
  	d. 找规律分表,减少单表中的数据量提高查询速度。
  	e. 添加缓存机制,比如memcached,apc等。
  	f. 不经常改动的页面,生成静态页面。
  	g. 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE.
  	
  	存储引擎.   优化字段数据类型.   为搜索字段添加索引.   使用 ENUM 而不是 VARCHAR.   尽可能的使用 NOT NULL.   固定长度的表会更快
  	(1)存储引擎选择
  		(1)Mysql的存储引擎有myisam和innodb,区别有两点:
  
  			1.MyISAM 是非事务的存储引擎,适合用于频繁查询的应用。表锁,不会出现死锁,适合小数据,小并发。
  				是MySQL官方提供的存储引擎,主要面向OLAP(Online Analytical Processing,在线分析处理)方面的应用。
  			特点:
  				不支持事务,锁粒度是支持并发插入得表级锁,支持表所和全文索引。操作速度快,不能读写操作太频繁;
  			2.innodb是支持事务的存储引擎,合于插入和更新操作比较多的应用,设计合理的话是行锁(最大区别就在锁的级别上),适合大数据,大并发。
  				主要面向OLTP(Online Transaction Processing,在线事务处理)方面的应用,是第一个完整支持ACID事务的存储引擎(BDB第一个支持事务的存储引擎,已经停止开发)。
  			特点:
    · 			行锁设计.   支持外键,支持事务,支持并发,锁粒度是支持mvcc得行级锁;
  			综述:选择innodb作为存储引擎;
  	(2)优化字段数据类型
  		记住一个原则,越小的列会越快。如果一个表只会有几列罢了(比如说字典表,配置表),那么,我们就没有理由使用INT来做主键,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 会更经济一些。如果你不需要记录时间,使用 DATE 要比 DATETIME 好得多。当然,你也需要留够足够的扩展空间。
  
  	(3)为搜索字段添加索引
  		
  		mysql中有索引,主键,唯一索引,联合索引,对数据库的性能有什么影响(从读写两方面),区别如下?
  			索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分),它们包含着对数据表里所有记录的引用指针。
  			 普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度。
  			普通索引允许被索引的数据列包含重复的值。如果能确定某个数据列将只包含彼此各不相同的值,在为这个		数据列创建索引的时候就应该用关键字UNIQUE把它定义为一个唯一索引。也就是说,唯一索引可以保证数据记录的唯一性。
  			主键,是一种特殊的唯一索引,在一张表中只能定义一个主键索引,主键用于唯一标识一条记录,使用关键字 PRIMARY KEY 来创建。
  			索引可以覆盖多个数据列,如像INDEX(columnA, columnB)索引,这就是联合索引。
  			索引可以极大的提高数据的查询速度,但是会降低插入.   删除.   更新表的速度,因为在执行这些写操作时,还要操作索引文件。
  			
  			a).   索引的目的是什么?
  			快速访问数据表中的特定信息,提高检索速度
  			
  			创建唯一性索引,保证数据库表中每一行数据的唯一性。
  			
  			加速表和表之间的连接
  			
  			使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
  			
  			b).   索引对数据库系统的负面影响是什么?
  			负面影响:
  			创建索引和维护索引需要耗费时间,这个时间随着数据量的增加而增加;索引需要占用物理空间,不光是表需要占用数据空间,每个索引也需要占用物理空间;当对表进行增.   删.   改.   的时候索引也要动态维护,这样就降低了数据的维护速度。
  			
  			c).   为数据表建立索引的原则有哪些?
  			在最频繁使用的.   用以缩小查询范围的字段上建立索引。
  			
  			在频繁使用的.   需要排序的字段上建立索引
  			
  			d).   什么情况下不宜建立索引?
  			对于查询中很少涉及的列或者重复值比较多的列,不宜建立索引。
  			
  			对于一些特殊的数据类型,不宜建立索引,比如文本字段(text)等
  
  		综述:索引并不一定就是给主键或是唯一的字段。如果在你的表中,有某个字段你总要会经常用来做搜索,那么最好是为其建立索引,除非你要搜索的字段是大的文本字段,那应该建立全文索引。
  
  	(4)SQl语句进行少用通配符.   要精确
  		避免使用Select*从数据库里读出越多的数据,那么查询就会变得越慢。并且,如果你的数据库服务器和WEB服务器是两台独立的服务器的话,这还会增加网络传输的负载。即使你要查询数据表的所有字段,也尽	量不要用通配符,善用内置提供的字段排除定义也许能给带来更多的便利。
  	(5)使用 ENUM 而不是 VARCHAR
  		ENUM 类型是非常快和紧凑的。在实际上,其保存的是 TINYINT,但其外表上显示为字符串。这样一来,用这个字段来做一些选项列表变得相当的完美。例如,性别.   民族.   部门和状态之类的这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 而不是 VARCHAR。
  	(6)尽可能的使用 NOT NULL
  		除非你有一个很特别的原因去使用 NULL 值,你应该总是让你的字段保持 NOT NULL。 NULL其实需要额外的空间,并且,在你进行比较的时候,你的程序会更复杂。 当然,这里并不是说你就不能使用NULL了,现实情况是很复杂的,依然会有些情况下,你需要使用NULL值。
  	(7)固定长度的表会更快
  		如果表中的所有字段都是“固定长度”的,整个表会被认为是 “static” 或 “fixed-length”。 例如,表中没有如下类型的字段:VARCHAR,TEXT,BLOB。只要你包括了其中一个这些字段,那么这个表就不是“固定长度静态表”了,这样,MySQL 引擎会用另一种方法来处理。
  		固定长度的表会提高性能,因为MySQL搜寻得会更快一些,因为这些固定的长度是很容易计算下一个数据的偏移量的,所以读取的自然也会很快。而如果字段不是定长的,那么,每一次要找下一条的话,需要程序找到主键。并且,固定长度的表也更容易被缓存和重建。不过,唯一的副作用是,固定长度的字段会浪费一些空间,因为定长的字段无论你用不用,他都是要分配那么多的空间。
  3.   事务管理?
  	(1)事务(transaction)是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。ACID 四大特性,原子性.   隔离性.   一致性.   持久性。
  	
  	(2)Myql中的事务回滚机制概述
  		事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位,事务回滚是指将该事务已经完成的对数据库的更新操作撤销。
  		
  		要同时修改数据库中两个不同表时,如果它们不是一个事务的话,当第一个表修改完,可能第二个表修改过程中出现了异常而没能修改,此时就只有第二个表依旧是未修改之前的状态,而第一个表已经被修改完毕。而当你把它们设定为一个事务的时候,当第一个表修改完,第二表修改出现异常而没能修改,第一个表和第二个表都要回到未修改的状态,这就是所谓的事务回滚 

基础知识

| name | population | area |

±-------------±------------±-------------+

| Afghanistan | 25500100 | 652230 |

| Algeria | 37100000 | 2381741 |

±-------------±------------±-------------+

(1)SQL Schema

SQL Schema 用于在本地环境下创建表结构并导入数据,从而方便在本地环境解答。

DROP TABLE

什么是事务

  1. 事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。
    Java高级:面试题-1_第6张图片
    2.ACID
    (1)原子性(Atomicity)
    事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。
    回滚可以用回滚日志来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
    (2)一致性(Consistency)
    数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对一个数据的读取结果都是相同的。
    (3)隔离性(Isolation)
    一个事务所做的修改在最终提交以前,对其它事务是不可见的。
    (4)持久性(Durability)
    一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。
    使用重做日志来保证持久性。

事务的 ACID 特性概念简单,但不是很好理解,主要是因为这几个特性不是一种平级关系:

  • 只有满足一致性,事务的执行结果才是正确的。

  • 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。

  • 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。

  • 事务满足持久化是为了能应对数据库崩溃的情况。
    Java高级:面试题-1_第7张图片
    3.封锁粒度

MySQL 中提供了两种封锁粒度:行级锁以及表级锁。

应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。

但是加锁需要消耗资源,锁的各种操作(包括获取锁.   释放锁.   以及检查锁状态)都会增加系统开销。因此封锁粒度越小,系统开销就越大。

在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。

4.范式

范式理论是为了解决以上提到四种异常。

高级别范式的依赖于低级别的范式,1NF 是最低级别的范式。

(1)第一范式(1NF)
  属性不可分。

(2)第二范式(2NF)

  每个非主属性完全函数依赖于键码。

  可以通过分解来满足。

(3)第三范式(3NF)

  非主属性不传递函数依赖于键码。

  上面的 关系-1 中存在以下传递函数依赖:

5.ER图
  Entity-Relationship,有三个组成部分:实体.   属性.   联系。

  用来进行关系型数据库系统的概念设计。

(1)实体的三种联系

  包含一对一,一对多,多对多三种。

  • 如果 A 到 B 是一对多关系,那么画个带箭头的线段指向 B;

  • 如果是一对一,画两个带箭头的线段;

  • 如果是多对多,画两个不带箭头的线段。

下图的 Course 和 Student 是一对多的关系。
在这里插入图片描述

(2)表示出现多次的关系

  一个实体在联系出现几次,就要用几条线连接。

  下图表示一个课程的先修关系,先修关系出现两个 Course 实体,第一个是先修课程,后一个是后修课程,因此需要用两条线来表示这种关系。
Java高级:面试题-1_第8张图片
(3)联系的多向性

虽然老师可以开设多门课,并且可以教授多名学生,但是对于特定的学生和课程,只有一个老师教授,这就构成了一个三元联系。
Java高级:面试题-1_第9张图片

(4)表示子类

用一个三角形和两条线来连接类和子类,与子类有关的属性和联系都连到子类上,而与父类和子类都有关的连到父类上。
Java高级:面试题-1_第10张图片

MySQL -SQL

1.Big Countries习题

(1)Description

±----------------±-----------±-----------±-------------±--------------+

| name | continent | area | population | gdp |

±----------------±-----------±-----------±-------------±--------------+

| Afghanistan | Asia | 652230 | 25500100 | 20343000 |

| Albania | Europe | 28748 | 2831741 | 12960000 |

| Algeria | Africa | 2381741 | 37100000 | 188681000 |

| Andorra | Europe | 468 | 78115 | 3712000 |

| Angola | Africa | 1246700 | 20609294 | 100990000 |

±----------------±-----------±-----------±-------------±--------------+

查找面积超过 3,000,000 或者人口数超过 25,000,000 的国家。

±-------------±------------±-------------+

EXISTS World;CREATE TABLE World ( NAME VARCHAR ( 255 ), continent VARCHAR ( 255 ), area INT, population INT, gdp INT );INSERT INTO World ( NAME, continent, area, population, gdp )VALUES
    
    ( 'Afghanistan', 'Asia', '652230', '25500100', '203430000' ),
 
     ( 'Albania', 'Europe', '28748', '2831741', '129600000' ),
 
     ( 'Algeria', 'Africa', '2381741', '37100000', '1886810000' ),
 
     ( 'Andorra', 'Europe', '468', '78115', '37120000' ),
 
     ( 'Angola', 'Africa', '1246700', '20609294', '1009900000' );

(2)Solution

    SELECT name,
    
        population,
    
        areaFROM
    
        World WHERE
    
        area > 3000000
    
        OR population > 25000000;
  1. Swap Salary习题

(1)Description

| id | name | sex | salary |

|----|------|-----|--------|

| 1 | A | m | 2500 |

| 2 | B | f | 1500 |

| 3 | C | m | 5500 |

| 4 | D | f | 500 |

只用一个 SQL 查询,将 sex 字段反转。

| id | name | sex | salary |

|----|------|-----|--------|

| 1 | A | f | 2500 |

| 2 | B | m | 1500 |

| 3 | C | f | 5500 |

| 4 | D | m | 500 |

(2)SQL Schema

   DROP TABLE
   
   IF
   
       EXISTS salary;CREATE TABLE salary ( id INT, NAME VARCHAR ( 100 ), sex CHAR ( 1 ), salary INT );INSERT INTO salary ( id, NAME, sex, salary )VALUES
   
       ( '1', 'A', 'm', '2500' ),
   
       ( '2', 'B', 'f', '1500' ),
   
       ( '3', 'C', 'm', '5500' ),
   
       ( '4', 'D', 'f', '500' );

(3)Solution

使用异或操作,两个相等的数异或的结果为 0,而 0 与任何一个数异或的结果为这个数。

‘f’ ^ ‘m’ ^ ‘f’ = ‘m’

‘m’ ^ ‘m’ ^ ‘f’ = ‘f’

UPDATE salarySET sex = CHAR ( ASCII(sex) ^ ASCII( ‘m’ ) ^ ASCII( ‘f’ ) );

3.7.3.5.   MYsql -知识点概述

1.索引的优点

  • 大大减少了服务器需要扫描的数据行数。

  • 帮助服务器避免进行排序和分组,以及避免创建临时表(B+Tree 索引是有序的,可以用于 ORDER BY 和 GROUP BY 操作。临时表主要是在排序和分组过程中创建,不需要排序和分组,也就不需要创建临时表)。

  • 将随机 I/O 变为顺序 I/O(B+Tree 索引是有序的,会将相邻的数据都存储在一起)。

2.索引的使用条件

  • 对于非常小的表.   大部分情况下简单的全表扫描比建立索引更高效;

  • 对于中到大型的表,索引就非常有效;

  • 但是对于特大型的表,建立和维护索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。

3.数据类型

(1)整型

  TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT 分别使用 8, 16, 24, 32, 64 位存储空间,一般情况下越小的列越好。

I  NT(11) 中的数字只是规定了交互工具显示字符的个数,对于存储和计算来说是没有意义的。

(2)浮点数
  FLOAT 和 DOUBLE 为浮点类型,DECIMAL 为高精度小数类型。CPU 原生支持浮点运算,但是不支持 DECIMAl 类型的计算,因此 DECIMAL 的计算比浮点类型需要更高的代价。

  FLOAT.   DOUBLE 和 DECIMAL 都可以指定列宽,例如 DECIMAL(18, 9) 表示总共 18 位,取 9 位存储小数部分,剩下 9 位存储整数部分。

(3)字符串

  主要有 CHAR 和 VARCHAR 两种类型,一种是定长的,一种是变长的。

  VARCHAR 这种变长类型能够节省空间,因为只需要存储必要的内容。但是在执行 UPDATE 时可能会使行变得比原来长,当超出一个页所能容纳的大小时,就要执行额外的操作。MyISAM 会将行拆成不同的片段存储,而 InnoDB 则需要分裂页来使行放进页内。

  在进行存储和检索时,会保留 VARCHAR 末尾的空格,而会删除 CHAR 末尾的空格。

(4)时间和日期

  MySQL 提供了两种相似的日期时间类型:DATETIME 和 TIMESTAMP。

① DATETIME

  能够保存从 1000 年到 9999 年的日期和时间,精度为秒,使用 8 字节的存储空间。

  它与时区无关。

  默认情况下,MySQL 以一种可排序的.   无歧义的格式显示 DATETIME 值,例如“2008-01-16 22:37:08”,这是 ANSI 标准定义的日期和时间表示方法。

② TIMESTAMP

  和 UNIX 时间戳相同,保存从 1970 年 1 月 1 日午夜(格林威治时间)以来的秒数,使用 4 个字节,只能表示从 1970 年到 2038 年。

  它和时区有关,也就是说一个时间戳在不同的时区所代表的具体时间是不同的。

  MySQL 提供了 FROM_UNIXTIME() 函数把 UNIX 时间戳转换为日期,并提供了 UNIX_TIMESTAMP() 函数把日期转换为 UNIX 时间戳。

  默认情况下,如果插入时没有指定 TIMESTAMP 列的值,会将这个值设置为当前时间。

  应该尽量使用 TIMESTAMP,因为它比 DATETIME 空间效率更高。

4.切分

(1)水平切分

  水平切分又称为 Sharding,它是将同一个表中的记录拆分到多个结构相同的表中。

  当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。

Java高级:面试题-1_第11张图片

(2)垂直切分

  垂直切分是将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。

  在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库.   用户数据库等。
Java高级:面试题-1_第12张图片

5.Sharding 策略

  • 哈希取模:hash(key) % N;

  • 范围:可以是 ID 范围也可以是时间范围;

  • 映射表:使用单独的一个数据库来存储映射关系。

6.Sharding 存在的问题

(1)事务问题

使用分布式事务来解决,比如 XA 接口。

(2)连接

可以将原来的连接分解成多个单表查询,然后在用户程序中进行连接。

(3)ID唯一性

  • 使用全局唯一 ID(GUID)

  • 为每个分片指定一个 ID 范围

  • 分布式 ID 生成器 (如 Twitter 的 Snowflake 算法)

7.主从复制

主要涉及三个线程:binlog 线程.   I/O 线程和 SQL 线程。

  • binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。

  • I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。

  • SQL 线程 :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)。
    Java高级:面试题-1_第13张图片
    8.读写分离

主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。

读写分离能提高性能的原因在于:

  • 主从服务器负责各自的读和写,极大程度缓解了锁的争用;

  • 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;

  • 增加冗余,提高可用性。

读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。
Java高级:面试题-1_第14张图片

算法

简答题

编程题

有序数组的 Two Sum

Input: numbers={2, 7, 11, 15}, target=9

Output: index1=1, index2=2

题目描述:在有序数组中找出两个数,使它们的和为 target。

使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。

  • 如果两个指针指向元素的和 sum == target,那么得到要求的结果;

  • 如果 sum > target,移动较大的元素,使 sum 变小一些;

  • 如果 sum < target,移动较小的元素,使 sum 变大一些。

public int[] twoSum(int[] numbers, int target) {
    int i = 0, j = numbers.length - 1;
    while (i < j) {
        int sum = numbers[i] + numbers[j];
        if (sum == target) {
            return new int[]{i + 1, j + 1};
        } else if (sum < target) {
            i++;
        } else {
            j--;
        }
    }
    return null;
}

2.两数平方和

Input: 5

Output: True

Explanation: 1 * 1 + 2 * 2 = 5

题目描述:判断一个数是否为两个数的平方和。

public boolean judgeSquareSum(int c) {

    int i = 0, j = (int) Math.sqrt(c);

    while (i <= j) {

        int powSum = i * i + j * j;

        if (powSum == c) {

            return true;

        } else if (powSum > c) {

            j--;

        } else {

            i++;

        }

    }

    return false;

}

3.反转字符串中的元音字符

Given s = “leetcode”, return “leotcede”.

使用双指针指向待反转的两个元音字符,一个指针从头向尾遍历,一个指针从尾到头遍历。

private final static HashSet<Character> vowels = new HashSet<>(

    Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));

	public String reverseVowels(String s) {

    int i = 0, j = s.length() - 1;

    char[] result = new char[s.length()];

    while (i <= j) {

        char ci = s.charAt(i);

        char cj = s.charAt(j);

        if (!vowels.contains(ci)) {

            result[i++] = ci;

        } else if (!vowels.contains(cj)) {

            result[j--] = cj;

        } else {

            result[i++] = cj;

            result[j--] = ci;

        }

    }

    return new String(result);

}

4.回文字符串

Input: “abca”

Output: True

Explanation: You could delete the character ‘c’.

题目描述:可以删除一个字符,判断是否能构成回文字符串。

public boolean validPalindrome(String s) {

    for (int i = 0, j = s.length() - 1; i < j; i++, j--) {

        if (s.charAt(i) != s.charAt(j)) {

            return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);

        }

    }

    return true;

}

private boolean isPalindrome(String s, int i, int j) {

    while (i < j) {

        if (s.charAt(i++) != s.charAt(j--)) {

            return false;

        }

    }

    return true;

}

5.归并两个有序数组

Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]

题目描述:把归并结果存到第一个数组上。

需要从尾开始遍历,否则在 nums1 上归并得到的值会覆盖还未进行归并比较的值。

public void merge(int[] nums1, int m, int[] nums2, int n) {

    int index1 = m - 1, index2 = n - 1;

    int indexMerge = m + n - 1;

    while (index1 >= 0 || index2 >= 0) {

        if (index1 < 0) {

            nums1[indexMerge--] = nums2[index2--];

        } else if (index2 < 0) {

            nums1[indexMerge--] = nums1[index1--];

        } else if (nums1[index1] > nums2[index2]) {

            nums1[indexMerge--] = nums1[index1--];

        } else {

            nums1[indexMerge--] = nums2[index2--];

        }

    }

}

6.判断链表是否存在环

使用双指针,一个指针每次移动一个节点,一个指针每次移动两个节点,如果存在环,那么这两个指针一定会相遇。

public boolean hasCycle(ListNode head) {

    if (head == null) {

        return false;

    }

    ListNode l1 = head, l2 = head.next;

    while (l1 != null && l2 != null && l2.next != null) {

        if (l1 == l2) {

            return true;

        }

        l1 = l1.next;

        l2 = l2.next.next;

    }

    return false;

}

7.最长子序列

Input:
s = “abpcplea”, d = [“ale”,“apple”,“monkey”,“plea”]
Output:
“apple”

题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回字典序的最小字符串。

通过删除字符串 s 中的一个字符能得到字符串 t,可以认为 t 是 s 的子序列,我们可以使用双指针来判断一个字符串是否为另一个字符串的子序列。

public String findLongestWord(String s, List<String> d) {
    String longestWord = "";
    for (String target : d) {
        int l1 = longestWord.length(), l2 = target.length();
        if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) {
            continue;
        }
        if (isSubstr(s, target)) {
            longestWord = target;
        }
    }
    return longestWord;
}

private boolean isSubstr(String s, String target) {
    int i = 0, j = 0;
    while (i < s.length() && j < target.length()) {
        if (s.charAt(i) == target.charAt(j)) {
            j++;
        }
        i++;
    }
    return j == target.length();

}

数据结构

选择题

  • 选择排序的思想是,将数据序列划分为两个子列,一个子列是排好序的,另一个是尚未排序的。现若想将数据序列由小到大排序,则每次放到有序子列尾部位置的元素,应从无序序列中选择(A )。
    A. 最大的
    B. 最小的
    C. 任意的
    D. 头上的

填空题

  • 对于树的结构,最上层的点称为 根 结点。
  • 一个结点没有任何的子结点,则称该结点为 叶子/终端 结点。
  • 在Java中, Treemap/TreeSet 是建立树结构的类。

简答题

数据结构——树——知识点总结
数据结构——树
定义:树是一个n(n>=0)个结点的有序合集

名词理解:

结点:指树中的一个元素;

结点的度:指结点拥有的子树的个数,二叉树的度不大于2;

数的度:指树中的最大结点度数;

叶子:度为0的结点,也称为终端结点;

高度:叶子节点的高度为1,根节点高度最高;

层:根在第一层,以此类推;

二叉树的定义:由一个结点和两颗互不相交.   分别称为这个根的左子树和右子树的二叉树构成(递归定义)

二叉树的性质:

1:二叉树的第i层上至多有2^(i-1)个结点

2:深度为k的二叉树,至多有2^k-1个结点

满二叉树:叶子节点一定要在最后一层,并且所有非叶子节点都存在左孩子和右孩子;

最特别的二叉树:完全二叉树:从左到右.   从上到下构建的二叉树;

完全二叉树的性质:

1:结点 i 的子结点为2*i 和 2*i+1(前提是都小于总结点数)

2:结点 i 的父结点为 i/2 

二叉树的遍历(要有递归的思想!!!):

1:先序遍历:根->左子树->右子树(先序)

2:中序遍历:左子树->根->右子树(中序)

3:后序遍历:左子树->右子树->根(后序)

这三种遍历方法只是访问结点的时机不同,访问结点的路径都是一样的,时间和空间复杂度皆为O(n)

Java高级:面试题-1_第15张图片
二叉树的存储结构

找出两个链表的交点

例如以下示例中 A 和 B 两个链表相交于 c1:

A:     a1 → a2
            ↘
               c1 → c2 → c3
             ↗
B:    b1 → b2 → b3          

但是不会出现以下相交的情况,因为每个节点只有一个 next 指针,也就只能有一个后继节点,而以下示例中节点 c 有两个后继节点。


A:     a1 → a2       d1 → d2
               ↘  ↗
                 c
               ↗  ↘
B: b1 → b2 → b3        e1 → e2

要求时间复杂度为 O(N),空间复杂度为 O(1)。如果不存在交点则返回 null。

设 A 的长度为 a + c,B 的长度为 b + c,其中 c 为尾部公共部分长度,可知 a + c + b = b + c + a。

当访问 A 链表的指针访问到链表尾部时,令它从链表 B 的头部开始访问链表 B;同样地,当访问 B 链表的指针访问到链表尾部时,令它从链表 A 的头部开始访问链表 A。这样就能控制访问 A 和 B 两个链表的指针能同时访问到交点。

如果不存在交点,那么 a + b = b + a,以下实现代码中 l1 和 l2 会同时为 null,从而退出循环。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {

    ListNode l1 = headA, l2 = headB;

    while (l1 != l2) {

        l1 = (l1 == null) ? headB : l1.next;

        l2 = (l2 == null) ? headA : l2.next;

    }

    return l1;

}

如果只是判断是否存在交点,那么就是另一个问题,有两种解法:

  • 把第一个链表的结尾连接到第二个链表的开头,看第二个链表是否存在环;

  • 或者直接比较两个链表的最后一个节点是否相同。

树的高度

public int maxDepth(TreeNode root) {

    if (root == null) return 0;

    return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;

}

数组中两个数的和为给定值

可以先对数组进行排序,然后使用双指针方法或者二分查找方法。这样做的时间复杂度为 O(NlogN),空间复杂度为 O(1)。

用 HashMap 存储数组元素和索引的映射,在访问到 nums[i] 时,判断 HashMap 中是否存在 target - nums[i],如果存在说明 target - nums[i] 所在的索引和 i 就是要找的两个数。该方法的时间复杂度为 O(N),空间复杂度为 O(N),使用空间来换取时间。

public int[] twoSum(int[] nums, int target) {

    HashMap<Integer, Integer> indexForNum = new HashMap<>();

    for (int i = 0; i < nums.length; i++) {

        if (indexForNum.containsKey(target - nums[i])) {

            return new int[]{indexForNum.get(target - nums[i]), i};

        } else {

            indexForNum.put(nums[i], i);

        }

    }

    return null;

}

编程题

容器

选择题

  • 编译并运行以下程序段的结果是:( B )
   public static void main(String[] args) {
        Frame f=new Frame ("Visual");
        f.setSize(300,300);
        f.setVisible(true);
        Point p=f.getLocation();
        //p.setLocation(30,30);
        System.out.println("x is "+ p.x);
        System.out.println("y is "+ p.y);
    }

  A.   x is 300

   y is 300

   B.   x is 0

   y is 0

   C.   x is 0
   y is 300

   D.   x is 300

   y is 0

  • 哪个布局管理器使用的是组件的最佳尺寸? ( A )

A. FlowLayout B. BorderLayout
C. GridLayout D. CardLayout

  • Frame的默认的布局管理器是下列哪一个? ( B )
    A.FlowLayout
    B.BorderLayout
    C.GridLayout
    D.CardLayout

  • 下列哪个用户图形界面组件在软件安装程序中是常见的? ( B )
    A.滑块
    B.进度条
    C.对话框
    D.标签

  • 包含可单击按钮的类的Java类库是哪个? C
    A.AWT
    B.Swing
    C.二者都有
    D.二者都没有

  • 下面的哪个用户界面组件不是容器? ( D )
    A. JScrollPane
    B. JFrame
    C. JWindows
    D. JScrollBar

  • 在下列事件处理机制中哪个不是机制中的角色? ( C )
    A. 事件            
    B. 事件源
    C. 事件接口       
    D. 事件处理者

  • 容器被重新设置大小后,哪种布局管理器的容器中的组件大小不随容器大小的变化而改变? ( B )
    A.   CardLayout
    B.   FlowLayout
    C.   BorderLayout
    D.   GridLayout

  • 监听事件和处理事件( C )
    A.   都由Listener完成  
    B.   都由相应事件Listener处登记过的构件完成  
    C.   由Listener和构件分别完成  
    D.   由Listener和窗口分别完成

  • 如果希望所有的控件在界面上均匀排列,应使用下列那种布局管理器?( D )
    A.   BoxLayout
    B.   GridLayout
    C.   BorderLayout
    D.   FlowLouLayout

填空题

  • Java的抽象窗口工具包中包含了许多类来支持__设计。GUI
  • Button类、Label类是包java.awt中的类,并且是java.awt包中的___的子类。Component
  • Java把有Component类的子类或间接子类创建的对象称为一个____。组件
  • Java程序中可以向容器添加组件,一个容器可以使用__方法将组件添加到该容器中。add( )
  • Applet类是包__中的一个类,同时还是包java.awt中容器类的子类。java.applet
  • 一个Java Applet小应用程序是有若干个类组成,且必须有一个类扩展了___类。Applet
  • 一个完整的Java Applet的生命周期包含init( )、、stop( )、destroy( )、paint(Graphics g)方法。stat( )
  • 在Java Applet程序中,对象首先自动调用___方法完成必要的初始化工作。init( )
  • 在Java Applet程序中,初始化之后,紧接着自动调用__方法。start( )
  • 在Java Applet程序中,当浏览器离开Java Applet所在的页面转到其他页面时, _____方法被调用。stop( )
  • 在Java Applet程序中,当浏览器结束浏览时,执行___方法,结束applet的生命。destroy( )
  • Java Applet的主类的实例是一个____,因此Java Applet可以添加交互组件。容器
  • 在java.awt包中的___类是专门用来建立文本框,它的一个对象就是一个文本框。TextField
  • 一个Java Applet 不再需要main方法,但必须有一个类扩展了_____类。Applet
  • Java Applet 必须有____来运行。浏览器
  • 用JDK工具,显示Applet程序运行结果的命令是___。appletviewer
  • 运行一个Applet程序,可通过双击其相应的超文本文件(A.html)来显示运行结果,或在命令控制台窗口下输入执行浏览器的命令: appletviewer A.html 。
  • java.awt 包封装了提供用户图形界面功能的抽象窗口工具类。
  • TextField类 是对单行文本进行编辑的组件。
  • 设置文本内容的方法是setText(String t)。
  • 获取文本内容的方法是 getText() 。
  • TextArea 是对多行文本进行编辑的组件。
  • 如果一个Java程序实现了监听接口ActionListener,则该程序的最开头必须引用类包 java.awt.event.* 。
  • Label 是用户只能查看其内容但不能修改的文本组件。
  • 获取按钮上的标签内容的方法是 getText() 。
  • 为了使组件能在面板上显示出来,需用 add 方法把组件添加到面板上。
  • 假若一个按钮产生了一个ActionEvent事件,则事件监听器会将该事件传递给 actionPerformed()方法来进行事件处理。
  • Java中最常见的3种布局方式:FlowLayout、BorderLayout和 GridLayout。
  • Applet容器的默认布局方式是 FlowLayout 。
  • Frame窗体的默认布局方式是 BorderLayout 。
  • FlowLayout 类是按组件的顺序,从左到右一行排列,一行放不下时自动换行。
  • BorderLayout 类把容器划分成东、西、南、北、中5个区域。
  • GridLayout 类是以行、列形式将容器划分成大小相等的单元格。
  • 假若一个按钮btn要产生一个ActionEvent事件,则使用 addActiionListener 方法 来注册监听器。
  • 事件处理者通常是一个类,该类如果能够处理某种类型的事件,就必须实 现与该事件类型相对应的 接口 。
  • 假若一个类实现了某个接口,则该类必须实现接口中所有的方法,但 Adapter 类只需重写需要的方法,而无关方法不用实现。

简答题

编程题

协议

简答题

TCP的三次握手和四次挥手,浏览器访问一个网址的过程

Java高级:面试题-1_第16张图片
位码即tcp标志位,有6种表示:SYN(synchronous建立连接)、ACK(acknowledgement 表示响应、确认)、PSH(push表示有DATA数据传输)、FIN(finish关闭连接)、RST(reset表示连接重置)、URG(urgent紧急指针字段值有效)

三次握手(建立连接):

第一次握手:客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

四次挥手(断开连接):

第一次挥手:主动关闭方发送一个FIN,用来关闭主动方到被动关闭方的数据传送。也就是主动关闭方告诉被动关闭方:我已经不会再给你发数据了。

第二次挥手:被动关闭方收到FIN包后,发送一个ACK给对方,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。

第三次挥手:被动关闭方发送一个FIN,用来关闭被动关闭方到主动关闭方的数据传送,也就是告诉主动关闭方,我的数据也发送完了,不会再给你发数据了。

第四次挥手:主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,至此,完成四次挥手。

访问过程:域名解析–>三次握手–>传输数据–>四次挥手。

TCP与UDP区别

  1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接;

  2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付;

  3. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信;

  4. UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信;

HTTP、HTTPS区别

a. HTTP协议传输的数据都是未加密的,也就是明文的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输

b. https协议需要到ca申请证书。

你可能感兴趣的:(Java体系,java,网络协议)