面试经验总结001

1.CAS的引发的ABA问题:详细描述
解决方法:使用AtomicStampedReference类加版本号

2.HTTP、TCP、IP在哪层?
应用层、传输层、网络层

3.ArrayList底层基于数组,初始容量InicialCapcity为10,默认扩容机制是扩容为原来的1.5倍,因为是oldCapicity>>1,会有小数点舍弃的情况。
HashMap底层基于数组+链表+红黑树,初始容量是16,默认的扩容机机制为增加1倍。

4.JVM常用的调优参数:
-Xms:初始堆大小 默认内存:物理内存1/64
-Xmx:最大堆大小 默认内存:物理内存1/4
-Xss:每个线程堆栈大小 ,系统有默认的初始值-XX:ThreadStackSize
-XX:+PrintGCDetails详细GC日志

5.JVM新生代老年代占比

6.TCP三次握手与四次挥手
三次握手
Round1: 客户端发送连接请求报文段,无应用层数据。
SYN=1,seq=x[随机]
Round2:客户端为该TCP连接分配缓存和变量,并向客户端返回确认报文段,允许连接,无应用层数据。
SYN=1,ACK=1,seq=y(随机),ack=x+1
Round3:客户端为该TCP连接分配缓存和变量,并向服务器端返回确认得确认,可以携带数据。
SYN=0,ACK=1,seq=x+1,ack=y+1

SYN洪泛攻击

四次挥手
Round1: 客户端发送连接释放报文段,停止发送数据,主动关闭TCP连接。
FIN=1,seq=u
Round2:服务器端回送一个确认报文段,客户到服务器这个方向的连接就释放了——半关闭状态。
ACK=1,seq=v,ack=u+1
Round3:服务器端发完数据,就发出连接释放报文段,主动关闭TCP连接,
FIN=1,ACK=1,seq=w,ack=u+1
Round4:客户端回送一个确认报文段,再等到时间等待计时器设置的2MSL(最长报文段寿命)后,连接彻底关闭。
ACK=1,seq=u+1,ack=w+1

7.线程池相关
线程池都有哪些参数?(给我记得死死的!!!)
1.corePoolSize
核心池数量,表示当前线程池中维护最小的线程数量,即使线程空闲也不会被销毁。
2.maximumPoolSize
线程池最大线程数,当该线程被分配一个任务时,首先会被缓存到工作队列workQueue中,当工作队列已经满了,会创建一个新的线程,然后从工作队列中取出一个任务给新建的线程执行,刚提交的任务会被放入工作队列中。
线程池不会无限创建新线程,线程池的最大线程数由maximumPoolSize规定。
3.keepAliveTime
线程存活时间,当线程池中某个线程空闲时,并且此时的线程数量超过核心池数量corePoolSize,则超过线程存活时间keepAliveTime该线程就会被销毁。
4.unit
线程存活时间keepAliveTime的计量单位
取值为TimeUnit枚举类型的值
TimeUnit.HOURS; //小时
  TimeUnit.MINUTES; //分钟
  TimeUnit.SECONDS; //秒
  TimeUnit.MILLISECONDS; //毫秒
  TimeUnit.MICROSECONDS; //微妙
  TimeUnit.NANOSECONDS; //纳秒
5.workQueue
工作队列,新任务被提交后,会先进入到此工作队列中,任务调度时再从队列中取出任务。
jdk中提供了四种工作队列:
①ArrayBlockingQueue
基于数组的有界阻塞队列,按FIFO排序。新任务进来后,会放到该队列的队尾,有界的数组可以防止资源耗尽问题。当线程池中线程数量达到corePoolSize后,再有新任务进来,则会将任务放入该队列的队尾,等待被调度。如果队列已经是满的,则创建一个新线程,如果线程数量已经达到maxPoolSize,则会执行拒绝策略。
②LinkedBlockingQuene
基于链表的无界阻塞队列(其实最大容量为Interger.MAX),按照FIFO排序。由于该队列的近似无界性,当线程池中线程数量达到corePoolSize后,再有新任务进来,会一直存入该队列,而不会去创建新线程直到maxPoolSize,因此使用该工作队列时,参数maxPoolSize其实是不起作用的。
③SynchronousQuene
一个不缓存任务的阻塞队列,生产者放入一个任务必须等到消费者取出这个任务。也就是说新任务进来时,不会缓存,而是直接被调度执行该任务,如果没有可用线程,则创建新线程,如果线程数量达到maxPoolSize,则执行拒绝策略。
④PriorityBlockingQueue
具有优先级的无界阻塞队列,优先级通过参数Comparator实现。
6.threadFactory
线程工厂,可以用来设定线程名、是否为daemon线程等等
7.handler
拒绝策略
①CallerRunsPolicy
由调用线程执行当前任务
②AbortPolicy
抛弃当前任务并抛RejectedExecutionException异常。
③DiscardPolicy
直接丢弃任务,不报异常
④DiscardOldestPolicy
该策略下,抛弃进入队列最早的那个任务,然后尝试把这次拒绝的任务放入队列

!!!!!!!!!!!
8.python数据类型和Java数据类型对比
—— Python <——> Java
整型 int <——>int,short,long
浮点 float<——>float,double
布尔True=1,Flase=0<——>true,false
复数complex
String字符串"“或’'表示,可切片,左右索引,元素不可变<——>”"表示,剩下的不多说
没有字符形式<——>char
List列表[,,],可切片可+,元素类型可不同,元素可变<——>List< Object >
Tuple元组(,,),可切片可+,元素类型可不同,元素不可变<——>Sets集合(),无序不重复
字典(key=value,key=value)<——>map

python总结:
可变数据对象:列表(list)和字典(dict)
不可变数据对象:整型(int)、浮点型(float)、字符串(string)和元组类型(tuple)
注:此处的可变和不可变,是指内存中的对象(Value)是否可以改变,对于不可变类型的对象,在对对象操作的时候,必须在内存中重新申请一块新的区域,即重新给一个新的地址用于存储;对于可变类型的对象,在对对象操作的时候,并不会重新申请新的地址,而是在该对象的地址后面继续申请即可,即address并不会改变,而是address的区域的大小会变长或变短。

9.时间复杂度和空间复杂度的计算

10.关系型数据库:
MySQL
Oracle
DB2
SQL Server
Access

11volite防止指令重排
主要在于singleton = new Singleton()这句,这并非是一个原子操作,事实上在 JVM 中这句话大概做了下面 3 件事情。
  1. 给 singleton 分配内存
  2. 调用 Singleton 的构造函数来初始化成员变量,形成实例
  3. 将singleton对象指向分配的内存空间(执行完这步 singleton才是非 null了)

在JVM的即时编译器中存在指令重排序的优化。
  
也就是说上面的第二步和第三步的顺序是不能保证的,最终的执行顺序可能是 1-2-3 也可能是 1-3-2。如果是后者,则在 3 执行完毕、2 未执行之前,被线程二抢占了,这时 instance 已经是非 null 了(但却没有初始化),所以线程二会直接返回 instance,然后使用,然后顺理成章地报错。
  
再稍微解释一下,就是说,由于有一个『instance已经不为null但是仍没有完成初始化』的中间状态,而这个时候,如果有其他线程刚好运行到第一层if (instance ==null)这里,这里读取到的instance已经不为null了,所以就直接把这个中间状态的instance拿去用了,就会产生问题。这里的关键在于线程T1对instance的写操作没有完成,线程T2就执行了读操作。
  
对于代码三出现的问题,解决方案为:给instance的声明加上volatile关键字
代码如下:

public class Singleton {
   private static volatile Singleton instance = null;
   private Singleton() {}
 
   public static Singleton getInstance() {
   if (instance == null){
     synchronized(Singleton.class){
       if (instance == null)
         instance = new Singleton();
     }
   }
   return instance;
   }
}

volatile关键字的一个作用是禁止指令重排,把instance声明为volatile之后,对它的写操作就会有一个内存屏障,这样,在它的赋值完成之前,就不用会调用读操作。

注意:volatile阻止的不是singleton = new Singleton()这句话内部[1-2-3]的指令重排,而是保证了在一个写操作([1-2-3])完成之前,不会调用读操作(if (instance == null))。

12session和cookie
Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
总结:
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5、可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。

13hashmap底层和hashtable底层
都是哈希表(数组+链表+红黑树),但是hashtable用了synchronized加锁,线程安全但效率低

14JDK 和JRE
JDK java开发环境 JDK=JRE+java开发工具(javac.exe,java.exe,javadoc.exe)
JRE java运行环境 JRE=JVM+java核心工具类

15计算机网络七层协议模型
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层

16计网之死锁条件
四个充分条件:
互斥条件:资源任意一个时刻只能被一个线程占用
请求与保持条件:一个线程因为请求资源而堵塞的时候,对已获得的资源保持不放
不剥夺条件:线程对于已经获得的资源在未使用完之前不能被其他线程强行剥夺,只有线程自己使用完毕之后才能释放
循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

避免死锁只要破坏其中一条条件即可!

17拥塞控制采用什么算法
慢开始
拥塞避免
快重传与快恢复

18数据库索引
myisam是非聚簇索引
innodb是聚簇索引

19****LRU最近最少使用
使用LinkedHashMap,最近使用放队首,最少使用排在队尾

public class LRUcache extends LinkedHashMap {
    private int size;
    
    public LRUcache(int size){
        super(16,0.75,true);
        this.size=size;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size()>=size;
    }
}

20mysql隔离级别为什么不直接用串行化?
serializable的效率较低,不支持较大的高并发。
serializable隔离级别的多个事务不可以同时对同一张表修改!
串行化事务中,行锁容易发生死锁。

21情景题
解耦,异步
方法有三:
线程(线程池、子线程(缺点:无法控制线程数量))
mq,支持重发,独立应用
入库之后再调度,缺点是消耗数据库和应用服务器的性能

22线程的状态
NEW
RUNNABLE
BLOCKED
WAITING
TIMED_WAITING
TERMINATED

23线程切换需要消耗哪些资源
线程开启需要占用的资源

24不用线程池的话,需要一个线程就创一个线程,会出现什么问题
1.不受控风险
2.频繁创建开销大

25消息队列的使用场景

26MySQL 中 MyISAM 中的查询为什么比 InnoDB 快?
MySQL 中 MyISAM 中的查询为什么比 InnoDB 快?

27cookie和session的区别
1、cookie数据存放在客户的浏览器上,session数据放在服务器上。

2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。

3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。

4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

5、可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。

28MySQL为什么要选用B+树
减少磁盘IO,查找效率稳定,便于遍历。

29G1和CMS区别,用什么算法,会不会分代?CMS和G1
CMS 第一个用户线程和收集线程并发执行的垃圾收集器,标记清除算法,针对老年代
初始标记
并发标记
重新标记
并发清除
G1面向服务器的垃圾收集器,分代回收,标记整理算法 利用优先列表G1就可以对部分的region进行回收!这使得停顿时间是用户自己可以控制的!!!!
初始标记
并发标记
最终标记
筛选回收

30syn和reenterlock区别底层,是不是可重入锁,是不是公平的 syn是不公平的
synchronized 是非公平锁,可以重入
ReentrantLock内部有公平锁和非公平锁两种,而这两种锁都是基于AQS同步器实现的,可重入

31单例设计模式手写

32concurrenthashmap和hashmap

33spring循环依赖,单例模式不会发生死锁
详解
超级详细
“A的某个field或者setter依赖了B的实例对象,同时B的某个field或者setter依赖了A的实例对象”这种循环依赖的情况。A首先完成了初始化的第一步,并且将自己提前曝光到singletonFactories中,此时进行初始化的第二步,发现自己依赖对象B,此时就尝试去get(B),发现B还没有被create,所以走create流程,B在初始化第一步的时候发现自己依赖了对象A,于是尝试get(A),尝试一级缓存singletonObjects(肯定没有,因为A还没初始化完全),尝试二级缓存earlySingletonObjects(也没有),尝试三级缓存singletonFactories,由于A通过ObjectFactory将自己提前曝光了,所以B能够通过ObjectFactory.getObject拿到A对象(虽然A还没有初始化完全,但是总比没有好呀),B拿到A对象后顺利完成了初始化阶段1、2、3,完全初始化之后将自己放入到一级缓存singletonObjects中。此时返回A中,A此时能拿到B的对象顺利完成自己的初始化阶段2、3,最终A也完成了初始化,进去了一级缓存singletonObjects中,而且更加幸运的是,由于B拿到了A的对象引用,所以B现在hold住的A对象完成了初始化。

知道了这个原理时候,肯定就知道为啥Spring不能解决“A的构造方法中依赖了B的实例对象,同时B的构造方法中依赖了A的实例对象”这类问题了!因为加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决。

34spring的底层源码

35MySQL为什么采用B+树,跟B+树的数据结构有关,为什么innodb只在叶子节点上存放索引文件和数据文件?为了减少树的高度

36什么是反射,反射的优缺点

37Executors工具类下的线程都有什么?使用的是什么阻塞队列?

38Synchronized锁升级的底层synchronized详解
锁的优化
1、锁升级
锁的4中状态:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态(级别从低到高)

(1)偏向锁:

为什么要引入偏向锁?

因为经过HotSpot的作者大量的研究发现,大多数时候是不存在锁竞争的,常常是一个线程多次获得同一个锁,因此如果每次都要竞争锁会增大很多没有必要付出的代价,为了降低获取锁的代价,才引入的偏向锁。

偏向锁的升级

当线程1访问代码块并获取锁对象时,会在java对象头和栈帧中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,因此以后线程1再次获取锁的时候,需要比较当前线程的threadID和Java对象头中的threadID是否一致,如果一致(还是线程1获取锁对象),则无需使用CAS来加锁、解锁;如果不一致(其他线程,如线程2要竞争锁对象,而偏向锁不会主动释放因此还是存储的线程1的threadID),那么需要查看Java对象头中记录的线程1是否存活,如果没有存活,那么锁对象被重置为无锁状态,其它线程(线程2)可以竞争将其设置为偏向锁;如果存活,那么立刻查找该线程(线程1)的栈帧信息,如果还是需要继续持有这个锁对象,那么暂停当前线程1,撤销偏向锁,升级为轻量级锁,如果线程1 不再使用该锁对象,那么将锁对象状态设为无锁状态,重新偏向新的线程。

偏向锁的取消:

偏向锁是默认开启的,而且开始时间一般是比应用程序启动慢几秒,如果不想有这个延迟,那么可以使用-XX:BiasedLockingStartUpDelay=0;

如果不想要偏向锁,那么可以通过-XX:-UseBiasedLocking = false来设置;

(2)轻量级锁

为什么要引入轻量级锁?

轻量级锁考虑的是竞争锁对象的线程不多,而且线程持有锁的时间也不长的情景。因为阻塞线程需要CPU从用户态转到内核态,代价较大,如果刚刚阻塞不久这个锁就被释放了,那这个代价就有点得不偿失了,因此这个时候就干脆不阻塞这个线程,让它自旋这等待锁释放。

轻量级锁什么时候升级为重量级锁?

线程1获取轻量级锁时会先把锁对象的对象头MarkWord复制一份到线程1的栈帧中创建的用于存储锁记录的空间(称为DisplacedMarkWord),然后使用CAS把对象头中的内容替换为线程1存储的锁记录(DisplacedMarkWord)的地址;

如果在线程1复制对象头的同时(在线程1CAS之前),线程2也准备获取锁,复制了对象头到线程2的锁记录空间中,但是在线程2CAS的时候,发现线程1已经把对象头换了,线程2的CAS失败,那么线程2就尝试使用自旋锁来等待线程1释放锁。

但是如果自旋的时间太长也不行,因为自旋是要消耗CPU的,因此自旋的次数是有限制的,比如10次或者100次,如果自旋次数到了线程1还没有释放锁,或者线程1还在执行,线程2还在自旋等待,这时又有一个线程3过来竞争这个锁对象,那么这个时候轻量级锁就会膨胀为重量级锁。重量级锁把除了拥有锁的线程都阻塞,防止CPU空转。

*注意:为了避免无用的自旋,轻量级锁一旦膨胀为重量级锁就不会再降级为轻量级锁了;偏向锁升级为轻量级锁也不能再降级为偏向锁。一句话就是锁可以升级不可以降级,但是偏向锁状态可以被重置为无锁状态。

39打破双亲委派机制
打破双亲委派机制则不仅要继承ClassLoader类,还要重写loadClass和findClass方法,如下例子:

①定义Test类。

public class Test {
public Test(){
System.out.println(this.getClass().getClassLoader().toString());
}
}
②重新定义一个继承ClassLoader的TestClassLoaderN类,这个类与前面的TestClassLoader类很相似,但它除了重写findClass方法外还重写了loadClass方法,默认的loadClass方法是实现了双亲委派机制的逻辑,即会先让父类加载器加载,当无法加载时才由自己加载。这里为了破坏双亲委派机制必须重写loadClass方法,即这里先尝试交由System类加载器加载,加载失败才会由自己加载。它并没有优先交给父类加载器,这就打破了双亲委派机制。
public class TestClassLoaderN extends ClassLoader {

private String name;

public TestClassLoaderN(ClassLoader parent, String name) {
super(parent);
this.name = name;
}

@Override
public String toString() {
return this.name;
}

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
Class<?> clazz = null;
ClassLoader system = getSystemClassLoader();
try {
clazz = system.loadClass(name);
} catch (Exception e) {
// ignore
}
if (clazz != null)
return clazz;
clazz = findClass(name);
return clazz;
}

@Override
public Class<?> findClass(String name) {

InputStream is = null;
byte[] data = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
  is = new FileInputStream(new File("d:/Test.class"));
  int c = 0;
  while (-1 != (c = is.read())) {
    baos.write(c);
  }
  data = baos.toByteArray();
} catch (Exception e) {
  e.printStackTrace();
} finally {
  try {
    is.close();
    baos.close();
  } catch (IOException e) {
    e.printStackTrace();
  }
}
return this.defineClass(name, data, 0, data.length);

}

public static void main(String[] args) {
TestClassLoaderN loader = new TestClassLoaderN(
TestClassLoaderN.class.getClassLoader(), “TestLoaderN”);
Class clazz;
try {
clazz = loader.loadClass(“test.classloader.Test”);
Object object = clazz.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}

}

40java对象实现serializable有什么作用
好处:
a)比如说你的内存不够用了,那计算机就要将内存里面的一部分对象暂时的保存到硬盘中,等到要用的时候再读入到内存中,硬盘的那部分存储空间就是所谓的虚拟内存。在比如过你要将某个特定的对象保存到文件中,我隔几天在把它拿出来用,那么这时候就要实现Serializable接口;
b)在进行java的Socket编程的时候,你有时候可能要传输某一类的对象,那么也就要实现Serializable接口;最常见的你传输一个字符串,它是JDK里面的类,也实现了Serializable接口,所以可以在网络上传输。
c)如果要通过远程的方法调用(RMI)去调用一个远程对象的方法,如在计算机A中调用另一台计算机B的对象的方法,那么你需要通过JNDI服务获取计算机B目标对象的引用,将对象从B传送到A,就需要实现序列化接口。

41BIO、NIO和AIO区别
BIO与NIO、AIO的区别(容易理解的解释)

42堆排序 代码 一般升序采用大顶堆,降序采用小顶堆
堆排序

public class HeapSort {
    public static void main(String[] args) {
        int[] arr=new int[]{48,34,56,32,66,88,33,23};
        heapsort(arr);
        System.out.println(Arrays.toString(arr));
    }

    private static void heapsort(int[] arr) {
        for(int i=arr.length/2-1;i>=0;i--){
            adjustheap(arr,i,arr.length);//左闭右开
        }
        for(int j=arr.length-1;j>0;j--){
            swap(arr,0,j);
            adjustheap(arr,0,j);
        }
    }

    private static void swap(int[] arr, int i, int j) {
        int tem=arr[i];
        arr[i]=arr[j];
        arr[j]=tem;
    }

    private static void adjustheap(int[] arr, int i, int length) {
        int tem=arr[i];

        for(int k=2*i+1;k<length;k=k*2+1){
            if(k+1<length&&arr[k]<arr[k+1]){
                k++;
            }
            if(arr[k]>tem){
                arr[i]=arr[k];
                i=k;
            }else{
                break;
            }
        }
        arr[i]=tem;
    }
}

43运行时异常和非运行时异常
在Java中异常被当做对象来处理,根类是java.lang.Throwable类,在Java中定义了很多异常类(如OutOfMemoryError、NullPointerException、IndexOutOfBoundsException等),这些异常类分为两大类:Error和Exception。

Error是无法处理的异常,比如OutOfMemoryError,一般发生这种异常,JVM会选择终止程序。因此我们编写程序时不需要关心这类异常。

Exception,也就是我们经常见到的一些异常情况,比如NullPointerException、IndexOutOfBoundsException,这些异常是我们可以处理的异常。

Exception类的异常包括checked exception和unchecked exception(unchecked exception也称运行时异常RuntimeException,当然这里的运行时异常并不是前面我所说的运行期间的异常,只是Java中用运行时异常这个术语来表示,Exception类的异常都是在运行期间发生的)。

unchecked exception(非检查异常),也称运行时异常(RuntimeException),比如常见的NullPointerException、IndexOutOfBoundsException。对于运行时异常,java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。

checked exception(检查异常),也称非运行时异常(运行时异常以外的异常就是非运行时异常),java编译器强制程序员必须进行捕获处理,比如常见的IOExeption和SQLException。对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过。
  
  在Java中,所有异常类的父类是Throwable类,Error类是error类型异常的父类,Exception类是exception类型异常的父类,RuntimeException类是所有运行时异常的父类,RuntimeException以外的并且继承Exception的类是非运行时异常。

典型的RuntimeException包括NullPointerException、IndexOutOfBoundsException、IllegalArgumentException等。

典型的非RuntimeException包括IOException、SQLException等。

44ArrayList的remove(int index)方法ArrayList底层
remove(int index)方法的作用是删除指定下标的元素。在该方法的源码中,将指定下标后面一位到数组末尾的全部元素向前移动一个单位,并且把数组最后一个元素设置为null,这样方便之后将整个数组不再使用时,会被GC,可以作为小技巧。而需要移动的元素个数为:size-index-1。

public E remove(int index) {
// 检查索引是否合法
rangeCheck(index);

modCount++;
E oldValue = elementData(index);
// 需要移动的元素的个数
int numMoved = size - index - 1;
if (numMoved > 0)
    System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
// 赋值为空,有利于进行GC
elementData[--size] = null; 
// 返回旧值
return oldValue;

}

44MySQL中char和varchar的区别
(1)char是定长,如char(10),超过10个字符就截取插入,没超过就用空格补足。varchar是变长,如varchar(10),没超过指定范围,有多少字符存多少,超出的话根据指定模式处理,宽松模式截取后插入,严格模式提示错误信息。
(2)二者的存储容量不同
char最多存放255个字符(额外需要1到2个字节来存长度)
varchar最多存放65532个字节(从中还需要拿出1到2个字节来存长度)
(3)一般定长的数据选用char类型,比如身份证号,手机号,电话等,长度变化很大的可以使用varchar类型

注意:
根据编码不同,长度限制也不同:

字符类型为Latin1,每个字符占用1个字节,最大长度不能超过65532;

字符类型若为gbk,每个字符最多占2个字节,最大长度不能超过32766;

字符类型若为utf8,每个字符最多占3个字节,最大长度不能超过21845。

若定义的时候超过上述限制,则varchar字段会被强行转为text类型,并产生warning。

45Skiplist跳表跳表
ConcurrentSkipListMap
Skiplist性质:
(1) 由很多层结构组成,level是通过一定的概率随机产生的;
(2) 每一层都是一个有序的链表,默认是升序 ;
(3) 最底层(Level 1)的链表包含所有元素;
(4) 如果一个元素出现在Level i 的链表中,则它在Level i 之下的链表也都会出现;
(5) 每个节点包含两个指针,一个指向同一链表中的下一个元素,一个指向下面一层的元素。

46String中的intern方法String和常量池分析
String.intern()方法作用:
intern方法都是要在常量池拿到一个独一无二的变量,如果没有则创建,有则指向它,返回的是引用

public class Main33 {
    public static void main(String[] args) {
        String str=new String("我是小仙女!");
        String intern = str.intern();
        String str2="我是小仙女!";
        System.out.println(intern==str);
        System.out.println(intern==str2);
    }
}

结果

false
true

46快速排序最坏情况O(n2)
在分解时每次选取的主元素为最小元素
在分解时每次选取的主元素为最大元素

47****海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)
海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)
利用hash去重后用小顶堆

48IPV4与IPV6的区别
IPV4与IPV6的区别
ipv4长度为4字节
ipv6长度为16个字节

49python中的range()函数
python中range()函数可创建一个整数列表,一般用在for循环中.
range()函数语法:
range(start,stop[,step])
参数说明:
star: 计数从star开始.默认是从0开始.
stop: 计数到stop结束,但不包括stop.
step: 步长,默认为1.

50redirect和forward:
redirect方式相当于“response.sendRedirect()”,转发后浏览器的地址栏变为重定向后的地址,不共享之前请求的数据。
forward方式相当于“request.getRequestDispatcher().forward(request,response)”,转发后浏览器地址栏还是原来的地址,共享之前请求中的数据。

51LCS最长公共子序列 利用动态规划

import java.util.Stack;

public class LCSTest {
    public static void main(String[] args) {
        String str1=new String("hbjknmkldmvs");
        String str2=new String("dbrbsdfhngs");
        LCS(str1,str2);
    }
    public  static  void LCS(String str1,String str2){
        int len1=str1.length();
        int len2=str2.length();
        int[][] dp=new int[len1+1][len2+1];

        for(int i=0;i<len1;i++){
            dp[i][0]=0;
        }
        for(int j=0;j<len2;j++){
            dp[0][j]=0;
        }

        for(int i=1;i<=len1;i++){
            for(int j=1;j<=len2;j++){
                if(str1.charAt(i-1)==str2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        System.out.println(dp[len1][len2]);

        Stack<Character> stack=new Stack<>();
        int x=len1-1;
        int y=len2-1;
        while(x>=0&&y>=0){
            if(str1.charAt(x)==str2.charAt(y)){
                stack.push(str1.charAt(x));
                x--;
                y--;
            }else{
                if(dp[x+1][y]>dp[x][y+1]){
                    y--;
                }else{
                    x--;
                }
            }


        }
        while(!stack.isEmpty()){
            System.out.print(stack.pop());
        }
    }
}

52进程与线程
进程是资源分配的基本单位.线程是执行和调度的基本单位.线程本身不拥有资源,资源来自于它的进程.

53腾讯面试:全国范围内每个人的乘车记录中查找一条数据,要怎么查找?
利用每个人的id不同,通过散列表(与哈希表类似,通过取余定位该数据可以分配在哪个库中)分库建表存储数据,提高查找效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值