java基础02(异常 IO流 反射 多线程 集合)

1.Java异常

v1.异常体系。

--Error 错误,系统不可恢复错误
		堆内存溢出错误. 引用不释放,将会造成内存泄漏问题.
--Exception例外,异常
		可检查异常:也叫做编译异常IOEexception
		非检查异常:RuntimeException

v2.Exception和Error的区别。

Exception和Error都继承自Throwable类。Exception是程序出现的异常,是程序员可以处理,而且应该处理的。Error是系统级错误,是不可恢复的。

v3.异常处理的二种方式:catch和throws

	通过try、catch捕获异常

try{

// 程序代码

}catch(ExceptionName e1){

//Catch 块

}

通过throws抛出异常

定义一个方法的时候可以使用throws关键字声明。使用throws关键字声明的方法表示此方法不处理异常,而交给方法调用处进行处理。

throw关键字抛出异常

throw关键字作用是抛出一个异常,抛出的时候是抛出的是一个异常类的实例化对象,在异常处理中,try语句要捕获的是一个异常对象,那么此异常对象也可以自己抛出。

v4.常见异常:6种
在这里插入图片描述

2.IO流

v1.IO流可以按照功能和类型进行分类详细见如下图

按照流的流向分,可以分为输入流和输出流。输入、输出是针对程序来说的。

  1. 输出:把程序(内存)中的内容输出到磁盘、光盘等存储设备中。
  2. 输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。

按处理数据单位不同分为字节流和字符流。
3. 字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码。
4. 字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文。

按照流的角色划分为节点流和处理流。
5. 节点流:从或向一个特定的地方(节点)读写数据。如FileInputStream。
6. 处理流(包装流):是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
在这里插入图片描述
v2.字节流和字符流的区别是:

  1. 字节流按8位传输以字节为单位输入输出数据,字符流按16位传输以字符为单位输入输出数据。
  2. 字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的;而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。

v3.BIO NIO AIO分别是什么?

  • BlO: Block l0同步阻塞式l0,就是我们平常使用的传统I0,它的特点是模式简单使用方便,并发处理能力低。
  • NIO : New l0同步非阻塞l0,是传统l0的升级,客户端和服务器端通过Channel(通道)通讯,实现了多路复用。
  • AlO: Asynchronous l0是NIO的升级,也叫NIO2,实现了异步非堵塞I0,异步IO的操作基于事件和回调机制。

v4.补充 什么是Java序列化,如何实现Java序列化?

序列化就是一种用来处理对象流的机制,将对象的内容进行流化。可以对流化后的对象进行读写操作,可以将流化后的对象传输于网络之间。序列化是为了解决在对象流读写操作时所引发的问题
序列化的实现:将需要被序列化的类实现Serialize接口,没有需要实现的方法,此接口只是为了标注对象可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,再使用ObjectOutputStream对象的write(Object obj)方法就可以将参数obj的对象写出

v5.什么是反序列化,如何实现Java反序列化?

反序列化就是从 IO 流中恢复对象。
1.创建 ObjectInputStream 输入流 2.调用ObjectInputStream对象的readObject()得到序列化的对象。

v6.序列化使用场景

  • 所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口。
  • 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
  • 如果想让某个变量不被序列化,使用transient修饰。
  • 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
  • 反序列化时必须有序列化对象的class文件。
  • 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
  • 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
  • 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
  • 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。

3.反射

v1.什么是反射?(动态获取?),反射的优缺点?

  • 就是在运行状态中。获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
  • 获取任意对象的属性,并且能改变对象的属性
  • 调用任意对象的方法
  • 判断任意一个对象所属的类
  • 实例化任意一个类的对象

优:实现动态装配,降低代码的耦合度;动态代理
缺:反射的过度使用会严重消耗系统资源。

v2.反射机制

  • Java的反射机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

v3.反射机制的应用场景

  1. 1.JDBC中,利用反射动态加载了数据库驱动程序。
  2. Web服务器中利用反射调用了Sevlet的服务方法。
  3. Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。
  4. 很多框架都用到反射机制,注入属性,调用方法,如Spring。

v4. 反射机制的优缺点?

  • 优点:可以动态执行,在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性。
  • 缺点:对性能有影响,这类操作总是慢于直接执行java代码。

v5.什么是动态代理?

  • 为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为委托了(真实对象)预处理消息、过滤消息、传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。
    (后面还有正向代理和反向代理)
    v6.怎么实现动态代理?
  • JDK 原生动态代理和 cglib 动态代理。
  • JDK 原生动态代理是基于接口实现的,而 cglib 是基于继承当前类的子类实现的。

4.多线程

v1.什么是多线程?
1.先了解什么是线程,以及线程和进程的关系。一个程序中至少有一个进程,一个进程有至少有一个线程,但是一个进程也可以有多个线程。可以提高系统的性能。线程是进程最小的单位。

  • 进程想要执行任务就需要依赖线程。换句话说,就是进程中的最小执行单位就是线程,并且一个进程中至少有一个线程。
    2.串行和并行分别是什么?
  1. 所谓串行,其实是相对于单条线程来执行多个任务来说的,我们就拿下载文件来举个例子:当我们下载多个文件时,在串行中它是按照一定的顺序去进行下载的,也就是说,必须等下载完A之后才能开始下载B,它们在时间上是不可能发生重叠的。(同一个时间段只可以做一个事情)
  2. 并行:下载多个文件,开启多条线程,多个文件同时进行下载,这里是严格意义上的,在同一时刻发生的,并行在时间上是重叠的。(同一个时间段可以做多个事情)

3.并行和并发有什么区别?

  • 并行:多个处理器或多核处理器同时处理多个任务。
  • 并发:多个任务在同一个CPU核上,按细分的时间片轮流(交替)执行,从逻辑上来看那些任务是同时执行。

4.守护线程是什么?

  • 守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在Java中垃圾回收线程就是特殊的守护线程。
    5.怎么创建线程?
  • 继承Thread重新run方法;
  • 实现Runnable接口;
  • 实现Callable接口。

多线程:是指从软件或者硬件上实现多个线程并发执行的技术

v2.线程安全

  • 当多个线程访问某个方法时,不管你通过怎样的调用方式、或者说这些线程如何交替地执行,我们在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以说这个类是线程安全的。(相当于你去拿一个苹果 ,无论是其他人有没有让你拿其他的东西。最后的结果就是你只拿了一个苹果回来。那就是线程安全的。如果在这个过程中, 你多了其他的的东西。那就不是线程安全。)

v3.确保线程安全最常用的两种方式

  1. synchronized关键字,就是用来控制线程同步的,保证我们的线程在多线程环境下,不被多个线程同时执行,确保我们数据的完整性,使用方法一般是加在方法上。(实现线程同步)
  2. 引入Lock让锁有了可操作性,就是我们在需要的时候去手动的获取锁和释放锁,甚至我们还可以中断获取以及超时获取的同步特性。但是这样的效果就是如果一直没有执行完就需要一直在等待状态。

v4.线程的五种状态

  1. 新建(NEW):新创建了一个线程对象。
  2. 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
  3. 运行(RUNNING):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
  4. 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。
  5. 死亡(DEAD):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。

v5.阻塞的情况分三种:

  • 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
  • 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
  • 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。

v6.如何防止死锁?
什么是死锁:

   当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,称为死锁。

如何防止死锁:

  • 尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
  • 尽量使用 Java. util. concurrent 并发类代替自己手写锁。
  • 尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
  • 尽量减少同步的代码块。

v7.sleep()和wait()有什么区别?

  • 类的不同: sleep()来自Thread,wait()来自Object。·释放锁: sleep()不释放锁;wait()释放锁。
  • 用法不同: sleep()时间到会自动恢复;wait()可以使用notify()/notifyAll()直接唤醒。

v8.notify()和notifyAll()有什么区别?

  • notifyAll()会唤醒所有的线程,notify()之后唤醒一个线程。notifyAll()调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify()只会唤醒一个线程,具体唤醒哪一个线程由虚拟机控制。

v9.线程的run()和start()有什么区别?

  • start()方法用于启动线程,run()方法用于执行线程的运行时代码。run()可以重复调用,而start()只能调用一次。

5.集合

在这里插入图片描述
1.HashMap 和Hashtable有什么区别?

  • 存储: HashMap运行key和value为null,而Hashtable不允许。
  • 线程安全: Hashtable是线程安全的,而HashMap是非线程安全的。
  • 推荐使用:在Hashtable的类注释可以看到,Hashtable是保留类不建议使用,推荐在单线程环境下使用HashMap替代,如果需要多线程使用则用ConcurrentHashMap替代。

2.如何决定使用HashMap还是TreeMap?

  • 对于在Map中插入、删除、定位一个元素这类操作,HashMap是最好的选择
  • 因为相对而言HashMap的插入会更快,但如果你要对一个key集合进行有序的遍历,那TreeMap是更好的选择。

3.说一下HashMap的实现原理?

  • HashMap基于Hash算法实现的,我们通过put(key,value)存储,get(key)来获取。当传入key时,HashMap 会根据key. hashCode()计算出hash值,根据hash值将value保存在bucket里。当计算出的hash值相同时,我们称之为hash冲突,HashMap的做法是用链表和红黑树存储相同hash值的value。当hash冲突的个数比较少时,使用链表否则使用红黑树。

4.说一下HashSet的实现原理?

  • HashSet是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,因此HashSet的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成,HashSet不允许重复的值。

5.ArrayList和LinkedList的区别是什么?

  • 数据结构实现: ArrayList是动态数组的数据结构实现,而LinkedList是双向链表的数据结构实现。
  • 随机访问效率:ArrayList 比 LinkedList在随机访问的时候效率要高,因为LinkedList是线性的数据存储方式,所以需要移动指针从前往后依次查找
    增加和删除效率:在非首尾的增加和删除操作,LinkedList要比ArrayList效率要高,因为ArrayList增删操作要影响数组内的其他数据的下标。
  • 综合来说,在需要频繁读取集合中的元素时,更推荐使用ArrayList,而在插入和删除操作较多时,更推荐使用LinkedList。

6.如何实现数组和List之间的转换?

  • 数组转List:使用Arrays.asList(array)进行转换。
  • List转数组:使用List自带的toArray()方法。

7.ArrayList 和Vector的区别是什么?

  • 线程安全: Vector使用了Synchronized来实现线程同步,是线程安全的,而ArrayList是非线程安全的。
  • 性能: ArrayList在性能方面要优于Vector。
  • 扩容:ArrayList和Vector都会根据实际的需要动态的调整容量,只不过在Vector扩容每次会增加1倍,而ArrayList只会增加50%。

8.Array和ArrayList有何区别?

  • Array可以存储基本数据类型和对象,ArrayList只能存储对象。. Array是指定固定大小的,而ArrayList大小是自动扩展的。
  • Array内置方法没有ArrayList多,比如addAll、removeAll、iteration等方法只有ArrayList有。

9.在Queue 中poll()和remove()有什么区别?

  • 相同点:都是返回第一个元素,并在队列中删除返回的对象。
  • 不同点:如果没有元素poll()会返回null,而remove()会直接抛出NoSuchElementException异常。

10.哪些集合类是线程安全的?

  • Vector、Hashtable、Stack都是线程安全的,而像HashMap则是非线程安全的,不过在JDK 1.5之后随着Java.util. concurrent并发包的出现,它们也有了自己对应的线程安全类,比如HashMap对应的线程安全类就是ConcurrentHashMap。

11.Iterator 和Listlterator有什么区别?

  • lterator可以遍历Set和List集合,而Listlterator只能遍历List。
  • lterator只能单向遍历,而Listlterator可以双向遍历(向前/后遍历)。
  • Listlterator 从 Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。

12.迭代器Iterator是什么?

  • lterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration,迭代器允许调用者在迭代过程中移除元素。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值