八种基本数据类型的大小, 以及他们的封装类
整数型: byte 1 个字节 -128~127 封装类: Byte
short 2 个字节 -32768~32767 Short
Int 4 个字节 -2147483648~2147483647 Integer
long 8 个字节 -2 的 63 方~ 2 的 63 次方 - 1 Long
浮点型: float 4 个字节 单精度 Float
Double 8 个字节 双精度 Double
布尔类型: boolean 4 个字节 true 或 false Boolean
字符类型: char 2 个字节 Character
引用数据类型:
分为 3 种, 类, 接口和数组
Switch 能否用 String 做参数
在 jdk7 以前, switch 只支持 byte,int,short,char 或者对应的包装类和枚举.
equals 和 == 的区别
a) 对象类型不同 equals 是超类 Object 的方法, 而 == 是操作符
b) 比较类型不同 equals 用来检测两个对象是否相同, 即两个对象的内容是否相等,== 比较引用数据类型和基本数据类型时具有不同的功能.== 比较的是变量 (栈) 内存中存放的对象的内存地址, 用来判断两个对象的地址是否相同, 即是否指向同一对象, 比较的是真正意义上的指针操作, 而 equals 用来比较的是两个对象的内容是否相同, 适用于所有对象.
c) 注意: 如果没有对该对象进行覆盖的话, 调用的仍然是超类 Object 的方法, 而 Object 中的 equals 方法返回的是 == 的判断.
自动拆装箱和常量池
a) Java 自动将原始数据类型值转换成对应的对象, 比如将 int 类型的变量转换成 Integer 类型, 自动装箱时调用 valueOf 将原始数据类型转换成对应的对象.
b) 反之, 将 Integer 对象装换成 int 类型值, 这个过程叫拆箱, 自动拆箱通过调用类似 intValue,doubleValue 这类的方法将对象转换成对应的原始数据类型.
c) Java 中的常量池, 实际上分为两种形态: 静态常量池和运行时常量池.
i. 静态常量池: 即.*class 文件中的常量池, class 文件中的常量池不仅仅包含字符串, 还包含类, 方法的信息, 占用 class 文件绝大部分空间.
ii. 而运行时常量池: 则是 jvm 虚拟机在完成类装载过程后, 将 class 文件中的常量池载入到内存中, 并保存在方法区中, 我们常说的常量池就是指方法区中的运行时常量池.
Object 中有哪些公用方法?
a) Clone: 实现对象的浅复制, 只有实现了 cloneable 接口才可以调用此方法, 否则会抛出 CloneNotSupportedException 异常.
b) Equals: 在 Object 中和 == 是一样的, 子类一般需要重写此方法.
c) Hashcode: 该方法用于哈希查找, 重写了 equals 方法一般都要重写 hashcode 方法, 这个方法在一些具有哈希功能的 collection 中用到.
d) getClass: 获得运行时的类型.
e) wait: 是当前线程等待该对象的锁, 当前线程必须是该对象的拥有者, 也就是说具有该对象的锁!
f) Notify: 唤醒在对象上等待的某个线程.
g) notifyAll: 唤醒该对象上等待的所有线程.
h) toString: 转换成字符串, 一般子类都要重写此方法, 否则打印句柄.
Java 的四种引用, 强弱软虚.
a) 强引用: 最常见, 把一个对象赋给引用数据类型则为强引用. 如果内存中不足, java 虚拟机将会跑出 OutOfMemoryError 错误, 从而将程序异常停止强引用的对象是不可以 gc 回收的, 不可以随意回收具有强引用的对象来解决内存不足的问题. 在 java 中, 强引用是一种默认的状态, 除非 Java 虚拟机停止工作.
b) 软引用: 如果一个对象具有软引用, 内存空间足够, 垃圾回收就不会回收它, 如果内存空间不足了, 就会回收这些对象的内存. 只要垃圾回收器没有回收它, 该对象就可以被程序继续使用. 软引用用来实现内存敏感的高速缓存, 比如网页缓存或图片缓存, 使用软引用能防止内存泄露, 增强程序的健壮性.
c) 弱引用: 用来描述非必需对象的, 当 jvm 进行垃圾回收的时候, 无论内存是否充足, 都会回收被弱引用关联的对象.
d) 虚引用: 他不影响对象的生命周期, 如果一个对象与虚引用关联, 则跟没有与之关联一样, 在任何时候都可能被垃圾回收器回收.
hashcode 的作用
比较两个对象是否相等, 重写的 equals 方法一般比较全面, 比较复杂, 效率比较低, 而采用 hashcode 方法进行对比, 只需要生成一个 hashcode 进行比较就可以了!
Hashmap 中的 hashcode 的作用
a) Hashcode 的存'用于查找的快捷性, 如 hashtable,hashmap 等, hashcode 是在散列结构中确定对象的地址.
b) 如果两个对象相同, 就是适用 equals 方法, 那么这两个对象的 hashcode 一定要相同.
c) 如果对象的 equals 方法被重写, 那么对象的 hashcode 也尽量重写, 并且产生 hashcode 使用的对象, 一定要和 equals 放法使用的一致, 否则会违反上面的第二点.
d) 两个对象的 hashcode 相同, 并不代表这两个对象就相同, 也就是不一定适用 equals 方法, 只能说明这两个对象在散列存储结构中, 如 hashtable, 他们 "存放在同一个篮子里".
为什么重载 hashcode 方法?
一般不需要重载 hashcode 方法, 只有当类放在 hshtable,hashmap,hashset 等 hash 结构的集合时, 才会重载 hashcode. 就 hashmap 来说, 好比 hashmap 就是一个大内存块, 里面有许多小内存块, 小内存里面就是一系列的对象, 可以利用 hashcode 查找小内存块,, 所以当 equals 相等时, hashcode 必需相等, 而且如果是 Object 对象, 必须重载 hashcode 和 equals 方法.
Arraylist,linkedlist 和 vector 的区别?
a) Arraylist: 底层数据结构是数组, 查询快, 增删慢, 线程不安全.
b) Liskedlist; 底层数据结构是链表, 查询慢, 增删块, 线程不安全.
c) Vector: 底层是数组, 查询慢, 增删慢, 线程安全.
String,stringbuffer 与 stringbulder 的区别?
a) String 是不可变的对象, 因此每次对 string 类型进行改变的时候, 就等于生成了一个新的对象, 然后蒋指针指向一个新的 string 的对象, 因此经常改变内容的字符串最好不用 string, 因为每次生成对象都会对系统性能产生影响, 特别是当内存中无引用对象过多时, jvm 的 gc 就会开始工作, 那么速度一定会非常慢.
b) 而 stringbuffer 结果就完成不一样了, 每次结果都会对 stringbuffer 本省进行操作, 而不是生成新的对象, 再改变对象的引用. 是线程安全的.
c) Stringbuildere 是 jdk5 以后新增的, 其用法和 stringbuffer 完全一致, 但它是线程不安全的, 在单线程中是最佳的, 因为不需要维护线程的安全.
Map,set,list,queue,stack 的特点与用法.
a) Map 是键值对, 键 key 是唯一不能重复的, 一个键对应一个值, 值可以重复, treemap 可以保证顺序, hashmap 不保证顺序, 即是无序的, map 可以把 key 和 value 单独抽取出来, 其中 keyset()方法可以将所存的 key 抽取成一个 set. 而 valuses 方法可以将 map 中所有的 value 抽取成一个集合.
b) Set: 不包含重复元素, 且最多包含一个 null 元素, 只能用 iterater 实现单向遍历, set 没有同步方法.
c) List: 有序的可重复集合, 可以在任何位置增加和删除元素. 用 Iterator 实现单向遍历, 也可以用 listIterator 实现是双向遍历.
d) Queue: 遵从先进先出原则, 使用时尽量避免 add()和 remove()方法, 而只是使用 offer()来添加元素, 使用 poll 来移除元素, 它的优点是可以通过返回值来判断是否成功, LinkedList 实现 Queue 接口, Queue 通常不允许插入 null 元素.
e) Stack: 遵从先进后出原则, stack 继承自 vector, 它通过五个操作对类 vector 进行扩展, 允许将向量视为堆栈, 它提供 push 和 pop 操作, 以及取堆栈顶点的 peek()方法, 测试堆栈是否为空的 empty()方法等.
f) 用法: 如果涉及堆栈, 队列等操作, 建议使用 list, 对于快速插入和删除元素, 建议使用 linkedlist, 如果, 快速随机访问元素, 建议使用 ArrayList.
Hashmap 和 hashtable 的区别?
a) 都是 map 接口的实现类, 都是基于 hash 表的实现类.
b) Hashmap 集合线程不安全的类, 不同步, 执行效率高, 允许键和值是 null.
c) Hashtable 集合是线程安全的类, 同步, 执行效率低, 不允许键和值为 null.
Jdk7 和 jdk8 中的 hashmap 的实现.
a) Jdk7:hashmap 底层维护一个数组, 数组中的每一项都是一个 entry, 我们向 hashmap 中放置的对象实际上存储在该数组中, map 中的 key 和 value 则以 entry 的形式存放在数组中, 而这个 key 放在数组的哪一个位置上, 是通过 key 的 hashcode 来计算的.
b) Jdk8: 采用 (位桶 + 链表) 红黑树的方式, 也是非线程安全的.
Hashmap 和 hashConcurrentHashmap 的区别, hashmap 的底层源码.
Hashmap 是线程非安全的, 效率比较高, hashtable 和 ConcurrentHashmap 是线程安全的, 效率比 hashmap 差一点, 但 ConcurrentHashmap 采用了更高级的分段锁机制, 具体可以理解为把 hashmap 拆分为 n 个小的 hashtable, 根据 key.Hashcode()来决定把 key 放到哪个 hashtable 中, 在 concurrenthashmap 中, 就是把 map 分为 n 个 segment,put 和 get 时, 都是 key.hashcode()算出放到哪个 segment 中.
接口和继承的区别? 接口内可以定义常量吗? 继承可以继承父类的那些东西?
a) 区别:
i. 标识符不同, interface 和 extends
ii. 接口支持多继承, 而不支持继承的继承
iii. 接口中只能定义全局变量和抽象变量, 而继承中可以定义属性, 方法, 常量, 变量等.
iv. 某接口被实现, 在类中一定要实现接口所有的方法, 而继承只需要用哪一个就调用哪一个.
b) 接口不可以定义常量.
c) 继承可以继承父类所有的东西(成员方法, 成员变量, 包括私有).
如何修改父类中以 private 关键字修饰的变量?
如果父类中有 public 的 set 方法, 就可以通过 set 方法修改父类中以 private 修改的变量.
Java 中 public,private ,protect,default 的区别?
a) Public:java 中访问限制最宽的修饰符, 即公共的, 被修饰的类, 属性, 方法允许跨类访问, 甚至可以跨包访问.
b) Private: 是 java 中访问限制最窄的修饰符, 被 private 修饰的类, 属性, 方法只能被本类的对象进行访问, 其子类不能访问, 更不允许跨包访问.
c) Protec: 介于 public 和 private 之间的一种访问修饰符, 一般称受保护的, 被其修饰的类, 方法, 属性只能被本类和子类进行访问, 即使子类不在同一个包下.
d) Default: 意为默认的, 即不加修饰符, 该模式下只能同一个包下进行访问.
数据库锁的问题? 如何上锁? 是不是行锁?
a) 当多个用户同时对数据库进行操作时, 会带来数据不一致的问题, 所以锁主要是用于多用户环境下保证数据库完整性和一致性.
b) 锁分类: 从数据库系统来看: 排它锁, 悲观锁, 更新锁
从程序员角度来看: 一种是乐观锁, 一种是悲观锁.
i. 悲观锁: 很悲观, 每次去拿数据的时候, 都以为别人会修改, 所以在每次拿数据的时候, 都会上锁, 这样别人拿这个数据就会 block, 直到它合锁. 具有强烈的排他性和独占性, 悲观锁的实现依靠数据库提供的机制, 也只有数据库底层提供的机制才能保证数据访问的排他性. 传统的关系型数据库用到了很多这同样的机制, 比如行锁, 表锁, 读锁, 写锁等, 都是在操作前加上锁.
ii. 乐观锁: 很乐观, 每次去拿数据的时候都认为别人不会修改, 所以不会上锁, 但是在更新的时候会判断一下在此期间别人有没有去更新这个数据, 可以使用版本号等机制. 悲观锁适用于多读的应用类型, 这样可以提高吞吐量, 像数据库如果提供类似于 write-condition 机制的其实都是提供的乐观锁.
c) 按作用性质分:
i. 共享锁: 也叫读锁, 用于所有只读操作, 不能同时增删改, 可以查.
例如: select * from 表 lock in share mode;
ii. 排它锁: 也叫读锁, 表示对数据进行写操作, 一个事务对象施加了排它锁, 其他事务就不能加锁了.
例如: 查询时加排它锁, 别人不能加共享锁和排它锁.
Select * from 表 for update;
仅允许一个事务封锁此表, 其他事务必须等到此锁被释放才能访问.
排它锁 (x 锁) 一直到事务结束才能释放.
iii. 更新锁: 允许其他事务读, 但不允许在施加 x 锁和 u 锁, 当要被读取的对象要被更新的时候, 则升级为 x 锁, 防止死锁, 如果一个数据在修改前直接申请更新锁, 在修改时再升级为排它锁, 就可以避免死锁.
d) 按范围分:
i. 行锁: 锁的范围是行级别, 数据能够确定哪些行需要锁的情况下使用行锁(inodb), 如果在不知道会影响到哪些数据的时候就会使用表锁
例如: 一个用户表有主键 id 和 birthday.
Update ...where id=? 行锁
Update ... where birthday=? 表锁
ii. 表锁: 锁的范围是整张表. MyISAM
22. 事务的隔离性
a) 隔离性级别越低, 并发性越好, 但数据库的一致性就越差.
隔离级别越高, 并发性越差, 但数据库的一致性高.
b) 由低到高
读未提交<读提交<可重复读(默认)<序列化读
c) 错误的级别由低到高:
脏读, 不可重复读, 幻读
脏读: 两个事物, 一个事务先修改, 另一个事务读, 结果是修改前的结果.
不可重复读: 两个事物, 一个先读是一个结果, 一个后修改, 再读, 又是一个结果.
幻读: 第一个事务表中有 10,20,30,40 几个部门, 第二个事务插入表中 50 的部门, 然后提交, 第一个事务插入 50 部门, 主键冲突.
23. 能否用一个 sql 语句解决库存判断问题(非查询语句).
用 if 语句: if(exper1,exper2,exper3)
如果 exper1 的值是 true, 则返回是 exper2 的值, 如果 exper1 的值是 false, 则返回 exper3 的值.
例如: id name number
1 苹果 300
2 梨 100
Update fruit set number=if(number>200,number,0)where if='1';
即如果苹果的数量大于 200, 就不变, 否则, number 改为 0, 即就可以判断内存是否充足.
24. 红黑树
a) 特性:
i. 每个节点都是黑色或者红色.
ii. 根节点是黑色.
iii. 定义 null 为黑色.
iv. 如果某个子节点是红色, 那么它的两个儿子都是黑色, 且父节点一定是黑色.
v. 对于任意节点, 它到叶子节点的每一条路径都包含相同数目的黑色节点
性质 5 称之为黑高.
b) 相对平衡:
i. 若 H(left)>=H(right), 则 H(left)=2*H(right)+1
ii. 但 BH(left)=BH(right),H(left)<H(right)同理.
c) 在调整节点 p 之前, 必需保证 p 的左子树 left, 右子树 right 都已经是 rbt.
i. 多个子问题成立 ->某个总问题成立
ii. 插入调整: 删除调整均是由底向上
d) Rbt 的插入调整(默认是红色)
i. 无需调整
X 为根节点, 将 x 由红染黑
父亲节点是黑色
ii. 仅仅考虑父亲节点 p 是红色, 由于性质 4, 爷爷节点必定是黑色, 分为 3 中:
1. Case1:y 为黑色, x 可左可右; p,y 染黑, g 染红; x 回溯至 g
2. Case2:y 为黑色, x 为右孩子, 左旋 p,x 指向 p, 转为 case3
3. Case3:y 为黑色, x 为左孩子, p 染黑, g 染红, 右旋 g 结束.
Rbt 的插入调整最多 2 次
右旋转: 逆时针旋转两个节点, 使父亲节点被右孩子取代, 而自己变成左孩子.
左孩子: 顺时针旋转两个子节点, 使父亲节点被左孩子取代, 自己变成右孩子.
25.Session 是什么? 和 cookie 的区别?
a) Cookie 通过客户端记录信息确认身份, session 是通过服务端的信息确认身份.
b) 客户端浏览器访问服务器的时候, 服务端把客户端的信息以某种形式记录在服务器上, 这就是 session, 用户与服务器建立连接的同时, 服务器自动分配一个 sessionid.
c) 区别: cookie 不 *** 全, 别人可以分析本地存在的 cookie 并进行 cookie 欺骗, 考虑到安全应当使用 session.
有哪些排序算法? 说一下堆排序? 时间复杂度是多少?
a) 直接插入排序: 第一个元素已经排序, 第二个与第一个元素进行比较, 第一个大, 第一个则与第二个交换位置, 第三个分别于第一个和第二个比较, 以此类推.
时间复杂度: O(n*n)
b) 希尔排序: 按步长 grep 进行分组, 然后将每组元素利用直接插入排序的方法进行排序; 每一次结束后再将步长 grep 减半, 循环上述操作, 直到步长 grep=1, 利用直接插入排序, 完成排序.
时间复杂度: O(log n)
c) 简单选择排序: 首先在未排序序列中找到最小 (或最大) 的元素, 放在排序序列的起始位置, 然后再从未排序序列中找到最小 (最大) 的元素, 放在已排序序列的后面.
时间复杂度: O(n*n)
d) 堆排序: 堆排序过程就是将待排序序列构造成一个堆, 选出堆中最大的移走, 再把剩下的整成堆, 找出最大的在移走, 重复直至有序.
i. 每次将根节点与左右节点最大的进行交换, 直到根节点最大, 然后把根节点放在最后一个位置, 然后再次执行循环, 找到最大值放在长度 - 1 的位置.
ii. 时间复杂度: O(n log n)
e) 冒泡排序: 每次比较两个元素, 把小的放在前面.
时间复杂度: O(n*n)
f) 快速排序: 把一个序列分为两个子序列, 步骤可分为:
i. 从数列中选出一个元素, 作为基准.
ii. 重新排序数列, 所有比基准序列小的元素放在基准前面, 所有比基准大的元素放在基准后面, 相同的放在任意一边, 在这个分区结束后, 该基准处于中间位置.
iii. 递归将小于基准的子序列和大于基准的子序列排序.
iv. 即: 先对大序列进行排序, 大序列分为两个子序列, 然后递归调用方法对这两个序列进行排序.
g) 归并排序: 将两个或两个以上的有序表合并成一个新的有序表, 即把待排序序列分为若干个子序列, 每个子序列都是有序的, 然后再把整个序列合并成整体有序序列.
时间复杂度: O(nlogn)
h) 基数排序: 将所有待比较的数(正整数统一为同样的数位长度), 数位数不足的前面补 0, 然后从低位开始, 依次进行一次排序, 这个序列从最低位排序一直到最高位排序完成以后, 数列将变成一个有序序列.
时间复杂度: O(d*(n+r))
D 为位数, r 为基数, n 为数据个数
27.Statement 和 preparestatement 的区别?
a) 代码的可读性和可维护性 preparestatement 更好.
b) Preparestatement 尽最大可能提高性能.
c) 提高安全性, preparestatement 防止 sql 注入.
28.NIO 和 IO 到底有什么区别? 有什么关系?
a) NIO 是以块的方式处理数据, 但是 IO 是以最基础的字节流的形式去写入和读出的, 肯定 NIO 的效率比 IO 的效率高出好多.
b) NIO 不是和 IO 一样用 Ouputstream 和 Inputstream 输入流形式来处理数据, 但是基于这种流的形式, 而是采用通道和缓冲流的形式来处理数据的.
c) NIO 通道可以是双向的, IO 中的流只能是单向的.
d) 还有就是 NIO 的缓冲区 (其实也是一个字符数组) 还可以进行分片, 可以建立只读缓冲区, 直接缓冲区和间接缓冲区, 只读缓冲区很明显就字面意思, 直接缓冲区是为了加快 I/O 速度, 而以一种特殊的方式分配其内存的缓冲区.
29. 数据库索引的分类, 索引底层的实现, 说一下 b + 树, b - 树?
a) 索引的作用:
i. 提高查询速度
ii. 确保数据的唯一性
iii. 可以加快表与表之间的连接, 实现表和表之间的完整性.
iv. 使用分组和排序字句进行数据检查时, 可以减少分组和排序的时间.
v. 全文检索字段进行搜索优化.
b) 分类;
i. 主键索引(PRIMAY_KEY): 确保数据记录的唯一性, 一个表只有一个.
ii. 唯一索引(UNIQUE): 避免一个表中某些数据列中的值重复. 可以有多个.
iii. 常规索引(INDEX): 快速定位特定数据.
iv. 全文索引(FULLTEXT): 快速定位特定数据, 只能用于 MyISAM 类型的数据表.
c) 索引底层实现: 把平衡树当做数据表默认的索引数据结构, 平衡树也就你, b+tree 或者 b-tree.
d) B-tree: 适用于外查找的树, 是平衡树的多叉树.
i. 一个 m 阶 b 树是一颗平衡的 m 路搜索树, 它或者是空树, 或者满足下列性质:
1. 定义任意非叶子节点最多有 m 个儿子, 且 m>=2;
2. 根节点的儿子数[2,m];
3. 除根节点以外的叶子节点的儿子数{m/2,m};
4. 每个节点存放 m/2-1(向上取整)和至多 m-1 个关键字(至少 2 个).
5. 非叶子节点的关键字个数 = 指向儿子的指针个数 - 1;
6. 非叶子节点的关键字: k[1],k{2}...k[m-1], 且 k{i}<k{i+1}.
7. 非叶子节点的指针: p{1} ,p{2} ,p{3}, p{4} ...p{m}, 其中 p[1] 指向小于 k[1]的子树, p[m]指向关键字属于 k{i}和 k{i+1}之间的子树.
8. 所有子树节点位于同一层.
ii. B - 树的特性:
关键字集合分布在整棵树中.
任何一个关键字出现且只出现一个节点中.
搜索可能在非叶子节点结束.
其搜索性能等价于在在关键字全集中做一次二分查找.
自动层次控制.
e) B + 树:
i. B + 树的定义:
1. 其定义与 b - 树基本相同, 除了:
2. 非叶子节点的子树指针与关键字个数相同.
3. 非叶子节点的子树指针 p[i], 指向关键字属于 k[i],k[i+1]的子树.
4. 为所有关键字增加一个键指针.
5. 所有关键字在叶子节点出现.
ii. B + 树的特性:
1. 所有关键字都出现叶子节点的链表中 (稠密索引) 且链表中的关键字恰好是有序的.
2. 不可能在非叶子节点命中.
3. 非叶子节点相当于叶子节点的索引 (稀疏索引), 叶子节点相当于存储数据(关键字) 的数据层.
4. 更适合文件索引系统.
来源: http://www.bubuko.com/infodetail-3046323.html