1.java中class.forName()和classLoader区别
forName除了将类.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
classLoader只干一件事,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
Class.forName(name,initialize,loader)带参函数也可控制是否加载static块
2. Spring的两种常用事务传播属性
1.REQUIRED 如果存在当前事务则用当前事务,如果不存在当前事务,则新建一个事务
2.REQUIRES_NEW 如果当前存在事务则挂起当前事务,开启一个新事务,新事务执行完毕后,唤醒之前挂起的事务,继续执行。如果不存在当前事务,则新建一个事务
3. 哪些对象是GCROOT对象
1.虚拟机栈(栈帧中的本地变量表)中的引用的对象
2.方法区中的类静态属性引用的对象
3.方法区中常量引用的对象
4.本地方法栈中JNI(即一般说的Native方法)中引用的对象
4.JAVA的线程和操作系统的线程有什么关系?
在jdk1.2之前,程序员们为JVM开发了一个线程调度内核,而到操作系统层面就是用户空间内线程实现。
而到了JDK1.2及以后,JVM选择了更加稳健且方便使用的操作系统原生的线程模型,通过系统调用,将程序的线程交给了操作系统内核进行调度
对于Sun JDK来说,它的Windows版与Linux版都是使用一对一的线程模型实现的,一条Java线程就映射到一条轻量级进程之中,因为Windows和Linux系统提供的线程模型就是一对一的。
也就是说,现在的Java中线程的本质,其实就是操作系统中的线程,Linux下是基于pthread库实现的轻量级进程,Windows下是原生的系统Win32 API提供系统调用从而实现多线程。
5.binlog 的不同模式有什么区别呢?
binlog日志有三种格式,分别为Statement,MiXED,以及ROW!
Statement:优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能。(相比 row能节约多 少性能与日志量,这个取决于应用的SQL情况,正常同一条记录修改或者插入row格式 所产生的日志量还小于 Statement产生的日志量,但是考虑到如果带条件的update操作,以及整表删除,alter表等操作,ROW格式会产生大量日志,因此在考虑是否使用ROW格式日志时应该跟据应用的实际情况,其所产生的日志量会增加多少,以及带来的IO性能问题。)
缺点:由于记录的只是执行语句,为了这些语句能在slave上正确运行,因此还必须记录每条语句在执行的时候的一些相关信息,以保证所有语句能在slave得到和在master端执行时候相同的结果。另外mysql 的复制,像一些特定函数功能,slave可与master上要保持一致会有很多相关问题(如sleep()函数, 0,以及user-defined functions(udf)会出现问题).
Row:不记录sql语句上下文相关信息,仅保存哪条记录被修改。优点: binlog中可以不记录执行的sql语句的上下文相关的信息,仅需要记录那一条记录被修改成什么了。所以rowlevel的日志内容会非常清楚的记录下每一行数据修改的细节。而且不会出现某些特定情况下的存储过程,或function,以及trigger的调用和触发无法被正确复制的问题
缺点:所有的执行的语句当记录到日志中的时候,都将以每行记录的修改来记录,这样可能会产生大量的日志内容,比如一条update语句,修改多条记录,则binlog中每一条修改都会有记录,这样造成binlog日志量会很大,特别是当执行alter table之类的语句的时候,由于表结构修改,每条记录都发生改变,那么该表每一条记录都会记录到日志中。
Mixedlevel: 是以上两种level的混合使用,一般的语句修改使用statment格式保存binlog,如一些函数, statement无法完成主从复制的操作,则采用row格式保存binlog,MySQL会根据执行的每一条具体的sql语句来区分对待记录的日志形式,也就是在Statement和Row之间选择一种.新版本的MySQL中队row level模式也被做了优化,并不是所有的修改都会以row level来记录,像遇到表结构变更的时候就会以statement模式来记录。至于update或者delete等修改数据的语句,还是会记录所有行的变更。
6.反射的用途
当我们在使用IDE(Eclipse、IEDA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。反射最重要的用途就是开发各种通用的框架。很多框架(比如Spring都是配置化),为了保证框架的通用性,他们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。
5.Iterator及listIterator
也就是说如果是先Iterator接口,那么在遍历集合中元素的时候,只能往后遍历,被遍历后的元素不会在遍历到,通常无序集合实现的都是这个接口,比如HashSet,HashMap;而那些元素有序的集合,实现的一般都是LinkedIterator接口,实现这个接口的集合可以双向遍历,既可以通过next()访问下一个元素,又可以通过previous()访问前一个元素,比如ArrayList。
6.集合类的区别 ArrayList线程不安全,查询速度快 Vector 线程安全,但速度慢,已被ArrayList替代 LinkedList 链接结构,增删速度快
7.如何证明ArrayList是线程不安全的
package com.jeff.projectdemo.test;
import java.util.ArrayList;
import java.util.List;
public class TestArrayList {
private static List<Integer> list = new ArrayList<>();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
testList();
list.clear();
}
}
private static void testList() throws InterruptedException {
Runnable runnable = () -> {
for (int i = 0; i < 10000; i++) {
list.add(i);
}
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
Thread t3 = new Thread(runnable);
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println(list.size());
}
}
8.TreeMap和TreeSet在排序时如何比较元素,Collections工具类中的sort()方法如何比较元素?
TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Compareable接口从而根据键对元素进行排序。Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象必须实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用
9.JDK和JRE的区别
JDK:Java Development Kit的简称,java开发工具包,提供了Java的开发环境和运行环境。 JRE:Java Runtime Environment的简称,java运行环境,为java的运行提供了所需的环境。 具体来说JDK其实包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很 java程序调试和分析的工具。简单来说:如果你需要运行java程序,只需要安装JRE就可以了,如果你需要编写java 程序,需要安装JDK。
10.8种基础数据类型
Byte(8)、short(16)、int(32)、long(64)、float(32)、double(64)、char(16)、boolean(1)
11.HashMap的实现原理
HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序。
HashMap的数据结构,实际上是一个链表散列的数据结构,即数组和链表的结合体。
当我们往HashMap中put元素时,首先根据key的hashcode重新计算hash值,根据hash值得到这个元素在数组中位置(下标),如果该数组在该位置上已经存放了其他元素,那么在这个位置上的元素以链表的形式存放,新加入的放在链头,最先加入的放入链尾。如果数组中该位置没有元素,就直接将该元素放在数组的该位置上。
Jdk1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)
12.在Queue中poll()和remove()有啥区别
poll()和remove()都是从队列中取出一个元素,但是poll()在获取元素失败的时候会返回空,但是remove()失败的时候会抛出异常。
13.并行和并发区别
并行是指两个或多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔发生。
并行是在不同实体上的多个事件,并发是在同一实体上的多个事件。
在一台处理器上“同时”处理多个任务,在多台处理器上同时处理多个任务。
14.通过Callable和Future创建线程
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
class CallableDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
// 计算1-100的和
int sum = 0;
for (int i = 1; i <= 100; i++)
sum += i;
return sum;
}
}
public class TestCallable {
public static void main(String[] args) {
CallableDemo cd = new CallableDemo();
// 使用Callable方式创建线程,需要FutureTask类的支持,用于接收运算结果,可以使用泛型指定返回值的类型
FutureTask<Integer> result = new FutureTask<>(cd);
new Thread(result).start();
int sum = 0;
// 接收运算结果
// 只有当该线程执行完毕后才会获取到运算结果,等同于闭锁的效果
try {
sum = result.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
System.out.println("sum is " + sum);
}
}
15.说一下runnable和callable区别
Runable接口中的run()方法额返回值是void,它做的事情只是纯粹地去执行run()方法中的代码而已;
Callable接口中的call()方法是有返回值的,是一个泛型,和Future、FutureTask配合可以用来获取异步执行的结果。
16.接口与抽象类有什么区别
一个类可以实现多个接口,但是只能继承一个抽象类
接口里面的方法都是public类型的,抽象类的修饰词可以是任意的
抽象类中可以有成员方法实现细节,接口不行
抽象类中的成员变量可以是各种类型,而接口中的成员变量只能是public static final类型的
接口中不能含有静态代码块以及静态方法,而抽象类可以。
17.BIO NIO AIO区别
IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO
18.线程有几个状态
创建 就绪 运行 阻塞 死亡
19.在java程序中怎么保证多线程的运行安全?
线程安全在三个方面体现:
原子性:提供互斥访问,同一时刻只能有一个线程对数据进行操作,(atomic,synchronized);
可见性:一个线程对主内存的修改可以及时地被其他线程看到,(synchronized,volatile);
有序性:一个线程观察其他线程中的指令执行顺序,由于指令重排序,该观察结果一般杂乱无序,(happens-before原则)。
20.jdk设计synchronized的目的
序列化访问临界资源,即同一个时刻只有一个线程访问临界资源 (同步互斥访问)
属于隐式锁
显示锁:就是需要写代码去控制加锁与解锁
隐式锁:就是不需要通过自己写代码去控制加锁与解锁
21.实例对象内存存储是怎样
对象的实例存在堆区,对象的元数据存在元空间(方法区),对象的引用在栈空间
22.JVM内置锁的升级
锁有四种状态:无锁、偏向锁、轻量级锁、重量级锁
偏向锁 只有一个线程进入临界区,适用于只有一个线程访问同步块场景
轻量级锁 多线程未竞争或竞争不激烈,适用追求响应时间,同步块执行速度非常快。
重量级锁 多线程竞争,适用追求吞吐量,同步块执行速度较长
对象头部的Mark Word的32bit位,最后两位标识锁位标识,倒数第三位标识是不是偏向锁
锁状态升级与降级的过程
当有一个线程来加锁,对象会判断是锁的标志位,如果没有锁,则object Mark World的线程指向该线程
刚好有一个线程2 也来执行同步块,检查对象的锁的线程是不是指向自己,会尝试去修改线程2,会通知jvm,同步块有竞争了
如果线程1执行完了,对象的标识位修改锁的线程数据,置为空,线程2去修改数据。
如果两个线程一起来竞争锁,mark word中会记录会升级为轻量级锁。指向线程栈中的指针
线程栈中开辟一块空间,replace Mark
word也指向对象的锁。线程2加锁失败会进行一定数量的自旋。JDK1.7之后这个默认自旋的次数可以自己设置,自适应自旋。
如果一定次数还是没有获取到锁,锁会继续膨胀升级重量级锁,线程阻塞挂起。
上重量级锁,会涉及到线程上下文切换,上下文切换会涉及到操作系统用户态到内核态的切换,会非常消耗资源。
23.什么是 java 序列化?什么情况下需要序列化
简单的说就是为了保存内存中的各种对象状态,并且可以把保存的对象状态再读出来。java 提供了保存对象的机制,那就是序列化。
什么情况需要序列化:<br>
a).当你想把内存的对象状态保存到一个文件或者数据库的时候<br>
b).当你想用套接字在网络上传输对象的时候<br>
c).当你想通过RMI传输对象的时候<br>
24.常见的异常有哪些?
NullPointerException
FileNotFoundException
IndexOutOfBoundsException
IOException
SQLException
CalssCastException
IllegalArgumentException
25.mybatis中的#{}和{}方式传入的参数,mybatis不会对它进行特殊处理,而使用#{}传进来的参数,mybatis默认会将其当成字符串
可能在赋值给如id=井号{id}和id={table};
解析后是:
select * from test;
26.有没有使用过云主机?
使用过,在原来的公司我们没有使用自己的服务器,而是租用阿里的云主机。
没有使用过,但是有所了解。
云主机就是云服务运营商(阿里,华为,西部数码,新浪等),提供的远程服务器功能。
我们开发者或者企业只需按需付费就可以租用对应的服务器。
使用ssh和sftp来进行操作。
-
有没有做过数据库优化方面的事情
1.查找,定位慢查询并优化。
2.建立索引
3.分表
4.读写分离
5.使用redis缓存 -
Object o = new Object(); 在内存中占多少字节 在maven中加入依赖
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.10</version>
</dependency>
可以打印出内存布局。
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
结果为
java.lang.Object object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
12 4 (loss due to the next object alignment)
Instance size: 16 bytes
采用的是压缩的方式UseCompressedClassPointers,UseCompressedOops