面试频繁受挫,苦修数月深造这份Java面试宝典

面试频繁受挫,苦修数月深造这份Java面试宝典,第1张

📢📢📢📣📣📣
哈喽!大家好,我是【IT邦德】,江湖人称jeames007,10年DBA工作经验
一位上进心十足的【大数据领域博主】!😜😜😜
中国DBA联盟(ACDU)成员,目前从事DBA及程序编程
擅长主流数据Oracle、MySQL、PG 运维开发,备份恢复,安装迁移,性能优化、故障应急处理等。



✨ 如果有对【数据库】感兴趣的【小可爱】,欢迎关注【IT邦德】💞💞💞
❤️❤️❤️感谢各位大可爱小可爱!❤️❤️❤️

文章目录
  • 前言
    • 🚀 1.Java语言有哪些特点?
    • 🚀 2.Java和C++有什么关系,它们有什么区别?
    • 🚀 3.JVM、JRE和JDK的关系是什么?
    • 🚀 4.Java有哪些数据类型?
    • 🚀 5.访问修饰符public、private、protected区别是什么?
    • 🚀 6.String有哪些特性?
    • 🚀 7.关键字final、finally、finalize的区别?
    • 🚀 8.sleep() 方法和 wait() 方法区别和共同点?
    • 🚀 9.讲讲面向对象三大特性?
    • 🚀 10.java 创建对象有哪几种方式?
    • 🚀 11.线程和进程有什么区别?
    • 🚀 12.重载(Overload)和重写(Override)的区别是什么?
    • 🚀 13.什么是反射?优缺点有哪些?
    • 🚀 14.使用泛型的好处是什么?
    • 🚀 15.Java常见的集合有哪些?
    • 🚀 16.HashMap的底层数据结构是什么?
    • 🚀 17.什么是线程死锁?如何避免死锁?
    • 🚀 18.消息队列是什么?

前言 Java在面试中经常被问到,本文总结了面试中的经典问题。



🚀 1.Java语言有哪些特点?

1.面向对象(封装,继承,多态);
2.平台无关性,平台无关性的具体表现在于,Java 是“一次编写,到处运行(Write Once,Run any Where)”的语言,因此采用 Java 语言编写的程序具有很好的可移植性,而保证这一点的正是 Java 的虚拟机机制。


在引入虚拟机之后,Java 语言在不同的平台上运行不需要重新编译。



3.可靠性、安全性;
4.支持多线程。


C++ 语言没有内置的多线程机制,因此必须调用 *** 作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持;
5.支持网络编程并且很方便。


Java 语言诞生本身就是为简化网络编程设计的,因此 Java 语言不仅支持网络编程而且很方便;
6.编译与解释并存;

🚀 2.Java和C++有什么关系,它们有什么区别?

1.都是面向对象的语言,都支持封装、继承和多态;
2.C++ 支持指针,而 Java 没有指针的概念;
3.C++ 支持多继承,而 Java 不支持多重继承,但允许一个类实现多个接口;
4.Java 是完全面向对象的语言,并且还取消了 C/C++ 中的结构和联合,使编译程序更加简洁;
5.Java 自动进行无用内存回收 *** 作,不再需要程序员进行手动删除,而 C++ 中必须由程序释放内存资源,这就增加了程序员的负担。



6.Java 不支持 *** 作符重载, *** 作符重载则被认为是 C++ 的突出特征;
7.Java 允许预处理,但不支持预处理器功能,所以为了实现预处理,它提供了引入语句(import),但它与 C++ 预处理器的功能类似;
8.Java 不支持缺省参数函数,而 C++ 支持;
9.C 和 C++ 不支持字符串变量,在 C 和 C++ 程序中使用“Null”终止符代表字符串的结束。


在 Java 中字符串是用类对象(String 和 StringBuffer)来实现的;
10.goto 语句是 C 和 C++ 的“遗物”,Java 不提供 goto 语句,虽然 Java 指定 goto 作为关键字,但不支持它的使用,这使程序更简洁易读;
11.Java 不支持 C++ 中的自动强制类型转换,如果需要,必须由程序显式进行强制类型转换。


🚀 3.JVM、JRE和JDK的关系是什么?

JDK是(Java Development Kit)的缩写,它是功能齐全的 Java SDK。


它拥有 JRE 所拥有的一切,
还有编译器(javac)和工具(如 javadoc 和 jdb),它能够创建和编译程序。



JRE是Java Runtime Environment缩写,它是运行已编译 Java 程序所需的所有内容的集合,
包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。



但是,它不能用于创建新程序。



JDK包含JRE,JRE包含JVM

🚀 4.Java有哪些数据类型?

Java 语言的数据类型分为两种:基本数据类型和引用数据类型。


🚩🚩 1.基本数据类型
包括 boolean(布尔型)、float(单精度浮点型)、char(字符型)、byte(字节型)、short(短整型)、int(整型)、long(长整型)和 double (双精度浮点型)共 8 种,如下表所示。


🚩🚩 2.引用数据类型
建立在基本数据类型的基础上,包括数组、类和接口。



引用数据类型是由用户自定义,用来限制其他数据的类型。



另外,Java 语言中不支持 C++中的指针类型、结构类型、联合类型和枚举类型。


🚀 5.访问修饰符public、private、protected区别是什么?

Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。



Java 支持 4 种不同的访问权限。



🚩 1.default (即默认,什么也不写):
在同一包内可见,不使用任何修饰符。


使用对象:类、接口、变量、方法。



🚩 2.private :
在同一类内可见。


使用对象:变量、方法。


注意:不能修饰类(外部类)
🚩 3.public :
对所有类可见。


使用对象:类、接口、变量、方法
🚩 4.protected :
对同一包内的类和所有子类可见。


使用对象:变量、方法。


注意:不能修饰类(外部类)。


🚀 6.String有哪些特性?

1.不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何 *** 作,
其实都是创建一个新的对象,再把引用指向该对象。



不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性;
2.常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,
如果下次创建同样的对象时,会直接返回缓存的引用;
3.final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。


🚀 7.关键字final、finally、finalize的区别?

🚩 final 用于修饰变量、方法和类。


final 变量:
被修饰的变量不可变,不可变分为引用不可变和对象不可变,final 指的是引用不可变,
final 修饰的变量必须初始化,通常称被修饰的变量为常量。



final 方法:
被修饰的方法不允许任何子类重写,子类可以使用该方法。



final 类:
被修饰的类不能被继承,所有方法不能被重写。


🚩 finally 用于异常处理

finally 作为异常处理的一部分,它只能在 try/catch 语句中,并且附带一个语句块表示这段语句最终一定被执行(无论是否抛出异常),经常被用在需要释放资源的情况下,System.exit (0) 可以阻断 finally 执行。


🚩 finalize 是在 java.lang.Object 里定义的方法

也就是说每一个对象都有这么个方法,这个方法在 gc 启动,该对象被回收的时候被调用。



一个对象的 finalize 方法只会被调用一次,finalize 被调用不一定会立即回收该对象,所以有可能调用 finalize 后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,
所以不会再次调用 finalize 了,进而产生问题,因此不推荐使用 finalize 方法。


🚀 8.sleep() 方法和 wait() 方法区别和共同点?

🚩 区别点
1.sleep方法:
是Thread类的静态方法,当前线程将睡眠n毫秒,线程进入阻塞状态。


当睡眠时间到了,会解除阻塞,进入可运行状态,等待CPU的到来。


睡眠不释放锁(如果有的话)。



2.wait方法:
是Object的方法,必须与synchronized关键字一起使用,线程进入阻塞状态,当notify或者notifyall被调用后,会解除阻塞。


但是,只有重新占用互斥锁之后才会进入可运行状态。


睡眠时,会释放互斥锁。



3.sleep 方法没有释放锁,而 wait 方法释放了锁 。



4.sleep 通常被用于暂停执行Wait 通常被用于线程间交互/通信
5.sleep() 方法执行完成后,线程会自动苏醒。


或者可以使用 wait(long timeout)超时后线程会自动苏醒。


6.wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify() 或者 notifyAll()
🚩 相同点:两者都可以暂停线程的执行。


🚀 9.讲讲面向对象三大特性?

首选我们看下面向对象和过程的区别

🚩 封装
封装是面向对象的特征之一,是对象和类概念的主要特性。


封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象 *** 作,对不可信的进行信息隐藏。



🚩继承
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。


通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。



🚩多态性
它是指在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,这使得同一个属性或方法在父类及其各个子类中具有不同的含义。


🚀 10.java 创建对象有哪几种方式?

java中提供了以下四种创建对象的方式:
1.new创建新对象
2.通过反射机制
3.采用clone机制
4. 通过序列化机制
前两者都需要显式地调用构造方法。


对于clone机制,需要注意浅拷贝和深拷贝的区别,
对于序列化机制需要明确其实现原理,在java中序列化可以通过实现Externalizable或者Serializable来实现。


🚀 11.线程和进程有什么区别?

线程具有许多传统进程所具有的特征,故又称为轻型进程(Light—Weight Process)或进程元;
而把传统的进程称为重型进程(Heavy—Weight Process),它相当于只有一个线程的任务。



在引入了线程的 *** 作系统中,通常一个进程都有若干个线程,至少包含一个线程。



根本区别:
进程是 *** 作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
🚩资源开销:
每个进程都有独立的代码和数据空间(程序上下文),程序之间的切换会有较大的开销;
线程可以看做轻量级的进程,同一类线程共享代码和数据空间,
每个线程都有自己独立的运行栈和程序计数器(PC),线程之间切换的开销小。



🚩包含关系:
如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;
线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。



🚩内存分配:
同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
🚩影响关系:
一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。



所以多进程要比多线程健壮。



🚩执行过程:
每个独立的进程有程序运行的入口、顺序执行序列和程序出口。



但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,两者均可并发执行

🚀 12.重载(Overload)和重写(Override)的区别是什么?

方法的重载和重写都是实现多态的方式,
区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。



重写发生在子类与父类之间, 重写方法返回值和形参都不能改变,与方法返回值和访问修饰符无关,
即重载的方法不能根据返回类型进行区分。


即外壳不变,核心重写!
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。


返回类型可以相同也可以不同。



每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。



最常用的地方就是构造器的重载。


🚀 13.什么是反射?优缺点有哪些?

🚩🚩 反射的概念

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。


🚩🚩 反射机制的优缺点

优点:能够运行时动态获取类的实例,提高灵活性;可与动态编译结合Class.forName(‘com.mysql.jdbc.Driver.class’);,加载MySQL的驱动类。



缺点:使用反射性能较低,需要解析字节码,将内存中的对象进行解析。



其解决方案是:通过setAccessible(true)关闭JDK的安全检查来提升反射速度;
多次创建一个类的实例时,有缓存会快很多;
ReflflectASM工具类,通过字节码生成的方式加快反射速度

🚀 14.使用泛型的好处是什么?

🚩🚩类型安全
泛型的主要目标是提高 Java 程序的类型安全
编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常
符合越早出错代价越小原则

🚩🚩消除强制类型转换
泛型的一个附带好处是,使用时直接得到目标类型,消除许多强制类型转换
所得即所需,这使得代码更加可读,并且减少了出错机会

🚩🚩潜在的性能收益
由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改所有工作都在编译器中完成
编译器生成的代码跟不使用泛型(和强制类型转换)时所写的代码几乎一致,
只是更能确保类型安全而已

class Cls1 <T>   //定义泛型类
{
	T a;
	public Cls1(T a){
		this.a = a;
	}
	public T getData(){
		return a;
	}
}

public class Test {
	public static void main(String[] args) {
		Cls1<Integer> cls1 = new Cls1<Integer>(20);  //使用泛型类
		System.out.println(cls1.getData());
		
		Cls1<String> cls2 = new Cls1<String>("木易");
		System.out.println(cls2.getData());
	}
}
🚀 15.Java常见的集合有哪些?

Java集合类主要由两个根接口Collection和Map派生出来的,
Collection派生出了三个子接口:List、Set、Queue(Java5新增的队列),
因此Java集合大致也可分成List、Set、Queue、Map四种接口体系。



注意:Collection是一个接口,Collections是一个工具类,Map不是Collection的子接口。


🚩🚩 Java集合框架图如下:

图中,List代表了有序可重复集合,可直接根据元素的索引来访问;
Set代表无序不可重复集合,只能根据元素本身来访问;Queue是队列集合。



Map代表的是存储key-value对的集合,可根据元素的key来访问value。



上图中淡绿色背景覆盖的是集合体系中常用的实现类,
分别是ArrayList、LinkedList、ArrayQueue、HashSet、TreeSet、HashMap、TreeMap等实现类。


🚀 16.HashMap的底层数据结构是什么?

在JDK1.7 和JDK1.8 中有所差别:
在JDK1.7 中,由“数组+链表”组成,数组是 HashMap 的主体,
链表则是主要为了解决哈希冲突而存在的。



在JDK1.8 中,由“数组+链表+红黑树”组成。


当链表过长,
则会严重影响 HashMap 的性能,红黑树搜索时间复杂度是 O(logn),而链表是糟糕的 O(n)


因此,JDK1.8 对数据结构做了进一步的优化,引入了红黑树,
链表和红黑树在达到一定条件会进行转换:当链表超过 8 且数据总量超过 64 才会转红黑树。



将链表转换成红黑树前会判断,如果当前数组的长度小于 64,
那么会选择先进行数组扩容,而不是转换为红黑树,以减少搜索时间。


🚀 17.什么是线程死锁?如何避免死锁?

死锁
多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。



由于线程被无限期地阻塞,因此程序不可能正常终止
死锁必须具备以下四个条件:
1.互斥条件:该资源任意一个时刻只由一个线程占用。



2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。



3.不剥夺条件:线程已获得的资源在末使用完之前不能被其他线程强行剥夺,
只有自己使用完毕后才释放资源。



4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。


如何避免线程死锁?
只要破坏产生死锁的四个条件中的其中一个就可以了
1.破坏互斥条件 这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)
2.破坏请求与保持条件 一次性申请所有的资源。



3.破坏不剥夺条件 占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。



4.破坏循环等待条件 靠按序申请资源来预防。


按某一顺序申请资源,释放资源则反序释放。



锁排序法:(必须回答出来的点) 指定获取锁的顺序,比如某个线程只有获得A锁和B锁,
才能对某资源进行 *** 作,在多线程条件下,如何避免死锁? 通过指定锁的获取顺序,
比如规定,只有获得A锁的线程才有资格获取B锁,按顺序获取锁就可以避免死锁。



这通常被认为是解决死锁很好的一种方法。



5.使用显式锁中的ReentrantLock.try(long,TimeUnit)来申请锁

🚀 18.消息队列是什么?

比如,A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。


同理,B 进程要给 A 进程发送消息也是如此。



1.消息队列是保存在内核中的消息链表: ,在发送数据时,会分成一个一个独立的数据单元,也就是消息体(数据块),消息体是用户自定义的数据类型,消息的发送方和接收方要约定好消息体的数据类型,所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据。


如果进程从消息队列中读取了消息体,内核就会把这个消息体删除。



消息队列生命周期随内核,如果没有释放消息队列或者没有关闭 *** 作系统,消息队列会一直存在,而前面提到的匿名管道的生命周期,是随进程的创建而建立,随进程的结束而销毁。



2.消息队列不适合比较大数据的传输: ,因为在内核中每个消息体都有一个最大长度的限制,同时所有队列所包含的全部消息体的总长度也是有上限。


在 Linux 内核中,会有两个宏定义 MSGMAX 和 MSGMNB,它们以字节为单位,分别定义了一条消息的最大长度和一个队列的最大长度。



3.消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销: 因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另一进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。


大家点赞、收藏、关注、评论啦 👇🏻👇🏻👇🏻微信公众号👇🏻👇🏻👇🏻

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/577851.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-11
下一篇 2022-04-11

发表评论

登录后才能评论

评论列表(0条)

保存