欢迎光临散文网 会员登陆 & 注册

Java

2023-02-21 23:17 作者:Ssssssssssachima  | 我要投稿


Java 中如何实现序列化,有什么意义?

序列化是处理对象流的机制。

可以对流化后的对象进行读写操作。

可传输于网络之间。

序列化可解决对象流读写操作时可能引发数据乱序的问题。

序列化除了能够实现对象的持久化之外,还能够用于对象的深度克隆

实现序列化操作:

1. 实现 Serializable 接口

2. 构造对象输出流并通过 writeObject(Object)方法就可以将实现对象输出

3. 反序列化创建对象输入流,然后通过 readObject 方法从流中读取对象。

 

简述 synchronized 和 Lock的异同?

相同:

Lock 能完成 synchronized 所实现的所有功能;

不同:

Lock 有比synchronized 更精确的线程语义和更好的性能,而且不强制性的要求获得锁。

synchronized 会自动释放锁,而 Lock 需要手动释放

 

线程的基本状态以及状态之间的关系?

其中 Running 表示运行状态,Runnable 表示就绪状态(万事俱备,只欠CPU),Blocked 表示阻塞状态,阻塞状态又有多种情况,可能是因为调用 wait()

方法进入等待池,也可能是执行同步方法或同步代码块进入等锁池,或者是调用了 sleep()方法或 join()方法等待休眠或其他线程结束,或是因为发生了 I/O 中断。

 

 

 

什么是线程池(thread pool)?

减少线程创建和销毁对象的开销。

Executor 接口定义一个执行线程的工具。它的子类型线程池接口是 ExecutorService。

工具类 Executors 提供了静态工厂方法,生成的线程池,如下所示:

newSingleThreadExecutor:创建一个单线程的线程池。单线程串行执行所有任务。如果线程异常结束,那么会有一个新的线程来替代。此线程池保证所有任务按提交顺序执行。

newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60 秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说 JVM)能够创建的最大线程大小。

newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。

newSingleThreadExecutor:创建一个单线程的线程池。此线程池支持定时以及周期性执行任务的需求。

如果希望在服务器上使用线程池,强烈建议使用 newFixedThreadPool方法来创建线程池,这样能获得更好的性能。

 

启动一个线程是调用 run()还是 start()方法

启动一个线程是调用 start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由 JVM 调度并执行,这并不意味着线程就会立即运行。run()方法是线程启动后要进行回调(callback)的方法。

 

synchronized 关键字的用法?

synchronized 关键字可以将对象或者方法标记为同步,以实现对对象和方法的互斥访问,可以用 synchronized(对象) { … }定义同步代码块,或者在声明方法时将 synchronized 作为方法的修饰符。

 

编写多线程程序有几种实现方式

Java 5 以前实现多线程有两种实现方法:一种是继承 Thread 类;另一种是实现Runnable 接口。两种方式都要通过重写 run()方法来定义线程的行为,推荐使用后者,因为 Java 中的继承是单继承,一个类有一个父类,如果继承了 Thread 类就无法再继承其他类了,显然使用 Runnable 接口更为灵活。

Java 5 以后创建线程还有第三种方式:实现 Callable 接口,该接口中的 call方法可以在线程执行结束时产生一个返回值

 

请说出与线程同步以及线程调度相关的方法

wait():使一个线程处于等待(阻塞)状态,释放对象的锁;

sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要处理 InterruptedException 异常;

notify():唤醒一个处于等待状态的线程,当然在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤醒哪个线程,而且与优先级无关;

notityAll():唤醒所有处于等待状态的线程,该方法并不是将对象的锁给所有线程,而是让它们竞争,只有获得锁的线程才能进入就绪状态;

线程的 sleep()方法和 yield()方法有什么区别?

① sleep()方法给其他线程运行机会时不考虑线程的优先级;yield()方法只会给相同或更高优先级的线程以运行的机会;

② 线程执行 sleep()方法后转入阻塞(blocked)状态,而执行 yield()方法后转入就绪(ready)状态;

③ sleep()方法声明抛出 InterruptedException(中断异常),而 yield()方法没有声明任何异常;

 

Thread 类的 sleep()方法和对象的 wait()方法都可以让线程暂停执行,它们有什么区别?

sleep()方法是Thread的静态方法

会让当前线程根据指定的时间暂停,将执行机会让给其他线程

对象的锁依然保持,时间到会自动恢复。

wait()是 Object 类的方法

wait()方法导致当前线程放弃对象的锁,进入对象的等待池

只有调用对象的 notify()或 notifyAll()才能唤醒等待池中的线程进入等锁池,如果线程重获对象锁就可以进入就绪状态。

 

接口和抽象类的区别

抽象类和接口都不能够实例化。

一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。

抽象类可以定义构造器;而接口中不能定义构造器。

抽象类可以有抽象方法和具体方法;接口方法全部都是抽象方法。

抽象类中的成员可以是 private、默认、protected、public 的,而接口中的成员全都是 public 的。

抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。

有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

 

 

TreeMap 和 TreeSet 在排序时如何比较元素?Collections 工具类中的 sort()方法如何比较元素?

TreeSet 要求存放的对象所属的类必须实现 Comparable 接口,该接口提供了比较元素的 compareTo()方法,当插入元素时会回调该方法比较元素的大小。

TreeMap 要求存放的键值对的键必须实现 Comparable 接口从而根据键对元素进行排序。

Collections 工具类的 sort 方法有两种形式:

第一种要求待排序容器中存放的对象实现 Comparable 接口以实现元素的比较;

第二种不强制性要求容器中元素的比较,但是要求传入第二个参数是Comparator 接口的子类型(需要重写 compare 方法实现元素的比较),相当于临时定义的排序规则。

 

ArrayList、Vector、LinkedList 的存储性能和特性

ArrayList 和 Vector 都是数组方式存储数据

数组元素数大于实际存储的数据以便增加元素

按序号索引元素,插入元素涉及数组元素移动

Vector 中的方法由于添加了 synchronized 修饰。

LinkedList 使用双向链表实现存储

按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项

ArrayList 和LinkedList 可以通过Collections 中的 synchronizedList 方法将其转换成线程安全的容器后再使用。

 

 

当一个线程进入一个对象的 synchronized 方法 A 之后,其它线程是否可进入此对象的 synchronized 方法 B?

不能。其它线程只能访问该对象的非同步方法。

非静态方法上的 synchronized 修饰符要求执行方法时要获得对象的锁。

如果已经进入A 方法说明对象锁已经被取走,那么试图进入 B 方法的线程就只能在等锁池(注意不是等待池哦)中等待对象的锁。

 

 

 

List、Map、Set 三个接口存取元素时,各有什么特点?

List 以特定索引来存取元素,可以有重复元素。

Set 不能存放重复元素(用对象的equals()方法来区分元素是否重复)。

Map 保存键值对,映射关系可以是一对一或多对一。

如何实现对象克隆?

1). 实现 Cloneable 接口并重写 Object 类中的 clone()方法;

2). 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现深度克隆,

 

 

解释内存中的栈、堆和方法区的用法。

栈中存放的是局部变量、方法参数、方法帧。线程有私有的栈不对外共享。执行方法时,作为方法帧入栈,当执行完后出栈。

堆中主要用来存放的是对象。为所有的线程所共享。

方法区中存放的都是一些静态的数据,比如static变量、class等。为共享区域。方法区中都是存放的永远唯一的元素。

 

 

列出一些你常见的运行时异常?

ArithmeticException(算术异常)

ClassCastException (类转换异常)

IllegalArgumentException (非法参数异常)

IndexOutOfBoundsException (下标越界异常)

NullPointerException (空指针异常)

SecurityException (安全异常)

 

final、finally、finalize 的区别。

final

(1) 修饰类:表示该类不能被继承;

(2) 修饰方法:表示方法不能被重写;

(3) 修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。

finally

通常放在 try…catch…的后面

这就意味着程序无论正常执行还是发生异常,这里的代码只要 JVM 不关闭都能执行,

可以将释放外部资源的代码写在 finally 块中。

finalize

Object 类中定义的方法

垃圾收集器在销毁对象时调用的,通过重写 finalize()方法可以整理系统资源或者执行其他清理工作。

 

 

 

Java 中会存在内存泄漏吗,请简单描述

理论上 Java 因为有垃圾回收机制不会存在内存泄露问题;

而在实际开发中,可能会存在无用但可达的对象,这些对象不能被 GC 回收,因此也会导致内存泄露的发生。

例如Hibernate 的 Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄露。

 

 

GC 是什么?为什么要有 GC?

对内存堆中已经死亡的或者长时间没有使用的对象进行回收

防止内存泄露,有效的利用可使用的内存。

不能实时的调用垃圾回收器对某个对象进行垃圾回收。

垃圾回收机制有很多种:

分代复制垃圾回收

标记垃圾回收

增量垃圾回收等。

GC采用“分代式垃圾收集”。

将堆内存划分为不同的区域:

伊甸园(Eden):对象诞生的区域。

幸存者乐园(Survivor):在Eden幸存下来的对象。

终身颐养园(Tenured):保存老的幸存对象。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进Tenured时,就会触发一次完全收集(Major-GC)

与垃圾回收相关的 JVM 参数:

-Xms / -Xmx — 堆的初始大小 / 堆的最大大小

-Xmn — 堆中年轻代的大小

-XX:-DisableExplicitGC — 让 System.gc()不产生任何作用

-XX:+PrintGCDetails — 打印 GC 的细节

-XX:+PrintGCDateStamps — 打印 GC 操作的时间戳

-XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小

-XX:NewRatio — 可以设置老生代和新生代的比例

-XX:PrintTenuringDistribution — 设置每次新生代 GC 后输出幸存者乐园中对象年龄的分布

-XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold:设置老年代阀值的初始值和最大值

-XX:TargetSurvivorRatio:设置幸存区的目标使用率

 

静态变量和实例变量的区别

静态变量: 

static 修饰

属于类,也称为类变量

静态变量在内存中有且仅有一个拷贝;

静态变量可以实现让多个对象共享内存。

实例变量:

必须依存于某一实例,通过对象才能访问。

 

事物的四个特点——ACID是靠什么保证的

原子性

由undolog日志进行保证,记录需要回滚的信息,事物回滚时撤销已经执行成功的sql

一致性

由其他三大特征保证

隔离性

是由MVCC多版本并发控制保证

持久性

由redolog保证,mysql修改数据时,会在redolog中记录一份日志数据,就算数据没有保存成功,只要日志保存成功,数据就不会消失

 

 

try{}里有一个 return 语句,那么紧跟在这个 try 后的finally{}里的代码会不会被执行,什么时候被执行,在 return前还是后?

会执行,在方法返回调用者前执行。

如果存在 finally 代码块,try中的 return 语句不会立马返回调用者,而是记录下返回值待 finally 代码块执行完毕之后再向调用者返回其值,然后如果在 finally 中修改了返回值,就会返回修改后的值。

 

Collection 和 Collections 的区别?

Collection 是一个接口,它是 Set、List 等容器的父接口;

Collections 是个一个工具类,这些方法包括对容器的搜索、排序、线程安全化等等。

 

JVM、JRE和JDK的关系

JVM

Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。

JRE

Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包:如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等

JDK

其中包含了Java的开发工具,也包括了JRE。所以安装了JDK,就无需再单独安装JRE了。

面向对象三大特性?

其中Java 面向对象编程三大特性:封装 继承 多态

封装

封装把一个对象的属性私有化

提供一些可以被外界访问的属性的方法

继承

在父类的基础上建立子类

子类可以增加属性方法,也可以用父类的属性方法,但不能选择性地继承。

关于继承如下 3 点请记住:

1. 子类拥有父类非 private 的属性和方法。

2. 子类可以拥有自己属性和方法

3. 子类可以重写父类的方法。

多态

父类的引用指向子类的具体实现调用的实现方法,必须在由程序运行期间才能决定。

实现多态两种形式:

继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

多态实现个必要条件

继承、重写、向上转型。

继承:在多态中必须存在有继承关系的子类和父类。

重写:子类对父类中某些方法进行重新定义。

向上转型:将子类的引用赋给父类对象。

 

Overload和Override的区别。

如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。

如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型

 

 

==equals()的区别。

"=="判断的是两个对象的内存地址是否一样

equals 是 Object 类的方法,Object 对它的实现是比较内存地址,我们可以重写这个方法来自定义 “相等”这个概念。

 

线程池的原理,为什么要创建线程池?

在线程池中维护一组线程,这些线程可以重复利用,以减少线程的创建和销毁的开销。

线程池中的线程被维护在一个队列中,新来的任务会被插入到队列的尾部。当线程池中有空闲线程时,它会从队列的头部取出任务。

最大线程数限制了线程池中最多能有多少个线程同时工作

辅助线程要监控线程池的状态,及时调整线程池的大小。

 

 

Java 有没有 goto?

goto 是 Java 中的保留字,在目前版本的 Java 中没有使用。

 

&和&&的区别?

&运算符有两种用法:(1)按位与;(2)逻辑与。

&&运算符是短路与运算。

逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。

&&之所以称为短路运算是因为,如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

例如在验证用户登录时判定用户名不是 null 而且不是空字符串,应当写为:username != null &&!username.equals(“”),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的 equals 比较,否则会产生空值异常。

 

switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上?

在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的

数组有没有 length()方法?String 有没有 length()方法?

数组没有 length()方法,有 length 的属性。String 有 length()方法。JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。

构造器(constructor)是否可被重写(override)

构造器不能被继承,因此不能被重写,但可以被重载。

两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对

两个值相同,哈希码一定相同,哈希码相同,两个值不一定相同

是否可以继承 String 类?

String 类是 final 类,不可以被继承。

String 和 StringBuilder、StringBuffer 的区别

其中 String 是只读字符串,内容不能被改变。

而 StringBuffer/StringBuilder 类表示的字符串对象可以直接进行修改。

StringBuilder没有被synchronized 修饰

 

 

接口是否可继承接口?抽象类是否可实现接口?抽象类是否可继承具体类?

接口可继承接口,支持多重继承。

抽象类可以实现接口,抽象类可继承具体类也可以继承抽象类。

是否可以继承其它类?是否可以实现接口?

可以继承其他类或实现其他接口

内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制? 

一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。

 

 

 


Java的评论 (共 条)

分享到微博请遵守国家法律