1、封装、继承、多态
继承:基于某个父类扩展出一个新的子类,子类可以继承父类原有的属性和方法,也可以增加父类中不具备的属性和方法,或者直接重写父类中的某些方法。
封装:将对象的属性和行为封装起来,对客户隐藏其实现细节。保证了类内部数据结构的完整性。
多态:多态使程序具有良好的扩展性,程序可以对所有的类进行通用的处理。一个接口,多种实现是多态的体现,或者父类的引用变量可以指向子类的实例。多态可分为两种类型:编译时多态(方法的重载)和运行时多态(继承时方法的重写)。
2、数据库索引的原理
聚集索引
如果给表添加了主键,表中数据存储的结构由排列结构变为树状结构(平衡树),整个表变成了一个索引,也就是聚集索引。
假如表中有1万条数据,如果按照常规去匹配,最坏情况下要匹配1万次才能得到结果,对查询性能有非常大的提升。
如果将表转换成平衡树,假设树有10层,则只需要10次IO开销即可查到所需数据。
索引能让查询速度提升,但是会使写入速度下降。平衡树要维持正确的状态,增删改都会改变平衡树各节点中的索引数据内容,数据库必须重新梳理树结构,这会带来不小的性能开销。
非聚集索引
非聚集索引和聚集索引一样,都采用平衡树作为数据结构,索引树中各节点的值来自表中的索引字段。
每次给字段建一个新索引,字段中的数据就会被复制一份出来,用于生成索引。因此,给表添加索引,会增加表的体积,占用磁盘存储空间。
非聚集索引和聚集索引的区别在于,通过聚集索引可以查到需要查找的数据,而通过非聚集索引可以查到记录对应的主键值,再使用主键的值通过聚集索引查找到需要的数据。
覆盖索引--联合索引(复合索引)
从非聚集索引中就可以得到查询的记录,而不需要查询聚集索引中的记录,这样会减少IO操作。
联合索引是指对表中多个字段进行索引。规定从左到右使用索引字段,一个查询只使用索引的一部分,使用原则是最左优先,例如联合索引包含(A、B、C)三个字段,只支持A、AB、ABC三种组合进行查找,不支持B、C、BC组合。
平衡树
即平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
平衡二叉树的常用算法有红黑树、AVL、Treap、伸展树、SBT等。
3、索引的类型(Mysql)
普通索引(normal):最基本的索引,它没有任何限制。
唯一索引(unique):索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一。
全文索引(full text):主要用来查找文本中的关键字,而不是直接与索引中的值相比较,只有char、varchar,text 列上可以创建全文索引。解决模糊查询效率低的问题。
4、矩阵(二维数组)填数字,每一行各列数据从小到大排列,每行数据的和从小到大排列
基本思路:先将数字放入一个临时集合,当集合中元素数量等于矩阵行数和列数的乘积时,先给集合排序,再将集合数据放入矩阵,并清除临时集合中的数据。具体实现代码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class MatrixAddAndSort {
public static void main(String[] args) {
testMatrixAddAndSort();
}
public static void testMatrixAddAndSort(){
int matrixSize = 5;
int templen = matrixSize*matrixSize;
int[][] matrix = new int[matrixSize][matrixSize];
List<Integer> temp = new ArrayList<>(templen);
Random random = new Random();
for (int i = 0; i < 100; i++) {
temp.add(random.nextInt(100));
if((temp.size() % templen) == 0){
//排序
Collections.sort(temp);
//放入二维数组
for (int k = 0; k < matrix.length; k++) {//行
int rowStart = matrixSize * k;
for (int j = 0; j < matrix[k].length; j++) {//列
matrix[k][j] = temp.get(rowStart+j);
}
}
//打印二维数组
for (int k = 0; k < matrix.length; k++) {//行
for (int j = 0; j < matrix[k].length; j++) {//列
System.out.print(matrix[k][j] + " ");
}
System.out.println();
}
//清空临时list
temp.clear();
System.out.println("-------------------");
}
}
}
}
5、读取数据库一张表中所有数据,多线程查询出,数据不能重复
基本思路:没整明白面试官真正要问的要点,好像意思是让我确定每个线程读取数据的起始行,这样的话就和分页的起始位置有点像了。具体实现代码如下:
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.springframework.jdbc.core.JdbcTemplate;
import com.alibaba.druid.pool.DruidDataSource;
public class MultThreadReadDataTable {
private final static String driverClass = "com.mysql.jdbc.Driver";
private final static String jdbcUrl = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8";
private final static String username = "root";
private final static String password = "root";
public static JdbcTemplate getJdbcTemplate(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driverClass);
ds.setUrl(jdbcUrl);
ds.setUsername(username);
ds.setPassword(password);
JdbcTemplate jt = new JdbcTemplate(ds);
return jt;
}
public static void main(String[] args) {
JdbcTemplate jt = getJdbcTemplate();
//获取表中总记录数
List<Map<String, Object>> list = jt.queryForList("select count(id) as num from data_search");
int maxNum = Integer.parseInt(list.get(0).get("num").toString());
//线程池中线程数量
int fixedNum = 10;
//每个线程查询记录条数
int pageSize = 10;
//总页数
int totalPage = 0;
if(maxNum % pageSize == 0){
totalPage = maxNum / pageSize;
}else{
totalPage = maxNum / pageSize + 1;
}
ExecutorService es = Executors.newFixedThreadPool(fixedNum);
for (int i = 0; i < totalPage; i++) {
final int count = i;
es.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(50);
List<Map<String, Object>> list = jt.queryForList("select * from data_search limit " + pageSize*count + "," + pageSize);
for (Map<String, Object> map : list) {
System.out.println(Thread.currentThread().getName() + ": " + map.get("name"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
es.shutdown();
}
}