Java, 基础(面试题)总结(分享-交流)

1. Finally,final,finalize

  • Finally:
    释放资源(内存之外的,打开的文件、连接、屏幕上的图形,,)

    • 总会执行
    • 非后台线程结束,后台线程被强关,不会执行finally
    • 当try和catch中有return时,finally在return之后执行,但是返回值不会改变(finally中不会改变已保存的返回结果)
    • finally中最好不要包含return,否则程序会从finally中退出,返回值不是try或catch中保存的返回值。
  • final:
    基本数据类型:不可更改
    类:不可继承
    对象:引用不可变,对象内容可变

  • finalze:
    回收前调用,不适合用来清理或释放资源。对象免死最后机会!保证会被调用,但不保证会执行完(在低优先级线程中执行)

2. 数据在各个网络层之间是怎么传输的?

  • 数据在各层之间的单位都是不一样的,
  • 在物理层数据的单位称为比特(bit);在数据链路层,数据的单位称为帧(frame);
  • 在网络层,数据的单位称为数据包(packet);传输层,数据的单位称为数据段(segment)。

3. Hashtable、HashMap

  • Hashtable 与 HashMap类似,但是主要有7点不同。

    1. HashTable的方法是同步的,HashMap未经同步,如Vector和ArrayList一样。
    2. HashTable不允许null,key和value都不可以,HashMap允许null值,key和value都可以。HashMap允许 key值只能由一个null
    3. HashTable有一个contains(Object value)功能和containsValue(Object value)功能一样。
    4. 遍历的时候,HashTable使用Enumeration,HashMap使用Iterator。
    5. HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。
    6. 哈希值的使用不同,HashTable直接使用对象的hashCode。
    7. Hashtable继承自Dictionary类,实现了Map接口。而HashMap是继承自AbstractMap,实现了Map接口。
  • HashMap:
    一个数组,hash(h)决定位置,
    冲突使用链表法:单向–Entry对象(保存final key,value,next指针,hash值),遍历比较hash值
    Collections.synchronizedMap(hashmap)来构造一个线程安全的map,与Hashtable几乎一样
    扩容:先插入再判断是否扩容

  • Hashtable: 直接使用对象hash值,对跟线程安全相关的方法和步骤加Syncrolized

  • LinkedHashMap:
    继承HashMap, 重写Entry类,before,after两个指针,保存插入顺序或者访问顺序(可指定)

  • HashSet:
    持有一个HashMap
  • ConcurrentHashMap:
    • 两个数组Segment[] 和HashEntry[]
    • Segment: extends ReentrantLock, 一种可重入锁,持有一个数组HashEntry[],可以通过concurrencylevel指定Segment数组长度
    • HashEntry: hash,key,value,next
    • 读不需要锁,读到空时加锁重读
    • 扩容:支队某个Segment的HashEntry[]扩容,先判断是否扩容再插入
    • size():先尝试两次锁,判断modCount是否变化再决定是否加锁。
  • CopyOnWriteArrayList: 适合多读少写,只保证最终一致性,不保证实时一致性
    • 加锁–>拷贝数据–>改、写–>赋值回去–>解锁
    • 用的ReentrantLock,读无需锁,可能读到旧数据。
  • TreeMap:红黑树,可自定义顺序
  • TessSet:TreeMap

4. GET,POST区别?

  • 基础知识: Http的请求格式如下。
    主要包含三个信息:
    1、请求的类型(GET或POST),2、要访问的资源(如res\img\a.jif),3、Http版本(http/1.1)
    用来说明服务器要使用的附加信息
    这是Http的规定,必须空一行
    [] 请求的内容数据

  • 区别:
    1、Get是从服务器端获取数据,Post则是向服务器端发送数据。
    2、在客户端,Get方式通过URL提交数据,在URL地址栏可以看到请求消息,该消息被编码过;Post数据则是放在Html header内提交。
    3、对于Get方式,服务器端用Request.QueryString获取变量的值;对用Post方式,服务器端用Request.Form获取提交的数据值。
    4、Get方式提交的数据最多1024字节,而Post则没有限制。
    5、Get方式提交的参数及参数值会在地址栏显示,不安全,而Post不会,比较安全。

5. 网游服务器用TCP还是UDP

  • UDP:多用,一个socket,加自己的可靠协议,延迟要求高
  • TCP:承载链接数多,500以上有压力,魔兽世界用TCP,1000延迟照样玩
  • HTTP/HTTPS:由客户端间歇性的发起无状态的查询,并且偶尔发生延迟是可以容忍

6. 关于JAVA内存模型,一个对象(两个属性,四个方法)实例化100次,现在内存中的存储状态,几个对象,几个属性,几个方法。

  • 由于JAVA中new出来的对象都是放在堆中,所以如果要实例化100次,将在堆中产生100个对象,
  • 一般对象与其中的属性、方法都属于一个整体,但如果 属性和方法是静态的,就是用static关键字声明的,那么属于类的属性和方法永远只在内存中存在一份。

7. 红黑树的好处、AVL 树

  • 红黑树性质:

    • 根节点是黑色的;
    • 非黑即红;
    • 叶节点(空节点)是黑色的;
    • 父节点是红色的,则其孩子节点必须是黑色的;
    • 从某一个节点到叶节点的所有路径,其黑色节点数目相同。
  • 红黑树好处:

    • 红黑树是许多“平衡的”查找树中的一种,它能保证在最坏情况 下,基本的动态集合操作时间为 O(lgn)。
    • 红黑树并不追求完全平衡,它只要求部分的达到平衡要求,降低 了对旋转的要求,从而提高了性能。由于它的设计,任何不平衡都会在三次旋转之内解决。
    • 红黑树的算法时间复杂度和 AVL相同, 但统计性能比 AVL 树更高。
    • AVL 树明显比红黑树逻辑简单的多,但应用得少,应该是增删性能 差一点,增删时需要旋转的次数可能比较多。

8. 数组和链表,遍历效率哪个高,为什么(cpu缓存与内存)

  • 数组的效率高,因为数组是连续存储的,即内存地址是连续的,所以在读取数组时,会将连续的内存地址的数据放入缓存中,所以读取数组时相当于是从缓存读取。而链表遍历都是从内存读取,缓存的读取速度要比内存块 100 倍左右。

9. 进程间通信, 怎么共享内存

  • 匿名管道:单向,只能用于具有亲缘关系的进程间通信,如父 子进程、兄弟进程等,缓冲区大小有限制。
  • 命名管道:单向,可以用在任意的两个不同的进程间通信。
  • 信号量:主要用于同步。
  • 共享内存:最快的 IPC 机制,一般和信号量一起使用。一个进程创建,其他进程通过映射的形式,将共享内存加入到自己的内存空间中。数据结构:shmid_ds,函数 shmget:可以创建或 打开一块共享内存。
  • 消息队列:是消息的链接表,有足够权限的进程可以向队列中 添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了管道只能承载无格式字节流以及缓冲区大小受 限等缺点。
  • Socket:更为一般的进程间通信机制,可用于不同机器之间的进程间通信。

10. Fork 进程时,继承那些:

  • 继承:进程的资格、堆栈、环境、内存、打开文件的描述符、执行时关闭标志、信号控制设定、nice 值、进程调度类别、进程 组号、当前工作目录、根目录、资源限制、控制终端。
  • 独有:进程号、不同的父进程号、自己的文件描述符和目 录流的拷贝、子进程不继承父进程的进程,正文,数据和其他锁定内存、在 tms 结构中的系统时间、资源使用设定为 0、阻塞信号集初始化为空集、不继承由 timer_create 函数创建的计时器、不继承异步输入和输出。

11. 1000 个超大的文件,可能每一个都超过内存,怎么对他们进 行排序和消除冲项,1 个超大怎么排序和消除重项。

  • 读文件,计算hash(%10000),分成更小的文件,重复项肯定在一个文件里,归并的时候去重

12. 2 个数组,一个超大数组(10w 记录),一个小一点,几千条, 问怎么找交集。两个数组元素无重复

  • bitmap:bit数组,已bit代表一个数,1表示有,遍历大数组构造bit数组;遍历小数组,看对应位置是否为1

13. StackOverFlow和OutOfMemory分别在什么情况下出现

  • StackOverFlow:一般情况下stack的默认值为128k~256k, -Xss1024m
    请求栈深度大于允许最大深度,如:深度循环递归

    • OutOfMemory:
      多线程环境下,能够创建的线程最大内存=物理内存-最大堆内存-最大方法区内存,java虚拟机栈就会因为内存太小无法创建线程而产生OutOfMemoryError
      大的对象或数组,堆地方不够用
      运行时常量池(方法区)因无法再添加常量而产生OutOfMemoryError
      直接内存用光,堆与直接内存>物理内存
      虚拟机栈动态扩展时无法获得足够内存

14. java虚拟机模型

  • 虚拟机栈: 方法内存模型,一个方法一个栈帧,包括:局部变量表,操作数栈,动态链接,方法出口,请求栈深度大于允许报StackOverFlow,动态扩展无法申请足够内存,包OOM。-xss设栈容量默认256k?
  • 局部变量表: 所属对象引用,方法参数,局部变量(基本类型,引用)
    本地方法栈:与虚拟机栈相识,面向本地native方法,hotspot中与虚拟机栈合二为一
  • 堆: 对象实例,数组,类加载完成便可确定对象大小,OOM
  • 方法区: 也有人叫永久代(Permanent Generation)类信息,常量,静态变量等在加载完成后放入方法区,即时编译器编译后的代码。
  • 运行常量池:class文件中的常量池,编译生成的字面量,符号引用(new对象时:先检查此类的符号引用是否加载、解析、初始化过,若否,先加载);动态性:String.intern

15. 虚拟机垃圾回收

  • 可达性分析: 从GCroots向下搜索,判断是否有引用可达。
  • GCroots:
    虚拟机栈(本地变量表)中引用的对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中JNI引用的对象

  • 强引用:永远不会回收被引用的对象。
    软引用SoftRef:有用但非必需的对象,发生内存溢出异常前将对象列进回收范围中进行第二次回收,如果此次回收还没有足够内存才会抛异常
    弱引用WeakRef:非必需对象,只能生存到下一次垃圾回收之前,无论内存是否够,都会回收
    虚引用PhantomRef:完全不对生存时间构成影响,也无法通过虚引用来取得一个对象实例

  • 标记整理算法: 所有存活的对象都向一端移动,然后清理边界以外的内存
    分代收集:当前多采用,
    复制算法:老年代做担保,新生代分三块一个Eden80% 两个survivor都是10%

  • java堆分成:新生代Eden,老年代(Survivor,两个 from to)
    新生代:复制算法,
    老年代:存活率高,适合标记清理或整理。

  • Serial: 复制算法 单线程 client模式默认新生代收集器,stop the world,简单高效
    ParNew: Serial的多线程版本,其他都 server模式首选,只有它能跟CMS搭配
    Parallel Scavenge: 关注吞吐量(cpu执行用户)

    • 并行: 多个收集线程同时收集

      并发:收集线程和用户线程同时,不一定并行可能交替

    • 方法区(hotspot的永久代) 也可以回收
      废弃常量的回收
      类的回收: 无对象,classloader已回收,该类对应的class文件没有被引用,且不可通过反射获取该方法

16. TTL:

  • Time To Live,指定IP包被路由器丢弃之前允许通过的最大网段数量。《TCP/IP详解卷I》路由器会丢弃ttl为0或1的数据包

17. string类 能否继承?如果写一个类 不能被继承 final外 还有什么方法

  • 不能,因为是final的。
  • 还可以把构造函数私有化,单例模式

18. 链表的倒转,不倒转可以递归

19. session和cookie的区别:

  • session放在服务器,cookie放在客户端

  • session不区分路径,在同一个用户在访问一个网站期间,所有的session在任何一个地方都可以访问到。而cookie中如果设置了路径参数,那么同一个网站中不同路径下的cookie互相是访问不到的。也就是说,同一个用户的cookie,他换了浏览器,就访问不到之前的那个不同牌子的浏览器的cookie了。

  • session中保存的是对象,cookie中保存的是字符串。

  • 由于采用服务器端保持状态的方案在客户端也需要保存一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上它还有其他选择【经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段】。

20. 单例模式线程安全

  • 静态变量new 对象,类加载时即生成,
  • 加锁:双重检测加锁 不能达到真正的线程安全,1.5之前主要是JIT编译器执行顺序问题.1.6之后可能是指令重排(volatile可解决?)
  • 使用私有的静态类来实现:

    public class Singleton
    {

    private static class SingletonHolder //私有静态类  
    {  
        public final static Singleton instance = new Singleton();  
    }  
    public static Singleton getInstance()  
        {  
     return SingletonHolder.instance;  
        }  
    }
    
  1. 枚举单例

21. 序列化接口

  • 对象持久化,transient:修饰变量,不序列化

22. 删除无头链表的某节点(编程之美3.4)

  • 将下一节点数据复制到该节点,删除下一节点而非该节点

23. JAVA多态

  • 动态绑定(后期绑定,运行时绑定,前期是编译时绑定)
  1. 指向之类对象的指针,调用子类对象的方法(如果已重写父类方法,否则默认调父类方法)