Java 面试题整理《基础篇》,java 面试宝典 pdf 百度云
重载在同一个类中,方法名相同,参数不同(参数的个数、顺序、类型不同),?法返回值和访问修饰符可以不同。
方法重写的前提:继承,要求方法名、参数列表、返回值类型必须相同,子类的修饰符大于等于父类,抛出的异常范围?于等于?类。
重写的返回值类型如果?法的返回类型是 void 和基本数据类型,则返回值重写时不可修改。但是如果?法的返回值是引?类型,重写时是可以返回该引?类型的?类的。
构造?法?法被重写,但是可以重载,一个类中可以出现多个构造函数
1.面向对象
面向对象(OOP)就是 Java 语言的基础,也是 Java 语言的重要特性。面向对象的概念:生活中的一切事物都可以被称之为对象,生活中随处可见的事物就是一个对象,我们可以将这些事物的状态特征(属性)以及行为特征(方法)提取并出来,并以固定的形式表示。
2.简单好用
Java 语言是由 C 和 C++演变而来的,它省略了 C 语言中所有的难以理解、容易混淆的特性(比如指针),变得更加严谨、简洁、易使用。
3.健壮性
Java 的安全检查机制,将许多程序中的错误扼杀在摇蓝之中。 另外,在 Java 语言中还具备了许多保证程序稳定、健壮的特性(强类型机制、异常处理、垃圾的自动收集等),有效地减少了错误,使得 Java 应用程序更加健壮。
4.安全性
Java 通常被用在网络环境中,为此,Java 提供了一个安全机制以防恶意代码的攻击,从而可以提高系统的安全性。
5.平台无关性
Java 平台无关性由 Java 虚拟机实现,Java 软件可以不受计算机硬件和操作系统的约束而在任意计算机环境下正常运行。
6.支持多线程
在 C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持。多线程机制使应用程序在同一时间并行执行多项任务,该机制使得程序能够具有更好的交互性、实时性。
7.分布式(支持网络编程)
Java 语言具有强大的、易于使用的网络能力,非常适合开发分布式计算的程序。java 中提供了网络应用编程接口(java.net),使得我们可以通过 URL、Socket 等远程访问对象。
8.编译与解释共存
Java 是编译与解释共存的语言
JDK:Java Development Kit 的简称,java 开发工具包,是 Sun Microsystems 针对 Java 开发员的产品,提供了 java 的开发环境和运行环境,JDK 中包含 JRE,在 JDK 的安装目录中可以找到一个 jre 的目录。
JRE:Java Runtime Environment 的简称,是运行基于 Java 语言编写的程序所不可缺少的运行环境。通过它,Java 的开发者才得以将自己开发的程序发布到用户手中,让用户使用。在 jre 文件中有 bin 和 lib 文件夹,我们可以认为 bin 文件夹对应的就是 JVM,而 lib 则对应 JVM 工作所需要的类库。
JVM:java virtual machine 简称,是我们常说的 java 虚拟机,它是整个 java 实现跨平台的最核心的部分,所有的 java 程序会首先被编译为 .class 的类文件(字节码文件),这种类文件可以在虚拟机上执行。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 Java 虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
需要运行 java 程序,只需安装 JRE 就可以了
需要编写 java 程序,需要安装 JDK
字节码文件:
字节码文件是一种可以 JVM 上运行的文件(文件扩展名为 .class ),它不?向任何特定的处理器,只?向虚拟机。Java 语?通过字节码的?式,在?定程度上解决了传统解释型语?执?效率低的问题,同时?保留了解释型语?可移植的特点。所以 Java 程序运?时比较?效,?且,由于字节码并不针对?种特定的机器,因此,Java 程序?须重新编译便可在多种不同操作系统的计算机上运?
String、StringBuffer 和 StringBuilder 的区别?
可变性:
String 类中使? final 关键字修饰字符数组来保存字符串,所以 String 对象是不可变的,每次操作都会产生新对象。? StringBuilder 与 StringBuffer 都继承? AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使?字符数组保存字符串 char[]value 但是没有? final 关键字修饰,所以这两种对象都是可变的。
线程安全:
String 中的对象是不可变的,也就可以理解为常量,线程安全。StringBuilder 与 StringBuffer 的构造?法都是调??类构造?法也就是 AbstractStringBuilder(其中定义了一些字符串的基本操作,本身是线程安全的) 实现的。StringBuffer 对?法加了同步锁或者对调?的?法加了同步锁(synchronized),所以是线程安全的。StringBuilder 并没有对?法进?加同步锁,所以是?线程安全的。
性能:
每次对 String 类型进?改变的时候,都会?成?个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进?操作,?不是?成新的对象并改变对象引?。相同情况下使? StringBuilder 相?使? StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的?险。
对于三者使?的总结:
1. 操作少量的数据: 适? String
2. 单线程操作字符串缓冲区下操作?量数据: 适? StringBuilder
3. 多线程操作字符串缓冲区下操作?量数据: 适? StringBuffer
抽象类:如果一个类里有抽象方法,那么这个类只能是抽象类,抽象类里可以没有抽象方法,抽象方法只能申明,不能实现。
接口:在 Java 中接口就是一个规范,是一种更加抽象化的抽象类。需要被类实现。
两者区别:
?个类可以实现多个接?,但只能实现?个抽象类。接?本身也可以继承接口进行扩展。
接?中只能定义公共的静态常量,不能有其他变量,?法默认是 public ,所有?法在接?中不能有实现(Java 8 开始接口?法可以有默认实现);抽象类中可以定义普通变量,抽象方法需要被实现,不能是静态的,也不能是私有的,可以使用 public 、 protected 和 default 这些修饰符修饰。
抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。
从设计层?来说,抽象是对类的抽象,是?种模板设计(is-a),?接?是对?为的抽象,是?种?为的规范(like-a)。
相同点:
抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。
从语法形式上看:成员变量是属于类的,?局部变量是在?法中定义的变量或是?法的参数;成员变量可以被 public , private , static 等修饰符所修饰,?局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。
从变量在内存中的存储?式来看:如果成员变量是使? static 修饰的,那么这个成员变量是属于类的,如果没有使? static 修饰,这个成员变量是属于实例的。对象存于堆内存,如果局部变量类型为基本数据类型,那么存储在栈内存,如果为引?数据类型,那存放的是指向堆内存对象的引?或者是指向常量池中的地址。
从变量在内存中的?存时间上看:成员变量是对象的?部分,它随着对象的创建?存在,?局部变量随着?法的调???动消失。
**成员变量如果没有被赋初值:则会?动以类型的默认值?赋值(?种情况例外:被 fina
l 修饰的成员变量也必须显式地赋值),?局部变量则不会?动赋值。**
==
: 比较两个对象是否相等,本质是比较两者的值是否相等,对于基本数据类型来说,==
比较的是值。对于引用数据类型来说,==
比较的是对象的内存地址(因为引用类型变量存的值是对象的地址)。equals() : 它的作?不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。但它?般有两种使?情况:
情况 1:类没有覆盖 equals() ?法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况 2:类覆盖了 equals() ?法。?般,我们都覆盖 equals() ?法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
以 String 为例:
String 中的 equals ?法是被重写过的,因为 object 的 equals ?法是比较的对象的内存地址,? String 的 equals ?法比较的是对象的值。当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引?。如果没有就在常量池中重新创建?个 String 对象。
例题:
hashCode()介绍:
hashCode() 的作?是获取哈希码,也称为散列码;它实际上是返回?个 int 整数。这个哈希码的作?是确定该对象在哈希表中的索引位置。 hashCode() 定义在 JDK 的 Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。Object 的 hashcode ?法是本地?法,也就是? c 语?或 c++ 实现的,该?法通常?来将对象的 内存地址 转换为整数之后返回。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利?到了散列码!(可以快速找到所需要的对象)
为什么要有 hashCode?
以“ HashSet 如何检查重复”为例?来说明为什么要有 hashCode?
当对象加? HashSet 时, HashSet 会先计算对象的 hashcode 值来判断对象加?的位置,同时也会与其他已经加?的对象的 hashcode 值作比较,如果没有相符的 hashcode, HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调? equals() ?法来检查 hashcode 相等的对象是否真的相同。如果两者相同, HashSet 就不会让其加?操作成功。如果不同的话,就会重新散列到其他位置。这样我们就??减少了 equals 的次数,相应就??提?了执?速度。
为什么重写 equals 时必须重写 hashCode ?法?
如果两个对象相等,则 hashcode ?定也是相同的。
两个对象相等,对两个对象分别调? equals?法都返回 true。
但是,两个对象有相同的 hashcode 值,它们也不?定是相等的 。
因此,equals ?法被覆盖过,则 hashCode ?法也必须被覆盖。
hashCode() 的默认?为是对堆上的对象产?独特值。如果没有重写 hashCode() ,则该 class 的两个对象?论如何都不会相等(即使这两个对象指向相同的数据)
为什么两个对象有相同的 hashcode 值,它们也不?定是相等的?
因为 hashCode() 所使?的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的 hashCode) 。
我们刚刚也提到了 HashSet ,如果 HashSet 在对?的时候,同样的 hashcode 有多个对象,它会使? equals() 来判断是否真的相同。也就是说 hashcode 只是?来缩?查找成本。
final 关键字,意思是最终的、不可修改的,最见不得变化 ,用来修饰类、方法和变量,具有以下特点:
修饰类:类不能继承,final 类中的所有成员方法都会被隐式的指定为 final 方法;
修饰符变量:该变量为常量,,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能让其指向另一个对象。
**修饰符方法:方法不能重写
说明:使用 final 方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。类中所有的 private 方法都隐式地指定为 final。**
final 可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写
finally 一般作用在 try-catch 代码块中,finally 代码块内语句无论是否发生异常,都会在执行 finally,常用于一些流的关闭。( 可以在 try 或 finally 块中使用 System.exit(int) 退出程序,使 finally 不执行)
finalize:Object 类的一个方法,Java 中允许使用 finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
强、软、弱、虚
强引用(StrongReference): 最传统的“引用”的定义,是指在程序代码之中普遍存在的引用赋值,即类似
“object obj=new Object()”
这种引用关系。无论任何情况下,只要强引用关系还存在,垃圾收集器就永远不会回收掉被引用的对象。软引用(SoftReference): 在系统将要发生内存溢出之前,将会把这些对象列入回收范围之中进行第二次回收。如果这次回收后还没有足够的内存,才会抛出内存流出异常。
弱引用(WeakReference): 被弱引用关联的对象只能生存到下一次垃圾收集之前。当垃圾收集器工作时,无论内存空间是否足够,都会回收掉被弱引用关联的对象。
虚引用(PhantomReference): 一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来获得一个对
new 一个对象:最常见的方式
User user = new User();
。通过反射方式:调用构造器来初始化对象
Class 的 newInstance()方法:User user = User.class.newInstance();
,因为只能调用空参构造器,权限必须是 public。
Constructor 的 newInstance(Xxx)方法:Constructor<User> constructor = User.class.getInstance(); User user = constructor.newInstance();
可以调用空参的,或者带参的构造器
使用对象的 clone()方法返回对象:
User user2 = <User>user.clone();
不调用任何的构造器,直接复制已有的数据,来初始化新建的对象。要求当前的类需要实现 Cloneable 接口中的 clone 接口使用反序列化方式:
ObjectInputStream in = new ObjectInputStream (new FileInputStream(filename)); User user = (User)obj.readObject();
,序列化一般用于 Socket 的网络传输通过第三方库创建对象,比如 Objenesis
JAVA 反射机制是在运行状态中进行自我观察的能力,通过 class、constructor、field、method 等方法获取一个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性; 这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
反射机制优缺点:
优点: 运行期类型的判断,动态加载类,提高代码灵活度。
缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 java 代码要慢很多。
在 Java 中,所有的异常都有?个共同的祖先 java.lang 包中的 Throwable 类。 Throwable 类有两个重要的?类 Exception (异常)和 Error (错误)。
Exception 类的错误是可以在应用程序中进行捕获并处理的,通常遇到这种错误,应对其进行处理,使应用程序可以继续正常运行。Exception ?可以分为受检查异常(必须处理) 和 不受检查异常(可以不处理)。
Error 是?法处理的(只能尽量避免)。这种类型的错误通常是虚拟机相关的错误,例如:Java 虚拟机运?错误( Virtual MachineError )、虚拟机内存不够错误( OutOfMemoryError )等 。这些异常发?时,Java 虚拟机(JVM)?般会选择线程终?,仅靠应用程序本身无法恢复;
受检查异常:
Java 代码在编译过程中,如果受检查异常没有被 catch / throw 处理的话,会导致程序编译不通过。?如下?这段 IO 操作的代码。除了 RuntimeException 及其?类以外,其他的 Exception 类及其?类都属于检查异常 。常?的受
检查异常有: IO 相关的异常、 ClassNotFoundException 、 SQLException (数据库相关异常)等。
不受检查异常:
Java 代码在编译过程中 ,我们即使不处理不受检查异常也可以正常通过编译,不受检查异常往往发生在程序运行的过程中,会导致当前线程执行失败。
RuntimeException 及其?类都统称为?受检查异常,例如:
NullPointExecrption (空指针异常)
NumberFormatException (字符串转换为数字)
ArrayIndexOutOfBoundsException (数组越界)
ClassCastException (类型转换错误)
ArithmeticException (算术错误)等
我们自定义的异常往往也都继承 RuntimeException。
评论