欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  Java

分享java的一些基础面试题

程序员文章站 2022-03-19 17:07:07
...

1.保存数据的地方

寄存器、栈、堆、静态存储、常量存储(常量池 String a = “abc” a在栈里、“abc”在常量池里)、非RAM存储

2.基本数据类型

作为类的成员自动初始化为默值

boolean 1 默认false

byte 8 一个字节 \u0000

char 16 一个字符 0

short 16 0

int 32 0

float 32 0.0f

long 64 0L

double 64 0.0d

3.高精度数字的类

BigInteger 、Bigdecimal 精度高、速度慢

4.java垃圾处理

Java 有一个特别的“垃圾收集器”,它会查找用 new 创建的所有对象,并辨别其中哪些不再被引用。随后,它会自动释放由那些闲置对象占据的内存,以便能由新对象使用。

5.static执行顺序

父类的 static 成员变量和 static 语句

子类的static 成员变量和 static 语句

父类的 static 成员变量 static 语句块

父类的构造方法

子类的非 static 成员变量 和非 static 语句块

子类的构造方法

static只执行一次。第一次new的时候执行)

6.集合类

分享java的一些基础面试题

Vector会自动增长的数组,查询效率高,增删效率低,线程安全,速度较慢,增长为原来的一倍。

ArrayList会自动增长的数组,查询效率高,增删效率低,线程不安全的,速度快,增长为原来的0.5倍。

LinkedList双向循环链表,查询效率低,增删效率高,线程不安全。

HashMap 为链表散列即数组与链表的结合体 允许null值,线程不安全,效率高。

TreeMap为二叉排序树实现,利用Key排序。

LinkedHashMap 为哈希表和链表实现,是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap

Hashtable线程安全,效率低,不允许null值。

Set 为不可重复的:

TreeSet基于TreeMap实现,为有序的,线程不安全的。

HashSet 基于HashMap实现,HashMapkey

LinkedHashSet基于LinkedHashMap实现 ,是有序的。

7.Map的遍历

使用 entrySet 遍历 Map 类集合 KV,而不是 keySet 方式进行遍历。
说明: keySet 其实是遍历了 2 次,一次是转为 Iterator 对象,另一次是从 hashMap 中取出
key 所对应的 value。而 entrySet 只是遍历了一次就把 key value 都放到了 entry 中,效
率更高。如果是 JDK8,使用 Map.foreach 方法。
正例: values()返回的是 V 值集合,是一个 list 集合对象; keySet()返回的是 K 值集合,是
一个 Set 集合对象; entrySet()返回的是 K-V 值组合集合。

1entrySet实现了Set接口,里面存放的是键值对。一个K对应一个V
2,用来遍历map的一种方法。
Set<Map.Entry<String, String>> entryseSet=map.entrySet();
for (Map.Entry<String, String> entry:entryseSet) {
System.out.println(entry.getKey()+","+entry.getValue());
}
通过getKey()得到KgetValue得到V

3,还有一种是keySet
Set<String> set = map.keySet();
for (String s:set) {
System.out.println(s+","+map.get(s));
}

二、IO系统

分享java的一些基础面试题

桥梁流:

InputStreamReader将字节流转换成字符流。(读为转换成字符流)

OutputStreamWriter将字符流转换成字节流(写为转换为字节流)

流分类

使用分类

字节输入流

字节输出流

字符输入流

字符输出流

抽象基类

InputStream

OutputStream

Reader

Writer

节点流

访问文件

FileInputStream

FileOutStream

FileReader

FileWriter

访问数值

ByteArrayInputStream

ByteArrayOutStream

CharArrayReader

CharArrayWriter

访问管道(线程交互)

PipedInputStream

PipedOutStream

PipedReader

PipedWriter

访问字符串

StringReader

StringWriter

处理流

缓冲流

BufferedInputStream

BufferedOutputStream

BufferedReader

BufferedWriter

转换流

InputStreamReader

OutputStreamWriter

对象流

ObjectInputStream

ObjectOutputStream

抽象基类(过滤)

FilterInputStream

FilterOutputStream

FilterReader

FilterWriter

打印流

PrintStream

PrintWriter

推回输入流

PushbackInputStream

PushbackReader

特殊流

DataInputStream

DataOutputStream

1.Java IO是采用的是装饰模式,即采用处理流来包装节点流的方式,来达到代码通用性。

2.处理流和节点流的区分方法,节点流在新建时需要一个数据源(文件、网络)作为参数,而处理流需要一个节点流作为参数。

3.处理流的作用就是提高代码通用性,编写代码的便捷性,提高性能。

4.节点流都是对应抽象基类的实现类,它们都实现了抽象基类的基础读写方法。其中read()方法如果返回-1,代表已经读到数据源末尾。

1. 以字节为单位的输入流的框架图

下面,是以字节为单位的输入流的框架图。

分享java的一些基础面试题

从中,我们可以看出。
(01) InputStream 是以字节为单位的输入流的超类。InputStream提供了read()接口从输入流中读取字节数据。
(02) ByteArrayInputStream 是字节数组输入流。它包含一个内部缓冲区,该缓冲区包含从流中读取的字节;通俗点说,它的内部缓冲区就是一个字节数组,而ByteArrayInputStream本质就是通过字节数组来实现的。
(03) PipedInputStream 是管道输入流,它和PipedOutputStream一起使用,能实现多线程间的管道通信。
(04) FilterInputStream 是过滤输入流。它是DataInputStreamBufferedInputStream的超类。
(05) DataInputStream 是数据输入流。它是用来装饰其它输入流,它“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”。
(06) BufferedInputStream 是缓冲输入流。它的作用是为另一个输入流添加缓冲功能。
(07) File 是“文件”和“目录路径名”的抽象表示形式。关于File,注意两点:
a), File不仅仅只是表示文件,它也可以表示目录!
b), File虽然在io保重定义,但是它的超类是Object,而不是InputStream
(08) FileDescriptor 是“文件描述符”。它可以被用来表示开放文件、开放套接字等。
(09) FileInputStream 是文件输入流。它通常用于对文件进行读取操作。
(10) ObjectInputStream 是对象输入流。它和ObjectOutputStream一起,用来提供对“基本数据或对象”的持久存储。


2. 以字节为单位的输出流的框架图

下面,是以字节为单位的输出流的框架图。

分享java的一些基础面试题

从中,我们可以看出。以字节为单位的输出流的公共父类是OutputStream
(01) OutputStream 是以字节为单位的输出流的超类。OutputStream提供了write()接口从输出流中读取字节数据。
(02) ByteArrayOutputStream 是字节数组输出流。写入ByteArrayOutputStream的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray() toString() 获取数据。
(03) PipedOutputStream 是管道输出流,它和PipedInputStream一起使用,能实现多线程间的管道通信。
(04) FilterOutputStream 是过滤输出流。它是DataOutputStreamBufferedOutputStreamPrintStream的超类。
(05) DataOutputStream 是数据输出流。它是用来装饰其它输出流,它“允许应用程序以与机器无关方式向底层写入基本 Java 数据类型”。
(06) BufferedOutputStream 是缓冲输出流。它的作用是为另一个输出流添加缓冲功能。
(07) PrintStream 是打印输出流。它是用来装饰其它输出流,能为其他输出流添加了功能,使它们能够方便地打印各种数据值表示形式。
(08) FileOutputStream 是文件输出流。它通常用于向文件进行写入操作。
(09) ObjectOutputStream 是对象输出流。它和ObjectInputStream一起,用来提供对“基本数据或对象”的持久存储。

三、多线程

分享java的一些基础面试题

生命周期

线程共包括以下5种状态。
1. 新建状态(New) : 线程对象被创建后,就进入了新建状态。例如,Thread thread = new Thread()
2. 就绪状态(Runnable): 也被称为“可执行状态”。线程对象被创建后,其它线程调用了该对象的start()方法,从而来启动该线程。例如,thread.start()。处于就绪状态的线程,随时可能被CPU调度执行。
3. 运行状态(Running) : 线程获取CPU权限进行执行。需要注意的是,线程只能从就绪状态进入到运行状态。
4. 阻塞状态(Blocked) : 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
(01) 等待阻塞 -- 通过调用线程的wait()方法,让线程等待某工作的完成。
(02) 同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态。
(03) 其他阻塞 -- 通过调用线程的sleep()join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
5. 死亡状态(Dead) : 线程执行完了或者因异常退出了run()方法,该线程结束生命周期

2.start() run()的区别说明

//继承Thread

class MyThread extends Thread{

public void run(){

...

}

};

MyThread mythread = new MyThread();

//实现Runnable

class MyThread implements Runnable{

public void run(){

...

}

};

MyThread mt=new MyThread();

Thread t1=new Thread(mt);

mythread.start()会启动一个新线程,并在新线程中运行run()方法。
mythread.run()则会直接在当前线程中运行run()方法,并不会启动一个新线程来运行run()

3.synchronized

我们将synchronized的基本规则总结为下面3条,并通过实例对它们进行说明。
第一条: 当一个线程访问某对象“synchronized方法或者“synchronized代码块时,其他线程对该对象的该“synchronized方法或者“synchronized代码块的访问将被阻塞。
第二条: 当一个线程访问某对象“synchronized方法或者“synchronized代码块时,其他线程仍然可以访问该对象的非同步代码块。
第三条: 当一个线程访问某对象“synchronized方法或者“synchronized代码块时,其他线程对该对象的其他的“synchronized方法或者“synchronized代码块的访问将被阻塞。

4.wait(), notify(), notifyAll()

notify()-- 唤醒在此对象监视器上等待的单个线程。
notifyAll()-- 唤醒在此对象监视器上等待的所有线程。
wait()-- 让当前线程处于等待(阻塞)状态直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,当前线程被唤醒(进入就绪状态”)
wait(long timeout)-- 让当前线程处于等待(阻塞)状态直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量,当前线程被唤醒(进入就绪状态”)
wait(long timeout, int nanos)-- 让当前线程处于等待(阻塞)状态直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量,当前线程被唤醒(进入就绪状态”)

5.yield()介绍

yield()的作用是让步。它能让当前线程由运行状态进入到就绪状态,从而让其它具有相同优先级的等待线程获取执行权;但是,并不能保证在当前线程调用yield()之后,其它具有相同优先级的线程就一定能获得执行权;也有可能是当前线程又进入到运行状态继续运行!

6.sleep()介绍

sleep() 定义在Thread.java中。
sleep() 的作用是让当前线程休眠,即当前线程会从运行状态进入到休眠(阻塞)状态sleep()会指定休眠时间,线程休眠的时间会大于/等于该休眠时间;在线程重新被唤醒时,它会由阻塞状态变成就绪状态,从而等待cpu的调度执行。

我们知道,wait()的作用是让当前线程由运行状态进入等待(阻塞)状态的同时,也会释放同步锁。而sleep()的作用是也是让当前线程由运行状态进入到休眠(阻塞)状态
但是,wait()会释放对象的同步锁,而sleep()则不会释放锁。
下面通过示例演示sleep()是不会释放锁的。

我们知道,wait()的作用是让当前线程由运行状态进入等待(阻塞)状态的同时,也会释放同步锁。而yield()的作用是让步,它也会让当前线程离开运行状态。它们的区别是:
(01) wait()是让线程由运行状态进入到等待(阻塞)状态,而yield()是让线程由运行状态进入到就绪状态
(02) wait()是会线程释放它所持有对象的同步锁,而yield()方法不会释放锁。

7.join()介绍

join() 定义在Thread.java中。
join() 的作用:让主线程等待子线程结束之后才能继续运行。这句话可能有点晦涩,我们还是通过例子去理解:

// 主线程public class Father extends Thread {

public void run() {

Son s = new Son();

s.start();

s.join();

...

}

}// 子线程public class Son extends Thread {

public void run() {

...

}

}

它的源码就是当子线程是活的(isAlive())主线程就不停的等待( wait(0))

8.interrupt()和终止线程的方式

interrupt()的作用是中断本线程。本线程中断自己是被允许的;其它线程调用本线程的interrupt()方法时,会通过checkAccess()检查权限。这有可能抛出SecurityException异常。

如果本线程是处于阻塞状态:调用线程的wait(), wait(long)wait(long, int)会让它进入等待(阻塞)状态,或者调用线程的join(), join(long), join(long, int), sleep(long), sleep(long, int)也会让它进入阻塞状态。若线程在阻塞状态时,调用了它的interrupt()方法,那么它的中断状态会被清除并且会收到一个InterruptedException异常。例如,线程通过wait()进入阻塞状态,此时通过interrupt()中断该线程;调用interrupt()会立即将线程的中断标记设为“true”,但是由于线程处于阻塞状态,所以该中断标记会立即被清除为“false”,同时,会产生一个InterruptedException的异常。

如果线程被阻塞在一个Selector选择器中,那么通过interrupt()中断它时;线程的中断标记会被设置为true,并且它会立即从选择操作中返回。

如果不属于前面所说的情况,那么通过interrupt()中断线程时,它的中断标记会被设置为“true”

中断一个已终止的线程不会产生任何操作。

8.1 终止处于“阻塞状态”的线程

通常,我们通过中断方式终止处于阻塞状态的线程。
当线程由于被调用了sleep(), wait(), join()等方法而进入阻塞状态;若此时调用线程的interrupt()将线程的中断标记设为true。由于处于阻塞状态,中断标记会被清除,同时产生一个InterruptedException异常。将InterruptedException放在适当的为止就能终止线程

8.2 终止处于“运行状态”的线程

通常,我们通过标记方式终止处于运行状态的线程。其中,包括中断标记额外添加标记
(01) 通过中断标记终止线程。
形式如下:

@Overridepublic void run() {

while (!isInterrupted()) {

// 执行任务... }

}

说明:isInterrupted()是判断线程的中断标记是不是为true。当线程处于运行状态,并且我们需要终止它时;可以调用线程的interrupt()方法,使用线程的中断标记为true,即isInterrupted()会返回true。此时,就会退出while循环。
注意:interrupt()并不会终止处于运行状态的线程!它会将线程的中断标记设为true

(02) 通过额外添加标记
形式如下:

private volatile boolean flag= true;protected void stopTask() {

flag = false;

}

@Overridepublic void run() {

while (flag) {

// 执行任务... }

}

说明:线程中有一个flag标记,它的默认值是true;并且我们提供stopTask()来设置flag标记。当我们需要终止该线程时,调用该线程的stopTask()方法就可以让线程退出while循环。
注意:将flag定义为volatile类型,是为了保证flag的可见性。即其它线程通过stopTask()修改了flag之后,本线程能看到修改后的flag的值。

最后谈谈 interrupted() isInterrupted()
interrupted() isInterrupted()都能够用于检测对象的中断标记
区别是,interrupted()除了返回中断标记之外,它还会清除中断标记(即将中断标记设为false);而isInterrupted()仅仅返回中断标记

9.线程优先级和守护线程

每个线程都有一个优先级。高优先级线程会优先于低优先级线程执行。每个线程都可以被标记为一个守护进程或非守护进程。在一些运行的主线程中创建新的子线程时,子线程的优先级被设置为等于创建它的主线程的优先级,当且仅当创建它的主线程是守护线程子线程才会是守护线程

Java虚拟机启动时,通常有一个单一的非守护线程(该线程通过是通过main()方法启动)。JVM会一直运行直到下面的任意一个条件发生,JVM就会终止运行:

(01) 调用了exit()方法,并且exit()有权限被正常执行。

(02) 所有的非守护线程都死了(JVM中仅仅只有守护线程”)

每一个线程都被标记为守护线程用户线程。当只有守护线程运行时,JVM会自动退出。

以上就是分享java的一些基础面试题的详细内容,更多请关注其它相关文章!