java基本类型
基本数据类型只有8个:byte、short、int、long、float、double、char、boolean
float f=3.14;是否正确?
不正确,3.14为double类型 可以写为 float f =(float)3.4; 或者写成float f =3.4F。
int 和Integer 有什么区别?
Integer 是int的包装类 Integer 是一个类 初始值为null int初始值是0
Math.round(11.5) 等于多少? Math.round(-11.5)等于多少?
Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。
什么类型可以用在switch上?
早期jdk byte、short、char、int JDK1.5以后 引入枚举(enum) JDK1.7 可以是String(long是不可以的)
构造器(constructor)是否可被重写(override)?
构造器不能被继承,因此不能被重写,但可以被重载。
两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。Java对于eqauls方法和hashCode方法是这样规定的:(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;(2)如果两个对象的hashCode相同,它们并不一定相同。
String 类是一个final类 不能被继承
当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
Java 编程语言只有值传递参数。
String 和StringBuilder、StringBuffer 的区别?
他们是两种类型的字符串, String是只读字符串,也就意味着String引用的字符串内容是不能被改变的.而StringBuffer和StringBuilder类表示的字符串对象可以直接进行修改
StringBuilder线程不安全;StringBuffer线程安全(加了synchronized)
抽象类(abstract class)和接口(interface)有什么异同?
(1)抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。
(2)抽象类必须在类前用abstract关键字修饰.抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。
(3)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的
抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
String s=new String(“xyz”);创建了几个字符串对象?
答:两个对象,一个是静态存储区的"xyz",一个是用new创建在堆上的对象。
接口是否可继承(extends)接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete
class)?
接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。
final 和static修饰变量的区别
final修饰变量是一个常量,强调的是值只有这一个
static修饰的变量是所有对象共享的变量,值可以改变,强调的是对象都是这一个
Error 和Exception 有什么区别?
Error 表示系统级的错误,无法通过程序自己处理掉;比如内存溢出,不可能指望程序能处理这样的情况;
Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
final, finally, finalize的区别
final: java关键字,被final修饰的类不能被继承,修饰方法方法能被重写,修饰变量变量就是一个常量 不能被重新赋值
finally:try catch finally 中使用,无论异常发生不发生都会执行finally中的东西
finalize是方法名: finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
throw和throws的区别
throw是语句抛出一个异常,一般是在代码块的内部,当程序出现某种逻辑错误时由程序员主动抛出某种特定类型的异常.
throws是方法可能抛出异常的声明。调用此方法需要拦截异常或者继续抛出
volatile和synchoronized
volatile和synchoronized区别:
(1) volatile变量是一种比synchronized关键字更轻量级的同步机制。volatile不会阻塞.
(2)volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
(3)volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
常用的集合类
Collection :
(1)List: 有序可重复 LinkedList(底层链表,线程不安全) , ArrayList(底层数组,线程不安全) , Vector(底层数组,线程安全)
(2)Set 不可重复,hashSet(线程不安全,通过HashCode()和equals判断是否重复),TreeSet(二叉树结构,可以进行排序)
Map:
HashMap:HashMap 底层是基于 数组 + 链表 组成的,线程不安全,允许null键和null值.
HashTable :线程安全,不允许null键和null值.
TreeMap: 基于红黑树(Red-Black tree)实现.线程不安全,有序;
HashMap的工作原理
底层实现:数组和链表
通过HashCode和equals保证键不能重复的
hashMap的主干是一个Node数组每一个Node包含一个key与value的键值对
hash冲突的解决方法:hashmap采用的就是链地址法,在冲突的地址上生成一个链表
HashMap的扩容机制
什么时候扩容:当HashMap的键值对个数大于容量的75%时,HashMap的容量扩大一倍
默认初始容量16 负载系数为0.75
HashMap中Put方法的实现原理
当我们调用put()方法时,比如hashMap.put(“Java”,0),此时要插入一个Key值为“Java”的元素,这时首先需要一个Hash函数来确定这个Entry的插入位置;如果hash冲突就该使用链表了.新来的Entry节点采用的是“头插法”,这是因为HashMap的发明者认为,新插入的节点被查找的可能性更大。
HashMap中Get方法的实现原理
get()方法用来根据Key值来查找对应点Value,当调用get()方法时,比如hashMap.get(“apple”),这时同样要对Key值做一次Hash映射,算出其对应的index值,.如果有hash冲突,就从链表的头部开始查找
HashMap的死锁
在多线程的情况下,当重新调整HashMap大小的时候,就会存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历。如果条件竞争发生了,那么就会产生死循环了。
HashSet,内部是如何工作的?
HashSet 的内部采用 HashMap来实现。是 HashSet 中只允许存储一个 null 对象。
初始大小也是16 默认装载因子是0.75
== 和 equals()的区别
==比较的是地址,
equals用来比较的是两个对象的值 String
hashCode
hashCode是用来在散列存储结构中确定对象的存储地址的;
如果两个对象相同,就是适用于equals(java.lang.Object) 方法,那么这两个对象的hashCode一定要相同;
两个对象的hashCode相同,并不一定表示两个对象就相同
Object有哪些公用方法?
(1)clone方法:保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
(2)getClass方法:final方法,获得运行时类型。
(3)toString方法:该方法用得比较多,一般子类都有覆盖。
(4)finalize方法:释放资源,很少使用
(5)equals方法
(6)hashCode方法:该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。
(7)wait方法:wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
1)其他线程调用了该对象的notify方法。
2)其他线程调用了该对象的notifyAll方法。
3)其他线程调用了interrupt中断该线程。
4)时间间隔到了。
(8)notify方法:该方法唤醒在该对象上等待的某个线程。
(9)notifyAll方法: 该方法唤醒在该对象上等待的所有线程。
如何实现对象克隆
浅克隆:
(1)被复制的类需要实现Clonenable接口
(2)覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象。
深克隆:
实现深克隆,可以通过覆盖Object类的clone()方法实现,也可以通过序列化(Serialization)等方式
构造器(constructor)是否可被重写(override)
Constructor(构造器)不能被继承,所以不能被override(重写),但是可以被overloading(重载)。
抽象的(abstract)方法 是否可同时是 静态的(static)?
不能, 抽象方法需要子类重写,而静态的方法是无法被重写的
abstract与synchronized可以同时使用吗?
abstract与synchronized不能同时使用 ,用synchronized的前提是该方法可以被直接调用, abstract方法需要被重写。
在try块中可以抛出异常吗?
可以
Collection和Collections的区别
Collection,是单列集合的接口,有子接口List和Set
Collections,是针对集合操作的工具类,其中包含对集合进行排序和二分查找的方法
如何实现数组和 List 之间的转换?
数组转 List ,使用 JDK 中 java.util.Arrays 工具类的 asList 方法
List 转数组,使用 List 的toArray方法。无参toArray方法返回Object数组,传入初始化长度的数组对象,返回该对象数组
Array和ArrayList之间的区别
(1)Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明。
(2)Array只能存储同构的对象,而ArrayList可以存储异构的对象。同构的对象是指类型相同的对象
(3)Array对象的初始化必须只定指定大小,且创建后的数组大小是固定的,
而ArrayList的大小可以动态指定,其大小可以在初始化时指定,也可以不指定,也就是说该对象的空间可以任意增加。
(4) Array不能够随意添加和删除其中的项,而ArrayList可以在任意位置插入和删除项。
什么是迭代器(Iterator)?
Iterator接口提供了很多对集合元素进行迭代的方法.
IO 和 NIO 的区别,NIO的优点
(1)IO是面向流的,NIO是面向缓冲区的。
(2)IO是阻塞的,NIO是非阻塞的
(3)NIO有选择器机制,可以让线程监控多个IO通道
NIO优点:
不需要使用 read() 或者 write() 就可以处理文件内容NIO比较快
什么是反射?
反射是指程序可以访问,检测和修改它本身状态或行为的一种能力,打破了java的封装性
什么是 java 序列化?什么情况下需要序列化?
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行序列化,将数据分解成字节流,方便存储在文件中或在网络上传输
通常分布式调用对象时需要序列化 如dubbo
什么是动态代理?动态代理是如何实现的?动态代理有哪些应用?
动态代理:是指当要给实现了某个接口的类中添加一些额外的处理, 比如日志,事务等.可以给这个类创建一个代理(一个新的类),这个类不仅有原来的类的方法,还添加新的功能.这个类不是定义好的,而是动态生成的
动态代理实现:首先必须定义一个接口,还要有一个InvocationHandler处理类
动态代理的应用:Spring的AOP,加事务,加权限,加日志。
常见的异常类有哪些?
java.io.FileNotFoundException 文件没找到
java.lang.ConcurrentModificationException 集合中的并发修改异常。
java.lang.nullpointerexception 空指针异常
ArrayIndexOutOfBoundsException 数组下标越界异常
简述 tcp 和 udp的区别?
(1)TCP基于连接与UDP无连接
(2)TCP要求系统资源较多,UDP较少;
(3)TCP保证数据正确性,UDP可能丢包
(4)TCP保证数据顺序,UDP不保证
TCP三次握手 为什么要三次握手,两次不行吗?为什么?
第一次握手: 客户端 发送请求报文,将SYN标识位置为1,然后进入SYN_SEND状态
第二次握手: 服务器收到SYN报文段进行确认,将SYN标识位置为1,ACK置为1,然后进入SYN_RECV状态
第三次握手: 客户端再进行一次确认,将ACK置为1,Sequence Number置为x+1,Acknowledgment Number置为y+1发向服务器,最后客户端与服务器都进入ESTABLISHED状态
为什么要三次握手?
这主要是为了防止已经失效的连接请求报文段突然又传回到服务端而产生错误的场景:所谓"已失效的连接请求报文段"是这样产生的。正常来说,客户端发出连接请求,但因为连接请求报文丢失而未收到确认。于是客户端再次发出一次连接请求,后来收到了确认,建立了连接。数据传输完毕后,释放了连接,客户端一共发送了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,没有"已失效的连接请求报文段"。
现在假定一种异常情况,即客户端发出的第一个连接请求报文段并没有丢失,只是在某些网络节点长时间滞留了,以至于延误到连接释放以后的某个时间点才到达服务端。本来这个连接请求已经失效了,但是服务端收到此失效的连接请求报文段后,就误认为这是客户端又发出了一次新的连接请求。于是服务端又向客户端发出请求报文段,同意建立连接。假定不采用三次握手,那么只要服务端发出确认,连接就建立了。
由于现在客户端并没有发出连接建立的请求,因此不会理会服务端的确认,也不会向服务端发送数据,但是服务端却以为新的传输连接已经建立了,并一直等待客户端发来数据,这样服务端的许多资源就这样白白浪费了。
TCP四次挥手
由于TCP连接是全双工的,因此每个方向都必须单独进行关闭。
(1)客户端A发送一个FIN,用来关闭客户A到服务器B的数据传送。
(2)服务器B收到这个FIN,它发回一个ACK,确认序号为收到的序号加1(报文段5)。和SYN一样,一个FIN将占用一个序号。
服务器B关闭与客户端A的连接,发送一个FIN给客户端A(报文段6)。
(4)客户端A发回ACK报文确认,并将确认序号设置为收到序号加1(报文段7)。
为什么建立连接协议是三次握手,而关闭连接却是四次握手呢
这是因为服务端的LISTEN状态下的SOCKET当收到SYN报文的连接请求后,它可以把ACK和SYN(ACK起应答作用,而SYN起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可能未必会马上会关闭SOCKET,也即你可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示你同意现在可以关闭连接了,所以它这里的ACK报文和FIN报文多数情况下都是分开发送的。
说一下 tcp 粘包是怎么产生的?
①. 发送方产生粘包
采用TCP协议传输数据的客户端与服务器经常是保持一个长连接的状态(一次连接发一次数据不存在粘包),双方在连接不断开的情况下,可以一直传输数据;但当发送的数据包过于的小时,那么TCP协议默认的会启用Nagle算法,将这些较小的数据包进行合并发送(缓冲区数据发送是一个堆压的过程);这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。
②. 接收方产生粘包
接收方采用TCP协议接收数据时的过程是这样的:数据到底接收方,从网络模型的下方传递至传输层,传输层的TCP协议处理是将其放置接收缓冲区,然后由应用层来主动获取(C语言用recv、read等函数);这时会出现一个问题,就是我们在程序中调用的读取数据函数不能及时的把缓冲区中的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。
简单工厂和抽象工厂有什么区别?
简单工厂 工厂类(SimpleFactory)拥有一个工厂方法(create),接受了一个参数,通过不同的参数实例化不同的产品类。
抽象工厂 抽象工厂是应对产品族概念的。
Java中的泛型是什么 ? 使用泛型的好处是什么?
泛型其实指得就是参数化类型,使得代码可以适应多种类型。
泛型作用:
1、编译时期类型检查,提高代码安全性,所有的强制转换都是自动和隐式的。
2、最大限度的复用代码。
Java的泛型是如何工作的 ? 什么是类型擦除 ?
泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。
Array中可以用泛型吗?
不能,可以用List替换Array,因为List可以提供编译期的类型安全保证,而Array却不能。
类加载过程
类加载过程即是指JVM虚拟机把.class文件中类信息加载进内存,并进行解析生成对应的class对象的过程
类加载分为三个步骤:加载,连接(验证 , 准备 , 解析 ),初始化;
加载: 根据一个类的全限定名来读取此类的二进制字节流到JVM内部
验证: 文件格式验证 元数据验证, 字节码验证 符号引用验证
准备: 为类中的静态变量分配内存空间,并设定初始值
解析: 将常量池中所有符号引用转化为(得到类或者字段)
初始化: 在连接阶段类变量已经赋过一次系统要求的初始值,初始化阶段是根据程序逻辑初始化变量和其他资源
自定义类加载器
要创建用户自己的类加载器,只需要继承java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,即指明如何获取类的字节码流。
JAVA热部署实现
不重启java虚拟机的情况下,自动侦测到class文件的变化,更新运行新的class文件
热部署步骤
1、销毁该自定义ClassLoader
2、更新class类文件
3、创建新的ClassLoader去加载更新后的class类文件。
如何将字符串反转?
(1)StringBuiler的reverse()的方法,方便快捷
(2)通过String类的charAt()的方法来获取字符串中的每一个字符,然后将其拼接为一个新的字符串
(3)通过String的toCharArray()方法可以获得字符串中的每一个字符串并转换为字符数组,然后用一个空的字符串从后向前一个个的拼接成新的字符串。
字符串去掉空格
(1)去除字符串首尾空格字符的方法:String trim();
(2)str.replace(" ", “”); 去掉所有空格,包括首尾、中间
参考:
https://www.cnblogs.com/aspirant/p/7200523.html
https://www.jianshu.com/p/60fdfce9bc25
https://blog.csdn.net/jackfrued/article/details/17339393
https://blog.csdn.net/qq_41701956/article/details/88074060
https://blog.csdn.net/StrideBin/article/details/79267121
https://blog.csdn.net/xiangzhihong8/article/details/78535331
https://blog.csdn.net/VampireKalus/article/details/79798372
https://blog.csdn.net/sihai12345/article/details/79465620