我这里以30道Java基础知识题目,带着大家回顾一下Java基础知识。

1. 面向对象和面向过程的区别

面向过程

长处: 性能比面向对象高,因为类调用时须要实例化,开销比拟大,比拟耗费资源;比方单片机、嵌入式开发、Linux/Unix等个别采纳面向过程开发,性能是最重要的因素。

毛病: 没有面向对象易保护、易复用、易扩大

面向对象

长处: 易保护、易复用、易扩大,因为面向对象有封装、继承、多态性的个性,能够设计出低耦合的零碎,使零碎更加灵便、更加易于保护

毛病: 性能比面向过程低

2. Java语言有哪些特点?

  1. 简略易学;
  2. 面向对象(封装,继承,多态);
  3. 平台无关性(Java虚拟机实现平台无关性);
  4. 可靠性;
  5. 安全性;
  6. 反对多线程(C++语言没有内置的多线程机制,因而必须调用操作系统的多线程性能来进行多线程程序设计,而Java语言却提供了多线程反对);
  7. 反对网络编程并且很不便(Java语言诞生自身就是为简化网络编程设计的,因而Java语言不仅反对网络编程而且很不便);
  8. 编译与解释并存;

3. 什么是JDK?什么是JRE?什么是JVM?三者之间的分割与区别

这几个是Java中很根本很根本的货色,然而我置信肯定还有很多人搞不清楚!为什么呢?因为咱们大多数时候在应用现成的编译工具以及环境的时候,并没有去思考这些货色。

JDK: 顾名思义它是给开发者提供的开发工具箱,是给程序开发者用的。它除了包含残缺的JRE(Java Runtime Environment),Java运行环境,还蕴含了其余供开发者应用的工具包。

JRE: 普通用户而只须要装置JRE(Java Runtime Environment)来运行Java程序。而程序开发者必须装置JDK来编译、调试程序。

JVM: 当咱们运行一个程序时,JVM负责将字节码转换为特定机器代码,JVM提供了内存治理/垃圾回收和平安机制等。这种独立于硬件和操作系统,正是java程序能够一次编写多处执行的起因。

区别与分割:

  1. JDK用于开发,JRE用于运行java程序 ;
  2. JDK和JRE中都蕴含JVM ;
  3. JVM是java编程语言的外围并且具备平台独立性。

4. 什么是字节码?采纳字节码的最大益处是什么?

先看下java中的编译器和解释器:   

Java中引入了虚拟机的概念,即在机器和编译程序之间退出了一层形象的虚构的机器。这台虚构的机器在任何平台上都提供给编译程序一个的独特的接口。

编译程序只须要面向虚拟机,生成虚拟机可能了解的代码,而后由解释器来将虚拟机代码转换为特定零碎的机器码执行。在Java中,这种供虚拟机了解的代码叫做 字节码(即扩大名为 .class的文件),它不面向任何特定的处理器,只面向虚拟机。

每一种平台的解释器是不同的,然而实现的虚拟机是雷同的。Java源程序通过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,而后在特定的机器上运行。这也就是解释了Java的编译与解释并存的特点。

Java源代码---->编译器---->jvm可执行的Java字节码(即虚构指令)---->jvm---->jvm中解释器----->机器可执行的二进制机器码---->程序运行。

采纳字节码的益处: 

Java语言通过字节码的形式,在肯定水平上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比拟高效,而且,因为字节码并不专对一种特定的机器,因而,Java程序毋庸从新编译便可在多种不同的计算机上运行。

5. Java和C++的区别

我晓得很多人没学过C++,然而面试官就是没事喜爱拿咱们Java和C++比呀!没方法!!!就算没学过C++,也要记下来!

  • 都是面向对象的语言,都反对封装、继承和多态
  • Java不提供指针来间接拜访内存,程序内存更加平安
  • Java的类是单继承的,C++反对多重继承;尽管Java的类不能够多继承,然而接口能够多继承。
  • Java有主动内存管理机制,不须要程序员手动开释无用内存

6. 什么是Java程序的主类?应用程序和小程序的主类有何不同?

一个程序中能够有多个类,但只能有一个类是主类。在Java应用程序中,这个主类是指蕴含main()办法的类。而在Java小程序中,这个主类是一个继承自零碎类JApplet或Applet的子类。应用程序的主类不肯定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口点。

7. Java应用程序与小程序之间有那些差异?

简略说应用程序是从主线程启动(也就是main()办法)。applet小程序没有main办法,次要是嵌在浏览器页面上运行(调用init()线程或者run()来启动),嵌入浏览器这点跟flash的小游戏相似。

8. 字符型常量和字符串常量的区别

  1. 模式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的若干个字符
  2. 含意上: 字符常量相当于一个整形值(ASCII值),能够加入表达式运算 字符串常量代表一个地址值(该字符串在内存中寄存地位)
  3. 占内存大小上: 字符常量只占一个字节 字符串常量占若干个字节(至多一个字符完结标记)

9. 结构器Constructor是否可被override

在讲继承的时候咱们就晓得父类的公有属性和构造方法并不能被继承,所以Constructor也就不能被override,然而能够overload,所以你能够看到一个类中有多个构造函数的状况。

10. 重载和重写的区别

重载: 产生在同一个类中,办法名必须雷同,参数类型不同、个数不同、程序不同,办法返回值和拜访修饰符能够不同,产生在编译时。   

重写: 产生在父子类中,办法名、参数列表必须雷同,返回值范畴小于等于父类,抛出的异样范畴小于等于父类,拜访修饰符范畴大于等于父类;如果父类办法拜访修饰符为private则子类就不能重写该办法。

11. Java 面向对象编程三大个性:封装、继承、多态

封装

封装把一个对象的属性私有化,同时提供一些能够被外界拜访的属性的办法,如果不想被外界办法,咱们大可不必提供办法给外界拜访。然而如果一个类没有提供给外界拜访的办法,那么这个类也没有什么意义了。

继承

继承是应用已存在的类的定义作为根底建设新类的技术,新类的定义能够减少新的数据或新的性能,也能够用父类的性能,但不能选择性地继承父类。通过应用继承咱们可能十分不便地复用以前的代码。

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

  1. 子类领有父类非private的属性和办法。
  2. 子类能够领有本人属性和办法,即子类能够对父类进行扩大。
  3. 子类能够用本人的形式实现父类的办法。(当前介绍)。

多态

所谓多态就是指程序中定义的援用变量所指向的具体类型和通过该援用变量收回的办法调用在编程时并不确定,而是在程序运行期间才确定,即一个援用变量倒底会指向哪个类的实例对象,该援用变量收回的办法调用到底是哪个类中实现的办法,必须在由程序运行期间能力决定。

在Java中有两种模式能够实现多态:继承(多个子类对同一办法的重写)和接口(实现接口并笼罩接口中同一办法)。

12. String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?

可变性 

String类中应用字符数组保留字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是应用字符数组保留字符串,char[]value,这两种对象都是可变的。   

线程安全性

String中的对象是不可变的,也就能够了解为常量,线程平安。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共办法。StringBuffer对办法加了同步锁或者对调用的办法加了同步锁,所以是线程平安的。StringBuilder并没有对办法进行加同步锁,所以是非线程平安的。   

性能

每次对String 类型进行扭转的时候,都会生成一个新的String对象,而后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象自身进行操作,而不是生成新的对象并扭转对象援用。雷同状况下应用StirngBuilder 相比应用StringBuffer 仅能取得10%~15% 左右的性能晋升,但却要冒多线程不平安的危险。

对于三者应用的总结:

如果要操作大量的数据用 = String 单线程操作字符串缓冲区 下操作大量数据 = StringBuilder 多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

13. 主动装箱与拆箱

装箱:将根本类型用它们对应的援用类型包装起来;

拆箱:将包装类型转换为根本数据类型;

14. 在一个静态方法内调用一个非动态成员为什么是非法的?

因为静态方法能够不通过对象进行调用,因而在静态方法里,不能调用其余非动态变量,也不能够拜访非动态变量成员。

15. 在Java中定义一个不做事且没有参数的构造方法的作用

Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因而,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将产生谬误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。 

16. import java和javax有什么区别

刚开始的时候JavaAPI所必须的包是java结尾的包,javax过后只是扩大API包来说应用。然而随着工夫的推移,javax逐步的扩大成为Java API的组成部分。然而,将扩大从javax包挪动到java包将是太麻烦了,最终会毁坏一堆现有的代码。因而,最终决定javax包将成为规范API的一部分。

所以,实际上java和javax没有区别。这都是一个名字。

17. 接口和抽象类的区别是什么?

  1. 接口的办法默认是public,所有办法在接口中不能有实现,抽象类能够有非形象的办法
  2. 接口中的实例变量默认是final类型的,而抽象类中则不肯定
  3. 一个类能够实现多个接口,但最多只能实现一个抽象类
  4. 一个类实现接口的话要实现接口的所有办法,而抽象类不肯定
  5. 接口不能用new实例化,但能够申明,然而必须援用一个实现该接口的对象 从设计层面来说,形象是对类的形象,是一种模板设计,接口是行为的形象,是一种行为的标准。

18. 成员变量与局部变量的区别有那些?

  1. 从语法模式上,看成员变量是属于类的,而局部变量是在办法中定义的变量或是办法的参数;成员变量能够被public,private,static等修饰符所润饰,而局部变量不能被访问控制修饰符及static所润饰;然而,成员变量和局部变量都能被final所润饰;
  2. 从变量在内存中的存储形式来看,成员变量是对象的一部分,而对象存在于堆内存,局部变量存在于栈内存
  3. 从变量在内存中的生存工夫上看,成员变量是对象的一部分,它随着对象的创立而存在,而局部变量随着办法的调用而主动隐没。
  4. 成员变量如果没有被赋初值,则会主动以类型的默认值而赋值(一种状况例外被final润饰但没有被static润饰的成员变量必须显示地赋值);而局部变量则不会主动赋值。

19. 创立一个对象用什么运算符?对象实体与对象援用有何不同?

new运算符,new创建对象实例(对象实例在堆内存中),对象援用指向对象实例(对象援用寄存在栈内存中)。一个对象援用能够指向0个或1个对象(一根绳子能够不系气球,也能够系一个气球);一个对象能够有n个援用指向它(能够用n条绳子系住一个气球)。

20. 什么是办法的返回值?返回值在类的办法里的作用是什么?

办法的返回值是指咱们获取到的某个办法体中的代码执行后产生的后果!(前提是该办法可能产生后果)。返回值的作用:接管出后果,使得它能够用于其余的操作!

21. 一个类的构造方法的作用是什么?若一个类没有申明构造方法,改程序能正确执行吗?为什么?

次要作用是实现对类对象的初始化工作。能够执行。因为一个类即便没有申明构造方法也会有默认的不带参数的构造方法。

22. 构造方法有哪些个性?

  1. 名字与类名雷同;
  2. 没有返回值,但不能用void申明构造函数;
  3. 生成类的对象时主动执行,无需调用。

23. 静态方法和实例办法有何不同?

  1. 在内部调用静态方法时,能够应用"类名.办法名"的形式,也能够应用"对象名.办法名"的形式。而实例办法只有前面这种形式。也就是说,调用静态方法能够无需创建对象。
  2. 静态方法在拜访本类的成员时,只容许拜访动态成员(即动态成员变量和静态方法),而不容许拜访实例成员变量和实例办法;实例办法则无此限度.

24. 对象的相等与指向他们的援用相等,两者有什么不同?

对象的相等 比的是内存中寄存的内容是否相等而援用相等 比拟的是他们指向的内存地址是否相等。

25. 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目标是?

帮忙子类做初始化工作。

26. ==与equals(重要)

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(根本数据类型==比拟的是值,援用数据类型==比拟的是内存地址)

equals() : 它的作用也是判断两个对象是否相等。但它个别有两种应用状况:

  • 状况1:类没有笼罩equals()办法。则通过equals()比拟该类的两个对象时,等价于通过“==”比拟这两个对象。
  • 状况2:类笼罩了equals()办法。个别,咱们都笼罩equals()办法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。

举个例子:

public class test1 {    public static void main(String[] args) {            String a = new String("ab"); // a 为一个援用           String b = new String("ab"); // b为另一个援用,对象的内容一样           String aa = "ab"; // 放在常量池中            String bb = "ab"; // 从常量池中查找            if (aa == bb) // true                   System.out.println("aa==bb");           if (a == b) // false,非同一对象                    System.out.println("a==b");     if (a.equals(b)) // true              System.out.println("aEQb");     if (42 == 42.0) { // true                  System.out.println("true");        }   }}

阐明:

  • String中的equals办法是被重写过的,因为object的equals办法是比拟的对象的内存地址,而String的equals办法比拟的是对象的值。
  • 当创立String类型的对象时,虚构机会在常量池中查找有没有曾经存在的值和要创立的值雷同的对象,如果有就把它赋给以后援用。如果没有就在常量池中从新创立一个String对象。

27. hashCode与equals(重要)

面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode办法?”

hashCode()介绍

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引地位。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都蕴含有hashCode() 函数。

散列表存储的是键值对(key-value),它的特点是:能依据“键”疾速的检索出对应的“值”。这其中就利用到了散列码!(能够疾速找到所须要的对象)

为什么要有hashCode

咱们以“HashSet如何查看反复”为例子来阐明为什么要有hashCode:

当你把对象退出HashSet时,HashSet会先计算对象的hashcode值来判断对象退出的地位,同时也会与其余曾经退出的对象的hashcode值作比拟,如果没有相符的hashcode,HashSet会假如对象没有反复呈现。然而如果发现有雷同hashcode值的对象,这时会调用equals()办法来查看hashcode相等的对象是否真的雷同。如果两者雷同,HashSet就不会让其退出操作胜利。如果不同的话,就会从新散列到其余地位。(摘自我的Java启蒙书《Head fist java》第二版)。这样咱们就大大减少了equals的次数,相应就大大提高了执行速度。

hashCode()与equals()的相干规定

  1. 如果两个对象相等,则hashcode肯定也是雷同的
  2. 两个对象相等,对两个对象别离调用equals办法都返回true
  3. 两个对象有雷同的hashcode值,它们也不肯定是相等的
  4. 因而,equals办法被笼罩过,则hashCode办法也必须被笼罩
  5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即便这两个对象指向雷同的数据)

28. Java中的值传递和援用传递

值传递是指对象被值传递,意味着传递了对象的一个正本,即便正本被扭转,也不会影响源对象。(因为值传递的时候,实际上是将实参的值复制一份给形参。)

援用传递是指对象被援用传递,意味着传递的并不是理论的对象,而是对象的援用。因而,内部对援用对象的扭转会反映到所有的对象上。(因为援用传递的时候,实际上是将实参的地址值复制一份给形参。)

29. 简述线程,程序、过程的基本概念。以及他们之间关系是什么?

线程与过程类似,但线程是一个比过程更小的执行单位。一个过程在其执行的过程中能够产生多个线程。与过程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以零碎在产生一个线程,或是在各个线程之间作切换工作时,累赘要比过程小得多,也正因为如此,线程也被称为轻量级过程。

程序是含有指令和数据的文件,被存储在磁盘或其余的数据存储设备中,也就是说程序是动态的代码。

过程是程序的一次执行过程,是零碎运行程序的根本单位,因而过程是动静的。零碎运行一个程序即是一个过程从创立,运行到沦亡的过程。简略来说,一个过程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个过程还占有某些系统资源如CPU工夫,内存空间,文件,文件,输入输出设施的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。 线程是过程划分成的更小的运行单位。线程和过程最大的不同在于基本上各过程是独立的,而各线程则不肯定,因为同一过程中的线程极有可能会相互影响。从另一角度来说,过程属于操作系统的领域,次要是同一段时间内,能够同时执行一个以上的程序,而线程则是在同一程序内简直同时执行一个以上的程序段。

30. 线程有哪些根本状态?这些状态是如何定义的?

  1. 新建(new):新创建了一个线程对象。
  2. 可运行(runnable):线程对象创立后,其余线程(比方main线程)调用了该对象的start()办法。该状态的线程位于可运行线程池中,期待被线程调度选中,获 取cpu的使用权。
  3. 运行(running):可运行状态(runnable)的线程取得了cpu工夫片(timeslice),执行程序代码。
  4. 阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu使用权,也即让出了cpu timeslice,临时进行运行。直到线程进入可运行(runnable)状态,才有 机会再次取得cpu timeslice转到运行(running)状态。阻塞的状况分三种: (一). 期待阻塞:运行(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)状态。
  5. 死亡(dead):线程run()、main()办法执行完结,或者因异样退出了run()办法,则该线程完结生命周期。死亡的线程不可再次复活。

备注: 能够用早起坐地铁来比喻这个过程:

还没起床:sleeping

起床拾掇好了,随时能够坐地铁登程:Runnable

等地铁来:Waiting

地铁来了,但要排队上地铁:I/O阻塞

上了地铁,发现临时没座位:synchronized阻塞

地铁上找到座位:Running

达到目的地:Dead

对于Java根底面试题,你学废了么?