1.面向对象和面向过程的区别?
- 面向过程:面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消 耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等 一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。
- 面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特 性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,面向对象性 能比面向过程低。
2.Java 语言有哪些特点?
- 面向对象(封装,继承,多态);
- 平台无关性( Java 虚拟机实现平台无关性);
- 可靠性;
- 安全性;
- 支持多线程;
- 支持网络编程;
- 编译与解释并存;
3.请解释什么是JVM、JDK、JRE ?
-
JVM
Java虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM有针对不同系统的特定实现(Windows, Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。
- 首先,JVM 类加载器首先加载字节码文件;
- 然后,通过解释器逐行解释执行;(这种方式的执行速度会相对比较慢)
- 因为,有些方法和代码块是经常需要被调用的(热点代码),所以后面引进了 JIT 编译器;
- JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。
- Java 是编译与解释共存的语言
-
JDK
JDK是Java Development Kit,它是功能齐全的Java SDK。它拥有JRE所拥有的一切,还有编译器 (javac)和工具(如javadoc和jdb)。它能够创建和编译程序。 -
JRE
JRE 是 Java运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java虚拟机 (JVM),Java类库,java命令和其他的一些基础构件。但是,它不能用于创建新程序。
4.什么是字节码?采用字节码的好处是什么?
在 Java 中,JVM可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。 Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特 点。所以 Java 程序运行时比较高效,而且,由于字节码并不针对一种特定的机器,因此,Java程序无须重新编译便可在多种 不同操作系统的计算机上运行。
5.Oracle JDK 和 OpenJDK 有什么区别?
- Oracle JDK 大概每 6 个月发一次主要版本,而 OpenJDK 版本大概每三个月发布一次;
- OpenJDK 是一个参考模型并且是完全开源的,而 Oracle JDK 是 OpenJDK 的一个实现,并不 是完全开源的;
- Oracle JDK 比 OpenJDK 更稳定。OpenJDK 和 Oracle JDK 的代码几乎相同,但 Oracle JDK 有更多的类和一些错误修复。因此,如果您想开发企业/商业软件,我建议您选择 Oracle JDK, 因为它经过了彻底的测试和稳定。
- 在响应性和 JVM 性能方面,Oracle JDK 与 OpenJDK 相比提供了更好的性能;
- Oracle JDK 不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支 持来获取最新版本;
- Oracle JDK 根据二进制代码许可协议获得许可,而 OpenJDK 根据 GPL v2 许可获得许可。
6.Java 和 C++的区别?
- 都是面向对象的语言,都支持封装、继承和多态;
- Java 不提供指针来直接访问内存,程序内存更加安全;
- Java 的类是单继承的,C++ 支持多重继承;
- Java 的类不可以多继承,但是接口可以多继承;
- Java 有自动内存管理机制,不需要程序员手动释放无用内存
7.字符型常量和字符串常量的区别?
- 形式上: 字符常量是单引号引起的一个字符; 字符串常量是双引号引起的若干个字符;
- 含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址 值(该字符串在内存中存放位置);
-
内存大小:字符常量只占 2 个字节; 字符串常量占若干个字节;
8.构造器 Constructor 是否可被 override?
- 父类的私有属性和构造方法并不能被继承,所以 Constructor 也就不能被 override(重写)
- 但是,可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况
9.重载和重写的区别
- 重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回 值和访问修饰符可以不同,发生在编译时。
- 重写: 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常 范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类 就不能重写该方法。
10.Java 面向对象编程三大特性: 封装 继承 多态
- 封装: 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性 不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的 方法,那么这个类也没有什么意义了。
- 继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据 或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方 便地复用以前的代码。
- 多态:多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用 在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对 象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。 在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同 一方法)。
11.String、StringBuffer 和 StringBuilder 的区别是什么?
- 可变性
- String 类中使用 final 关键字修饰字符数组来保存字符串,所以 String 对象是不可变的;
- StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中 也是使用字符数组保存字符串, 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
- 线程安全性
- String 中的对象是不可变的,也就可以理解为常量,线程安全。
- AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本 操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了 同步锁或者对调用的方法加了同步锁,所以是线程安全的。
- StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
- 性能
- 每次对 String 进行改变的时候,都会生成一个新的 String 对象,然后指向新的 String 对象。
- StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升
- StringBuilder > StringBuffer > String
- 对于三者使用的总结
- 操作少量的数据: 适用String
- 单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder
- 多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer
12.自动装箱与拆箱
- 装箱: 将基本类型用它们对应的引用类型包装起来;
- 拆箱:将包装类型转换为基本数据类型;
13.在一个静态方法内调用一个非静态成员为什么是非法的?
由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不 可以访问非静态变量成员。
14.在 Java 中定义一个空无参构造方法的作用?
Java 程序在执行子类的构造方法之前,如果没有用 super()来调用父类特定的构造方法,则会调 用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的 构造方法中又没有用 super()来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个空无参构造 方法。
15.接口和抽象类的区别是什么?
- 接口的方法默认是 public,所有方法均为抽象方法(Java 8 开始,接口中可以包含default默认方 法),而抽象类可以有非抽象的方法。
- 接口中除了static、final变量,不能有其他变量,而抽象类中则不一定。
- 一个类可以实现多个接口,但只能实现一个抽象类。接口自己本身可以通过extends关键字扩展 多个接口。
- 接口方法默认修饰符是public,抽象方法可以有public、protected和default这些修饰符(抽象 方法就是为了被重写所以不能使用private关键字修饰!)。
- 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为 的规范。
16.成员变量与局部变量的区别有哪些?
- 从语法形式上看:成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成 员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
- 从变量在内存中的存储方式来看:如果成员变量是使用static修饰的,那么这个成员变量是属于类 的,如果没有使用static修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则 存在于栈内存。
- 从变量在内存中的生存时间上看:成员变量是对象的一部分,它随着对象的创建而存在,而局部 变量随着方法的调用而自动消失。
- 成员变量如果没有被赋初值:则会自动以类型的默认值而赋值(一种情况例外:被 final 修饰的成 员变量也必须显式地赋值),而局部变量则不会自动赋值。
17.创建一个对象用什么运算符?对象实体与对象引用有何不同?
- new运算符,new创建对象实例(对象实例在堆内存中);
- 对象引用指向对象实例(对象引用存放在栈内存中);
- 一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);
- 一个对象可以有n个引用指向它(可以用n条绳子系住一个气球);
18.构造方法有哪些特性?
- 构造方法名字与类名相同。
- 没有返回值,但不能用void声明构造函数。
- 生成类的对象时自动执行,无需调用。
19.静态方法和实例方法有何不同?
- 在外部调用静态方法时,可以使用”类名.方法名”的方式,也可以使用”对象名.方法名”的方式。 而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
- 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允 许访问实例成员变量和实例方法;实例方法则无此限制。
20.== 和 equals的区别
- == : 它的作用是判断两个对象的地址是不是相等。即判断两个对象是不是同一个对象。(基本 数据类型==比较的是值,引用数据类型==比较的是内存地址)
- equals( ) : 它的作用也是判断两个对象是否相等,它不能用于比较基本数据类型的变量。
- 一般有两种使用情况:
情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过 “==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容 是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
21.hashCode( ) 与 equals( )
- 为什么重写 equals 时必须重写 hashCode 方法?
hashCode( ) 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希 码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就 意味着Java中的任何类都包含有hashCode() 函数。 - hashCode()与equals()的相关规定
①如果两个对象相等,则hashcode一定也是相同的
② 两个对象相等,对两个对象分别调用equals方法都返回true
③ 两个对象有相同的hashcode值,它们也不一定是相等的
④ 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
⑤ hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
22.关于 final 关键字的一些总结
- final关键字主要用在三个地方:变量、方法、类。
① 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如 果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
② 当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定 为final方法。
③ 使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二 个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞 大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行 这些优化了)。类中所有的private方法都隐式地指定为final。
23.Java 中的异常处理
- 在 Java 中,所有的异常都有一个共同的父类 java.lang包中的 Throwable类。
- Throwable 有两个重要的子类:Exception(异常) 和 Error(错误)。异常和错误的本质区 别,异常能被程序本身处理,错误是无法处理
- Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码 编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟 机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出 现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
- Exception(异常):是程序本身可以处理的异常。Exception 类有一个重要的子类 RuntimeException。RuntimeException 异常由Java虚拟机抛出。NullPointerException(要访问 的变量没有引用任何对象时,抛出该异常)、ArithmeticException(算术运算异常,一个整数 除以0时,抛出该异常)和 ArrayIndexOutOfBoundsException (下标越界异常)。
异常处理 - try 块: 用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally 块。
- catch 块: 用于处理try捕获到的异常。
- finally 块: 无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇 到return语句时,finally语句块将在方法返回之前被执行。
- throw:抛出异常对象
- throws:在方法定义中声明,可能抛出的异常类型
在以下4种特殊情况下,finally块不会被执行 - 在finally语句块第一行发生了异常。 因为在其他行,finally块还是会得到执行
- 在前面的代码中用了System.exit(int)已退出程序。 exit是带参函数 ;若该语句在异常语句之后, finally会执行
- 程序所在的线程死亡。
- 关闭CPU。