一.java基础
1.JDK和JRE有什么区别?
JDK是java开发工具包,JRE是java运行时环境(包括Java基础类库,java虚拟机)
2.==和equals的区别是什么?
==比较的是两者的地址值,equals比较的是两者的内容是否一样
3.两个对象的hashcode()相同,则equals()也一定为true吗?
两个对象的equals返回true,那么hashcode一定相等;
两个对象的hashcode相等,那么equals不一定为true;
4.final在java中的作用?
修饰类:表明该类不可被继承,类中的所有成员方法都隐式的被指定为final方法
修饰方法:不可被重写,JVM会尝试将其内联,以提高运行效率
修饰变量:不可被改变,修饰引用变量表示引用不可变,引用指向的内容可变
修饰常量:在编译阶段会存入常量池中
5.java中操作字符串都有哪些类?有什么区别?
String:是只读字符串,每次对string的操作都会产生一个新的对象
StringBuilder:可变的字符数组,线程不安全
StringBuffer:可变的字符数组,对方法加了同步锁,线程安全
6.如何将字符串反转?
1.使用StringBuilder的reverse()方法
2.使用字符串数组,实现从尾部开始逐个逆序放入字符串
3.使用String的CharAt方法,调用StringBuilder的insert方法进行操作
4.使用递归的方法
7.string类的常用方法有哪些?
1.获取字符串长度length()
2.获取位置上的某个字符charAt()
3.获取字符的位置indexOf()
4.判断是否包含某个字符contains()
5.判断字符串中是否有内容isEmpty()
6.判断字符串是否一指定字符开头结尾startsWith(),endsWith()
7.判断字符串内容是否相同equals()
8.切割split()
8.抽象类必须要写抽象方法吗?
不一定有抽象方法,但抽象方法一定在抽象类中,抽象类不能实例化
9.普通类和抽象类有哪些区别?
1.抽象类不能被实例化
2.抽象类允许普通方法有主体,抽象方法只需要申明不需要实现
3.抽象类一定有abstract关键词修饰
4.抽象的子类必须实现抽象类中的所有抽象方法,否则的话,这个子类也是抽象类
10.抽象类能使用final修饰吗?
不能,final是最终类不能被继承,而抽象类是必须被继承才有其意义
11.接口和抽象类的区别?
1.抽象类中可以定义构造器,接口不能
2.抽象类可以有抽象方法和具体方法,接口不能有具体方法
3.抽象类中可以定义成员变量,接口中只能是常量
4.抽象类中可以包含静态方法,接口中不能有静态方法
12.IO流分几种?
按照流的流向:输入流,输出流
按照操作单元:字节流和字符流
按照流的角色:节点流和处理流
13.java容器有哪些?
ArrayList,LinkedList,HashSet,HashMap
14.List,Set,Map之间的区别?
list:是个有序的集合,元素可以重复,可以索引访问
set:元素不能重复,无序
map:使用键值对KV,不允许重复,无序
15.HashMap与HashTable的区别?
1.两者父类不同:map继承abstractMap类,table继承Dictionary类
2.对外提供的接口不同:table比map多提供了elments和contains方法
3.对null的支持不同:tableK和V都不能为null,mapK可以为null,但必须保证K唯一
4.安全性不同:map不安全,会产生死锁,table每个方法上加了锁
5.初始容量大小和每次扩充容量的大小不同
6.计算hash值的方法不同
16.HashMap的实现原理?
基于hash算法实现,通过put(key,value)储存,get(key)来获取
17.HashSet的实现原理?
基于hashmap实现,使用hashmap来保存所有元素,不允许重复的值
18.ArrayList和LinkedList的区别?
arraylist:基于动态数组的数据结构,地址连续,查询效率高
linkedlist:基于链表的数据结构,地址无序,新增删除效率高
19.怎么实现数组和list之间的转换?
数组转list:使用asList方法
list转数组:使用toArray方法
20.数组有没有length()方法?String有没有length()方法?
数组是没有length()这个方法的,有length这个属性,可以计算数组的长度
String是有length()这个方法的,用来计算字符串的长度。
1.JDK和JRE区别
JRE(Java Runtime Enviroment)是运行Java程序所必须环境的集合,包含JVM标准实现及 Java核心类库。它包括Java虚拟机、Java平台核心类和支持文件。它不包含开发工具(编译器、调试器等)。
JDK(Java Development Kit)是Java开发工具包,它提供了Java的开发环境(提供了编译器javac等工具,用于将java文件编译为class文件)和运行环境(提供了JVM和Runtime辅助包,用于解析class文件使其得到运行)。
2.八大数据类型
分别是byte, short, int, long, char, float, double, boolean.
1.byte
byte属于Java中的整型,长度为1字节8bit,取值10000000(-128)到 01111111(127),变量初始化默认值为0,包装类Byte
2.short
short属于Java中的整型,长度为2字节16bit,取值10000000 00000000(-32768)到 01111111 11111111(32767),变量初始化默认值为0,包装类Short
3.int
int属于Java中的整型,长度为4字节32bit,取值-2^31 (-2,147,483,648)到 2^31-1(2,147,483,647),变量初始化默认值为0,包装类Integer
4.long
long属于Java中的整型,长度为8字节 64bit,取值-2^63 (-9,223,372,036,854,775,808)到 2^63-1(9,223,372,036,854,775,8087),变量初始化默认值为0或0L,包装类Long
5.float
float属于Java中的浮点型,也叫单精度浮点型,长度为4字节 32bit,变量初始化默认值0.0f,包装类Float,取值2-128~2128
6.double
double属于Java中的浮点型,也叫双精度浮点型,长度为8字节 64bit,变量初始化默认值0.0d,包装类Double,取值2-1024~21024
7.char
char属于java中的字符型,占2字节 16bit,可以赋值单字符以及整型数值, 变量初始化无默认值,包装类Character。
如:
char a = ‘a’;
char a = ‘中’;
char a = 12; // 取值范围0~65536,因为char类型在ASCII字符编码中,有对应的数值,可直接做运算,输出字符表中对应的字符
8.boolean
在JVM中并没有提供boolean专用的字节码指令,而boolean类型数据在经过编译后在JVM中会通过int类型来表示,此时boolean数据4字节32位,而boolean数组将会被编码成Java虚拟机的byte数组,此时每个boolean数据1字节占8bit.
仅有两个值true, false,变量初始化默认值false
4.String类的常用方法
public int length() //返回该字符串的长度
public char charAt(int index) //返回字符串中指定位置的字符;注意字符串中第一个字符索引是0,最后一个是length()-1。
public int compareTo(String anotherString) //该方法是对字符串内容按字典顺序进行大小比较,通过返回的整数值指明当前字符串与参数字符串的大小关系。若当前对象比参数大则返回正整数,反之返回负整数,相等返回0。
public String toLowerCase()//返回将当前字符串中所有字符转换成小写后的新串
public String toUpperCase()//返回将当前字符串中所有字符转换成大写后的新串
public String substring(int beginIndex)//该方法从beginIndex位置起,从当前字符串中取出剩余的字符作为一个新的字符串返回。
5.String不可变原理
String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)
之所以设计成不可变,是为了安全,保证了线程安全,以及让常量池有意义
string不可变的设计出于性能考虑,当然背后的原理是string pool,当然string pool不可能使string类不可变,不可变的string更好的提高性能。
6.线程池三大方法,七大参数,四种拒绝策略
7.ArrayList 和LinkedList 区别以及底层原理
ArrayList和LinkedList 都实现了list的接口,Al底层是数组,时间复杂度是O(1),Lk底层数据结构是双向循环链表 ,链表只有一个前驱和后继,时间复杂度O(n)。
相对来说,Al是数组查找更容易,Lk因为是链表,所以插入、删除比较容易,但是更占内存,因为每一个节点存储了两个引用 ,一个指向前一个元素 一个后。
8.类的实例化顺序
父类静态代变量 父类静态代码块 子类静态变量 子类静态代码块
父类非静态变量 父类构造函数 子类非静态变量 子类构造
9.synchronized 和 ReentrantLock 区别是什么?
1.ReentrantLock 是 API 级别的,synchronized 是 JVM 级别的
2. ReentrantLock 可以实现公平锁
3 ReentrantLock 通过 Condition 可以绑定多个条件
4. 底层实现不一样, synchronized 是同步阻塞,使用的是悲观并发策略,lock 是同步非阻塞,采用的是乐观并发策略
5. Lock 是一个接口,而 synchronized 是 Java 中的关键字,synchronized 是内置的语言实现。
6. synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;
而 Lock 在发生异常时,如果没有主动通过 unLock()去释放锁,则很可能造成死锁现象,
因此使用 Lock 时需要在 finally 块中释放锁。
7.通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到。
10.HashMap底层原理(重点)
hashMap是线程不安全的,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,采用哈希表来存储的,hashMap是根据键的hashCode值存储数据,又很快的访问速度,但是遍历顺序不确定 hashMap是一对一或一对多的关系 键只允许有一个空值 value可以有多个 当键相同时 会覆盖掉value值
底层实现原理:
HashMap4种构造方法 指定初始大小和负载因子 指定初始大小和默认负载因子 都采用默认值 容量默认16 为了减少hash碰撞次数,折中,均匀泊松分布 。负载因子默认0.75 ,因为0.5 元素达到一半就扩容 扩容太浪费资源 ,查询效率会增加,但是空间利用率低 。1.0时空间利用率高了,但是耗费时间 。
11.HashMap的put(k,v)实现原理
(1)首先将k,v封装到Node对象当中(节点)。
(2)然后它的底层会调用K的hashCode()方法得出hash值。
(3)通过哈希表函数/哈希算法,将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果说下标对应的位置上有链表。此时,就会拿着k和链表上每个节点的k进行equal。如果所有的equals方法返回都是false,那么这个新的节点将被添加到链表的末尾。如其中有一个equals返回了true,那么这个节点的value将会被覆盖。
12.HashMap的get(k,v)实现原理
(1)先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标。
(2)通过上一步哈希算法转换成数组的下标之后,在通过数组下标快速定位到某个位置上。如果这个位置上什么都没有,则返回null。如果这个位置上有单向链表,那么它就会拿着K和单向链表上的每一个节点的K进行equals,如果所有equals方法都返回false,则get方法返回null。如果其中一个节点的K和参数K进行equals返回true,那么此时该节点的value就是我们要找的value了,get方法最终返回这个要找的value。
13.Volatile
jvm提供的轻量级同步机制
三个特性:保证可见性 不保证原子性 禁止指令重排
14.线程几种状态,什么时候会阻塞
在Java当中,线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态;
第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,等待或者睡眠中回来之后,也会处于就绪状态
第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend等方法都可以导致线程阻塞。
第五是死亡状态。如果一个线程的run方法执行结束,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪状态。
15.为什么阿里巴巴Java手册不建议使用Executors创建线程池?
FixedThreadPool和SingleThreadExecutor => 允许的请求队列长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而引起OOM异常
CachedThreadPool => 允许创建的线程数为Integer.MAX_VALUE,可能会创建大量的线程,从而引起OOM异常,这就是为什么禁止使用Executors去创建线程池,而是推荐自己去创建ThreadPoolExecutor的原因。
17.Java中final、finally、finalize的区别与用法
final:java中的关键字,修饰符。
A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。
B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
2)被声明final的方法只能使用,不能重载。
finally:java的一种异常处理机制。
finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。
finalize:Java中的一个方法名。
Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。
finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
18.java中String、StringBuffer和StringBuilder的区别
StringBuffer是线程安全,可以不需要额外的同步用于多线程中;
StringBuilder是非同步,运行于多线程中就需要使用着单独同步处理,但是速度就比StringBuffer快多了;
StringBuffer与StringBuilder两者共同之处:可以通过append、indert进行字符串的操作。
String实现了三个接口:Serializable、Comparable、CarSequence
StringBuilder只实现了两个接口Serializable、CharSequence,相比之下String的实例可以通过compareTo方法进行比较,其他两个不可以。
19.线程安不安全指什么
线程安全就是说多线程访问同一代码,不会产生不确定的结果。编写线程安全的代码是低依靠线程同步。
20.Session 与 Token 的区别
session生成方式?
浏览器第一次访问服务器,服务器会创建一个session,然后同时为该session生成一个唯一的会话的key,也就是sessionid,然后,将sessionid及对应的session分别作为key和value保存到缓存中,也可以持久化到数据库中,然后服务器再把sessionid,以cookie的形式发送给客户端。这样浏览器下次再访问时,会直接带着cookie中的sessionid。然后服务器根据sessionid找到对应的session进行匹配;
还有一种是浏览器禁用了cookie或不支持cookie,这种可以通过URL重写的方式发到服务器;
简单来讲,用户访问的时候说他自己是张三,他骗你怎么办? 那就在服务器端保存张三的信息,给他一个id,让他下次用id访问。
token的生成方式?
答:浏览器第一次访问服务器,根据传过来的唯一标识userId,服务端会通过一些算法,如常用的HMAC-SHA256算法,然后加一个密钥,生成一个token,然后通过BASE64编码一下之后将这个token发送给客户端;客户端将token保存起来,下次请求时,带着token,服务器收到请求后,然后会用相同的算法和密钥去验证token,如果通过,执行业务操作,不通过,返回不通过信息;
21.java中四种修饰符的限制范围
1.public 公共的 可以被所有其他类访问
2.private 私有的 只可以被自己访问和修改
3.protected 保护的 可以被自己,子类,同一包下的类可以访问
4.default 默认 同一包中的类可以访问
22.Object 类中的方法
(1)getclass 返回运行时类
我们写一段代码 不运行 会生成.java文件,这就是编译时类。运行时类是java文件经过编译变成.class文件,这些文件不能直接运行,交给JVM来解析运行。
(2)hashCode方法
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2) = =true。可以推出obj1.hash- Code()= =obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
(3)equals 比较地址是否相同 相当于==
重写equals方法
(4)clone 返回当前对象的副本
克隆分为深克隆和浅克隆
对于一个类只有基本类型,那深克隆和浅克隆是一样的。如果有引用类型,则不同。
深克隆 :新开辟内存空间,值拷贝
浅克隆:拷贝的是引用
(5)toString
返回对象的字符串表示形式
线程安全就是说多线程访问同一代码,不会产生不确定的结果。编写线程安全的代码是低依靠线程同步。
(6)finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
(7)wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
其他线程调用了该对象的notify方法。
其他线程调用了该对象的notifyAll方法。
其他线程调用了interrupt中断该线程。
时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
(8)notify方法
该方法唤醒在该对象上等待的某个线程。
(9)notifyAll方法
该方法唤醒在该对象上等待的所有线程。
23.线程如何通信(面试常问)
方式一:使用 volatile 关键字
基于 volatile 关键字来实现线程间相互通信是使用共享内存的思想,大致意思就是多个线程同时监听一个变量,当这个变量发生变化的时候 ,线程能够感知并执行相应的业务。这也是最简单的一种实现方式
方式二:使用Object类的wait() 和 notify() 方法
众所周知,Object类提供了线程间通信的方法:wait()、notify()、notifyaAl(),它们是多线程通信的基础,而这种实现方式的思想自然是线程间通信。
方式三:使用JUC工具类 CountDownLatch
jdk1.5之后在java.util.concurrent包下提供了很多并发编程相关的工具类,简化了我们的并发编程代码的书写,***CountDownLatch***基于AQS框架,相当于也是维护了一个线程间共享变量state
方式四:使用 ReentrantLock 结合 Condition
方式五:基于LockSupport实现线程间的阻塞和唤醒
24.do while 和while的区别
while和do…while语句都是循环语句,功能都差不多,唯一的区别在于检验条件的时间上。while语句在进入循环体之前要先判断条件是否成立,如果成立的话则进入循环体。
而do…while语句则相反,是先执行循环体,然后再判断条件是否成立,如果成立的话则继续循环体,如果不成立则跳出循环,也就是说对于do…while语句,不管条件是否成立都要先执行一遍。
25.Continue和Break区别
break:while循环break是用于永久终止循环。即不执行本次循环中break后面的语句,直接跳出循环。
continue:while循环continue是用于终止本次循环。即本次循环中continue后面的代码不执行,进行下一次循环的入口判断。
26. 面向对象的特征
面向对象的编程语言有封装、继承 、抽象、多态等4个主要的特征。
封装: 把描述一个对象的属性和行为的代码封装在一个模块中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。
抽象: 把现实生活中的对象抽象为类。分为过程抽象和数据抽象 数据抽象 -->鸟有翅膀,羽毛等(类的属性) 过程抽象 鸟会飞,会叫(类的方法)
继承:子类继承父类的特征和行为。子类可以有父类的方法,属性(非private)。子类也可以对父类进行扩展,也可以重写父类的方法。缺点就是提高代码之间的耦合性。
多态:多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定(比如:向上转型,只有运行才能确定其对象属性)。方法覆盖和重载体现了多态性。
27.Java创建对象有几种方式?
java中提供了以下四种创建对象的方式:
new创建新对象
通过反射机制
采用clone机制
通过序列化机制
28. Java 中 IO 流分为几种?
按功能来分:输入流(input)、输出流(output)。
按类型来分:字节流和字符流。
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。
29.BIO、NIO、AIO 有什么区别?
BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。