社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
2020年3月份一些中小型互联网或计算机软件公司的社招题目,我会尽最大努力确保答案的正确性,但是我也才疏学浅,如果有错误或者遗漏的地方,欢迎指出。持续更新中……。
类型 | 字节数 | 位数 | 取值范围 |
---|---|---|---|
byte | 1 | 8 | -27 ~ 27-1 |
short | 2 | 16 | -215 ~ 215-1 |
char | 2 | 16 | |
int | 4 | 32 | -231 ~ 231-1 |
long | 8 | 64 | -263 ~ 263-1 |
float | 4 | 32 | 3.402823e+38 ~ 1.401298e-45 |
double | 8 | 64 | 1.797693e+308 ~ 4.9000000e-324 |
boolean | 1(前7位是0) | 1 | 0或者1 |
float
表示的 范围更大
。float
和 int
都是4
个字节,而 float
还要表示小数,为什么 float
表示的数字范围大?
int
底层使用的是补码的方式表示一个数:1 位符号位 + 31 位二进制数float
底层使用的是IEEE 754
浮点单精度数字格式,简单来说就是用指数的形式去表示一个数:1 位符号位 + 8 位指数 + 23位尾数Integer
是int
的包装类,int
则是java
的一种基本数据类型Integer
变量必须实例化后才能使用,而int
变量不需要Integer
实际是对象的引用,当new
一个Integer
时,实际上是生成一个指针指向此对象;而int
则是直接存储数据值Integer
的默认值是null
,int
的默认值是0
final
方法abstract
方法==
号在比较基本数据类型时比较的是值,而在比较两个对象时比较的是两个对象的地址值equals()
方法存在于Object
类中,其底层依赖的是==
号,如果类没有重写Object
中的equals()
方法的类中,则调用equals()
方法其实和使用==
号的效果一样相同点:
不同点:
public abstract
修饰),常量(public static final
修饰),在JDK8中,接口还可以定义static
静态方法和default
方法;而抽象类可以有普通类的所有内容和抽象方法。String
的底层使用的是char
数组。这个char
数组和String
这个类都是final
修饰的,所以不可变。
String
是只读字符串,它并不是基本数据类型,而是一个对象。从底层源码来看是一个final
类型的字符数组,所引用的字符串不能被改变,一经定义,无法再增删改。每次对String
的操作都会生成新的String
对象。
String
的每次+
操作 : 隐式在堆上new
了一个跟原字符串相同的StringBuilder
对象,再调用append
方法 拼接+
后面的字符,最后再调用toString
方法,返回String
对象
StringBuffer
和StringBuilder
他们两都继承了AbstractStringBuilder
抽象类,从AbstractStringBuilder
抽象类中我们可以看到他们的底层都是可变的字符数组,所以在进行频繁的字符串操作时,建议使用StringBuffer
和StringBuilder
来进行操作。
另外StringBuffer
对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder
并没有对方法进行加同步锁,所以是非线程安全的
使用的是 SimpleDateFormat
。
//使用SimpleDateFormat类,在构造方法中指定日期的格式:y年,M月,d日,H小时,m分钟,s秒
SimpleDateFormat sdf = new SimpleDateFormat("yyy y-MM-dd HH:mm:ss");
//调用SimpleDateFormat实例方法format(Date)可以把日期转换为字符串
String text = sdf.format(date);
text = "2068年5月12日 8:28:58";
//先创建SimpleDateFormat对象, 指定的格式串要与字符串匹配
SimpleDateFormat anotherSdf = new SimpleDateFormat("yyyy年M月dd日 H:mm:ss");
//调用SimpleDateFormat的实例方法parse(String)可以把字符串转换为日期对象, 如果格式串与字符串不匹配就会产生异常
date2 = anotherSdf.parse(text);
节点流(介质流):
父类 | InputStream(输入流、字节流) | OutputStream(输出流、字节流) | Reader(输入流、字符流) | Writer(输出流、字符流) |
---|---|---|---|---|
文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
字符串 | StringReader | StringWriter | ||
管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
处理流(装饰流):
父类 | InputStream(输入流、字节流) | OutputStream(输出流、字节流) | Reader(输入流、字符流) | Writer(输出流、字符流) |
---|---|---|---|---|
转换流 | InputStreamReader | OutputStreamWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
数据流 | DataInputStream | DataOutputStream | ||
对象流 | ObjectInputStream | ObjectOutputStream | ||
打印流 | PrintStream | PrintWriter |
File 对象可以表示文件或目录:
//第一个参数为父路径字符串,第二个参数为子路径名字
File f = new File("D:", "test");
f.mkdir(); //创建文件夹, 如果已存在重名的文件(夹),创建失败
f.createNewFile(); //创建文件
f.delete(); //删除文件
开闭原则:
开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类。
里氏替换原则:
所有引用基类的地方必须能透明地使用其子类的对象,也就是说子类可以扩展父类的功能,但不能改变父类原有的功能
里氏替换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏替换原则是对实现抽象化的具体步骤的规范。
依赖倒转原则:
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。简单的说就是尽量面向接口编程.
接口隔离原则:
客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。接口最小化,过于臃肿的接口依据功能,可以将其拆分为多个接口。
迪米特法则,又称最少知道原则:
一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。简单的理解就是高内聚,低耦合,一个类尽量减少对其他对象的依赖。
单一职责原则:
单一职责原则通俗来说就是一个类只负责一项职责。如果一个类有多个职责,这些职责就耦合在了一起。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起会影响复用性。
jdk
动态代理和cglib
动态代理。存储特点:有序,可重复。存储顺序与添加顺序一致,可以存储重复的数据
ArrayList
Vector
ArrayList
不是线程安全的LinkedList
存储特点:无序,不可重复。存储顺序与添加顺序可能不一样;不能存储重复(通过equals()
方法来判断)的数据
HashSet
HashMap
HashSet
添加元素就是把元素作为键添加到底层的HashMap
中TreeSet
TreeSet
实现了SortedSet
接口,可以根据元素自然排序,要求集合中的元素必须是可比较的(Comparator
与Comparable
)TreeSet
底层是TreeMap
TreeSet
添加元素就是把元素作为键添加到底层的TreeMap
中Map
是按<键,值>
对的形式存储数据,Map
的key
不允许重复
HashMap
null
,线程不安全8
时,链表转换为红黑树;插入时,新增的结点插入到链表的尾部16
0.75
,当键值对的数量 > 容量*加载因子时,按2倍大小扩容HashMap
会把初始化容量自动调整为2
的幂次方HashMap
是先插入数据再进行扩容的,但是如果是刚刚初始化容器的时候是先扩容再插入数据。CurrentHashMap
CAS+Synchronized
来保证线程安全HashTable
key
还是value
都不能为null
,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable
,效率低,ConcurrentHashMap做了相关优化11
,扩容:2倍+1
两种方式遍历:使用EntrySet
遍历;使用KeySet
遍历
比如说读取系统参数,在服务之间传递一些键值对时使用。
首先根据键的哈希码,经过hash
函数计算hash
值,然后根据hash
值计算数组下标,当下标相同时,就会出现hash
碰撞。
HashMap
采用链表法,将数组下标相同的键值对用链表存起来,解决了hash
碰撞。
HashMap
相较来说写入慢,读取快,上面介绍过了,就不赘述了;LinkedHashMap
它内部有一个链表,保持Key
插入的顺序,写入快,读取慢。迭代的时候,也是按照插入顺序迭代;TreeMap
可以根据Key
的自然顺序(如整数从小到大)或者自己定义的比较器,实现 Key
的有序排列。不能使用for
或者foreach
循环加list.remove()
进行删除,因为使用remove
方法删除后,集合的长度会变,导致一些元素被漏掉。
使用外部迭代器删除集合中的所有奇数:
List<Integer> list = new ArrayList<>();
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer i = iterator.next();
if (i % 2 == 1) {
iterator.remove();
}
}
使用内部迭代器(流),删除集合中的所有奇数:
List<Integer> list = new ArrayList<>();
list = list.stream().
filter(x -> x % 2 == 0).
collect(Collectors.toList());
Thread
类,重写run
方法(其实Thread类本身也实现了Runnable接口)Runnable
接口,重写run
方法Callable
接口,重写call
方法(有返回值)Callable
接口的任务线程能返回执行结果;而实现Runnable
接口的任务线程不能返回结果;Callable
接口的call()
方法允许抛出异常;而Runnable
接口的run()
方法的异常只能在内部消化,不能继续上抛;
Callable
接口支持返回执行结果,此时需要调用FutureTask.get()
方法实现,此方法会阻塞主线程直到获取结果;当不调用此方法时,主线程不会阻塞!
start()
方法来启动线程,而启动后的线程运行的是run()
方法中的代码。run()
方法当作普通方法的方式调用时,并不会开启新的线程。最常用的三个参数:
corePoolSize
:核心线程数queueCapacity
:任务队列容量(阻塞队列)maxPoolSize
:最大线程数三个参数的作用:
五种线程池:
ExecutorService threadPool = null;
threadPool = Executors.newCachedThreadPool();//有缓冲的线程池,线程数 JVM 控制
threadPool = Executors.newFixedThreadPool(3);//固定大小的线程池
threadPool = Executors.newScheduledThreadPool(2);//一个能实现定时、周期性任务的线程池
threadPool = Executors.newSingleThreadExecutor();//单线程的线程池,只有一个线程在工作
threadPool = new ThreadPoolExecutor();//默认线程池,可控制参数比较多
四种拒绝策略:
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();//默认,队列满了丢任务抛出异常
rejected = new ThreadPoolExecutor.DiscardPolicy();//队列满了丢任务不异常
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务
三种阻塞队列:
BlockingQueue<Runnable> workQueue = null;
workQueue = new ArrayBlockingQueue<>(5);//基于数组的先进先出队列,有界
workQueue = new LinkedBlockingQueue<>();//基于链表的先进先出队列,无界
workQueue = new SynchronousQueue<>();//无缓冲的等待队列,无界
利用Java自带工具JConsole
Java线程死锁查看分析方法
当一个变量定义为volatile
后,它将具备两种特性:1. 可见性,2. 禁止指令重排序。
可见性:编译器为了加快程序运行速度,对一些变量的写操作会现在寄存器或CPU缓存上进行,最后写入内存。而在这个过程中,变量的新值对其它线程是不可见的。当对volatile
标记的变量进行修改时,先当前处理器缓存行的数据写回到系统内存,然后这个写回内存的操作会使其他CPU里缓存了该内存地址的数据无效。
处理器使用嗅探技术保证它的内部缓存、系统内存和其他处理器的缓存的数据在总线上保持一致。如果一个正在共享的状态的地址被嗅探到其他处理器打算写内存地址,那么正在嗅探的处理器将使它的缓存行无效,在下次访问相同内存地址时,强制执行缓存行填充。
NEW
:新建状态,创建了一个线程对象RUNNABLE
:可以运行状态,线程调用了start()
方法。BLOCKED
:阻塞状态,遇到了阻塞事件,或者等待锁对象.WAITING
:等待状态。wait()
,join()
TIMED_WAITING
:等待状态,sleep()
TERMINATED
:终止状态where
及 order by
涉及的列上建立索引select * from t
,用具体的字段列表代替“*
”,不要返回用不到的任何字段。where
子句中使用!=
或<>
操作符,否则将引擎放弃使用索引而进行全表扫描,where
子句中对字段进行 null
值判断,否则将导致引擎放弃使用索引而进行全表扫描。可以在null
上设置默认值,确保表中没有null
值。in
和 not in
也要慎用,否则会导致全表扫描。对于连续的数值,能用 between
就不要用 in
了。%
"开头,会导致全表扫描索引(Index)是帮助MySQL高效获取数据的数据结构,可以理解为一本字典的目录,提高程序的检索 和查询效率
主键索引:数据列不允许重复,不允许为NULL,一个表只能有一个主键。
唯一索引:数据列不允许重复,允许为NULL值,一个表允许多个列创建唯一索引。
#创建唯一索引
ALTER TABLE table_name ADD UNIQUE (column);
#创建唯一组合索引
ALTER TABLE table_name ADD UNIQUE (column1,column2);
普通索引:基本的索引类型,没有唯一性的限制,允许为NULL值。
#创建普通索引
ALTER TABLE table_name ADD INDEX index_name (column);
#创建组合索引
ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3);
全文索引:是目前搜索引擎使用的一种关键技术。
#创建全文索引
ALTER TABLE table_name ADD FULLTEXT (column);
通过执行计划,可以判断本次查询中对于数据行定位是否是从索引获取的
EXPLAIN 查询语句
对于查询的评级由好到坏:const > primary(主键) > ref > range > index > all
show processlist;
,查看当前 mysql 使用频繁的 sql 语句。事务隔离级别 | 说明 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
读未提交(read-uncommitted) | 读取数据的事务对象,可以读取到另一个事务对象尚未提交的数据 | 是 | 是 | 是 |
不可重复读(read-committed) | 读取数据的事务对象,只能读取另一个事务对象提交过后的数据 | 否 | 是 | 是 |
可重复读(repeatable-read) (默认) |
读取数据的事务对象,在另一个事务对象提交前后读取的内容要保持一致 | 否 | 否 | 是 |
串行化(serializable) | 串行读取 | 否 | 否 | 否 |
脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。事务1在两次查询的过程中,事务2对该表进行了插入、删除操作,从而事务1第二次查询的结果发生了变化。
总结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
MyIsam:
使用三个文件表示每个表:
对表文件中数据行查询提速,有很大帮助。
灵活的AUTO_INCREMENT
字段处理
可被转换为压缩、只读表来节省空间
但是MyIsam不支持事务,因此在进行数据行添加,修改,删除时,无法保证数据安全性
INNODB:MySQL数据库的默认引擎;
InnoDB
表在数据库目录中以.frm
格式文件表示InnoDB
表空间tablespace
被用于存储表的内容ACID
兼容MySQL
服务器崩溃后提供自动恢复MVCC
)和行级锁定MEMORY:其数据存储在内存中,且行的长度固定,这两个特点使得MEMORY存储引擎非常快;
.frm
格式文件表示;MyISAM
表最适合于大量的数据读而少量数据更新的混合操作。MyISAM表的另一种适用情形是使用压缩的中读表。InnoDB
。其行级锁机制和多版本的支持为数据读取和更新的混合提供了良好的并发机制。MEMORY
存储引擎存储非永久需要的数据,或者是能够从基于磁盘的表中重新生成的数据。行级锁:
表级锁:
由于Innodb引擎支持的均为行锁,所以意向锁其实不会阻塞除全表扫描之外的任何请求
乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
实现方式:
+1
操作,否则就执行失败+1
操作。使用场景:
乐观锁适用于写比较少的情况下(多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry
,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适。
使用Power Designer
来创建表
第一范式:每一个字段是原子性不能再分;
第二范式:在第一范式基础之上,要求数据库中所有非主键字段完全依赖主键,不能产生部分依赖;
第三范式:在第二范式基础之上,要求非主键字段不能产生传递依赖于主键字段
SQL注入产生的原因,就是用户提交的数据,被数据库系统编译而产生了开发者预期之外的动作。也就是,SQL注入是用户输入的数据,在拼接SQL语句的过程中,超越了数据本身,成为了SQL语句查询逻辑的一部分,然后这样被拼接出来的SQL语句被数据库执行,产生了开发者预期之外的动作。
解决办法:
PreparedStatement
),在SQL语句中放置占位符’?
’,在执行前,数据库会先对含有占位符的SQL语句进行校验和预编译;执行时才会把参数传递进去,防止参数参与编译变成sql语句的一部分。'
),分号(;
) 和 注释符号(--
)的语句给替换掉来防止SQL注入单线程,利用redis队列技术并将访问变为串行访问,消除了传统数据库串行控制的开销
支持数据持久化,支持AOF和RDB两种持久化方式。
分布式 读写分离模式
支持丰富数据类型
支持事务,操作都是原子性,所谓原子性就是对数据的更改要么全部执行,要不全部不执行。
String类型:
Hash类型:
List类型:
Set类型:
Zset类型:
定期删除+惰性删除。
定期删除:redis
默认是每隔 100ms
就会扫描一定数量的数据库的expires
字典中的key
,检查其是否过期,如果过期就删除。定期删除可能会导致很多过期 key
到了时间并没有被删除掉,所以就使用惰性删除。
expires
字典会保存所有设置了过期时间的key
的过期时间数据,其中,key
是指向键空间中的某个键的指针,value
是该键的毫秒精度的UNIX
时间戳表示的过期时间。键空间是指该Redis
集群中保存的所有键。
惰性删除:获取 key
的时候,如果此时 key
已经过期,就删除,不会返回任何东西。
Redis Database(RDB),就是在指定的时间间隔内将内存中的数据集快照写入磁盘,数据恢复时将快照文件直接再读到内存。
RDB 保存了在某个时间点的数据集(全部数据)。存储在一个二进制文件中,只有一个文件。默认是 dump.rdb
。 RDB 技术非常适合做备份,可以保存最近一个小时,一天,一个月的全部数据。保存数据是在单独的进程中写文件,不影响 Redis 的正常使用。 RDB
恢复数据时比其他 AOF
速度快。
Append-only File(AOF), Redis
每次接收到一条改变数据的命令时,它将把该命令写到一个 AOF
文件中(只记录写操作,读操作不记录),当 Redis
重启时,它通过执行 AOF
文件中所有的命令来恢复数据。
CAP原则又称CAP定理,指在一个分布式系统不可能同时满足 Consistency
(一致性)、 Availability
(可用性)、Partition tolerance
(分区容错性)。由于分区容错性是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!