JAVA面试总结(基础篇一)
1. JDK和JRE区别,JVM
JDK(JAVA Development Kit):Java开发工具包;
JRE(JAVA Runtime Environment):Java运行环境;
JVM (Java Virtual Machine):是JAVA跨平台的关键,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言实现跨平台。
2. 面向对象的理解
面向对象是向现实世界模型的自然延伸,就是一种“万物皆对象”的编程思想。在现实世界中任何物体都可以归为一类事物,而每一个个体都是一类事物的实例。面向对象的编程是以对象为中心,以消息为驱动,即 程序=对象+消息。
2.1 三大特征
- 封装:将一类事物的属性和行为抽象为一个类,使其属性私有化,行为公开化。将对象的实现细节隐藏起来,然后通过公共方法暴露该对象的功能。优点:便于使用;提高了安全性;提供了重复性。
- 继承:进一步将事物共有的属性和行为抽象为一个父类,而每个子类是一个特殊的父类,既具有父类的属性和行为,也具有自己独特的属性和行为。目的:提高了代码的重用性,减少代码冗余;规范子类。
- 多态:实现接口重用。一个类可以创建多个对象每个对象可以有不同的属性和方法。
2.2 面向对象的五大基本原则
- 单一职责原则SRP(Single Responsibility Principle):类的功能单一,不能包罗万象。
- 开放封闭原则OCP(Open-Close Principle):一个模块对于拓展是开放的,对于修改是封闭的。
- 里式替换原则LSP(the Liskov Substitution Principle):子类可以替换父类出现在父类能够出现的地方。
- 依赖倒置原则DIP(the Dependency Inversion Principle):高层次的模块不应该依赖于低层次的模块,他们都依赖于抽象。抽象不依赖于具体实现,具体实现依赖于抽象。
- 接口分离原则ISP(the Interface Segregation Principle):设计时采用多个与特定客户类有关的接口比采用一个通用的接口好。
2.3 抽象类和接口
抽象类: 用来捕捉子类通用特性的,是对类的抽象,是一种模板设计。接口: 抽象方法的集合,接口是行为的抽象,是一种行为的规范。
相同点:
- 接口和抽象类都不可以被实例化,
- 接口和抽象类都位于继承树的顶端,用于被其他类实现和继承;
- 接口和抽象类都可以包含抽象方法,实现接口或者继承抽象类的普通子类都必须实现这些抽象方法。
不同点:
- 接口只包含抽象方法、静态方法、默认方法和私有方法,不能为普通方法提供方法实现;抽象类完全可以包含普通方法。
- 接口里只能定义静态常量,不能定义普通变量;抽象类既可以定义静态变量也可以定义普通成员变量。
- 接口不包含构造器,抽象类可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调佣构造器来完成抽象类的初始化操作。
- 接口中不包含初始化块, 但是抽象类则完全可以包含初始化块。
- 一个类最多只能有一个直接父类,包含抽象类;但是一个类可以直接实现多个接口,通过多个接口可以弥补JAVA单继承的不足。
2.4 抽象类和普通类的区别
- 普通类不能包含抽象方法,抽象类可以包含抽象方法。
- 抽象类不能直接实例化,普通类可以直接实例化。
2.5 重写和重载的区别
- 重写发生在父类子类中,若子类方法想要和父类方法构成重写关系,则它的方法名、参数列表必须与父类方法相同。另外,返回值要小于等于父类方法,抛出异常要小于等于父类方法,访问修饰符则要大于等于父类方法。还有,若父类方法访问修饰符为private,则子类不能对其重写。
- 重载发生在同一类中,若多个方法之间方法名相同、参数列表不同,则他们构成重载的关系。重载与方法的返回值以及访问修饰符无关,即重载的方法不能根据返回类型进行区分。
2.6 构造方法
- 作用: 完成对类对象的初始化工作。如果一个类没有声明构造方法,也会存在默认的不带参数的构造方法。
- 特性: 名字与类名相同;没有返回值,但不能用void声明构造函数;生成类的对象时自动执行,无需调用。
- 构造方法不能重写。 因为构造方法需要和类保持同名,而重写的要求是子类方法要和父类方法保持同名。如果允许重写构造方法的话,那么子类将会存在与类名不同的构造方法,这与构造方法的要求是矛盾的。
- 接口中不包含构造方法。 接口的定义是一种规范,因此接口中不包含构造器和初始化块的定义。接口中可以包含成员变量(只能是静态常量)、方法(只能是抽象实例方法、类方法、默认方法或者私有方法)、内部类定义(内部接口、枚举)。
3. JAVA访问权限
在修饰成员变量、成员方法时,有四种访问权限:
- private:此成员可以被该类内部成员访问;
- default:此成员可以被该类内部成员、同一包下其他类访问;
- protected:此成员课可以被该类内部成员、同一包下其他类和它的子类访问;
- public:此成员可以被任意包下、任意类访问。
在修饰类时,只有两种访问权限:
- default:此类可以被同一包下其他类访问;
- public:此类任意包下、任意类访问。
注意在不加任何修饰符时为default访问权限。
4. JAVA数据类型
4.1 基本数据类型
类型名(默认值)
- 整数类:byte(0)、short(0)、int(0)、long(0L)。
- 浮点类:float(0.0F)、double(0.0)。
- 字符类:char(‘\u000’)。
- 布尔类:boolean(false)
4.2 引用数据类型
引用类型就是对一个对象的引用,根据引用对象类型的不同,引用类型分为:数组、类、接口类。
5. String
5.1 String类的常用方法
-
获取功能
- length:获取字符串长度;
- charAt(int index):获取指定索引位置的字符;
- indexOf(int char):获取指定字符在字符串中第一次出现的索引;
- substring(int start):从指定的位置开始截取字符串,截止到最后一位;
- substring(int start, int end):从指定的位置开始截取字符串到指定位置结束。
-
转换功能
- byte[] getBytes(): 把字符串转换为字节数组;
- char[] toCharArray(): 把字符串转换为字符数组;
- String valueOf(char[] chs): 把字符数组转成字符串。valueOf可以将任意类型转为字符串;
- toLowerCase(): 把字符串转成小写;
- toUpperCase(): 把字符串转成大写;
- concat(String str): 把字符串拼接。
-
判断功能
- equals(Object obj):比较字符串的内容是否相同,区分大小写;
- contains(String str):判断字符串中是否包含传递进来的字符串;
- startsWith(String str):判断字符串是否以传递进来的字符串开头;
- endsWith(String str):判断字符串是否以传递进来的字符串结尾;
- isEmpty():判断字符串的内容是否为空串""。
-
其他
- replace(char old,char new) 将指定字符进行互换;
- replace(String old,String new) 将指定字符串进行互换;
- trim() 去除两端空格。
5.2 String str="i"与 String str=new String(“i”)
String str="i":
将其分配到常量池中,在常量池中没有重复的元素。如果常量池中存中 i,就将 i 的地址赋给变量,如果没有就创建一个再赋给变量。
String str=new String(“i”):
将对象分配到堆中,即使内存一样,还是会重新创建一个新的对象。
5.3 String、StringBuilder和StringBuffer
- String:是不可变类,一旦一个String对象被创建以后,包含在这个对象中的字符串序列是不可改变的,直到对象被销毁。
- StringBuffer:代表是一个可变的字符串。线程安全的,由于加锁原因,效率低于StringBuilder,多用于多线程。 当一个StringBuffer被创建以后,通过其提供的append()、insert()、reverse()、setCharAt()等方法可以改变这个字符串对象的字符序列。一旦通过StringBuffer生成了最终想要的字符串,就可以调用它的toString()方法将其转换为一个String对象。
- StringBuilder:代表是一个可变的字符串。线程不安全的,效率高,多用于单线程。
注意: StringBuilder > StringBuffer > String。
6. ArrayList 和 LinkedList
ArrayList:
- 基于数组,需要连续的存储空间;
- 随机访问比较快,根据指定下标访问;
- 尾部插入、删除性能可以,其他部分的插入、删除都需要移动数据,性能较低;
- 可以利用cpu缓存,局部性原理。
LinkedList:
- 基于双向链表,不需要连续的存储空间;
- 随机访问较慢,需要沿着链表遍历;
- 插入删除性能高;
- 占用内存多。
7. JAVA中Math函数取整用法
- ceil:向上取整
Math.ceil(6.4)=7; Math.ceil(-6.4)=-6. - floor:向下取整
Math.floor(6.4)=6; Math.floor(-6.4)=-7. - round:四舍五入法(原理是在参数上加 0.5 然后进行下取整)
Math.round(6.4)=6; Math.round(-6.4)=-6;
Math.round(6.9)=7; Math.round(-6.9)=-7.
8. JAVA中的引用类型
- 强引用:JAVA常用的引用方式。程序创建一个对象,并把这个对象赋给一个引用变量,程序通过该引用变量来操作实际对象。当一个对象被一个或一个以上的应用变量所引用时,它处于可达状态,不可能被系统垃圾回收机制回收。如果想要被回收,可以将对象置为NULL。
- 软引用:当对象只有软引用时,它可能被垃圾回收机制回收。对于只有软引用的对象而言,当系统内存储内存足够时,它不会被系统回收,程序也可以使用该对象。当系统内存不足时,系统可能会回收它,回收软引用对象之后若仍旧没有足够的内存,会跑出内存溢出异常。
软引用通常用于对内存敏感的程序中。
- 弱引用:弱引用和软引用很像,但是引用级别更低。对于只有弱引用的对象而言,当系统垃圾回收机制运行时,不管系统内存是否足够,总会回收该对象所占用的内存。
- 虚引用:虚引用完全类似于没有引用。虚引用对对象本身没有太大的影响,对象甚至感觉不到虚引用的存在。虚引用主要用于跟踪对象被垃圾回收的状态,虚引用不能单独使用,虚引用必须和引用队列联合使用。
- 引用队列:可以与软引用、弱引用、虚引用一起配合使用。
总: 当垃圾回收期准备回收一个对象时,若发现它还被引用,会在回收该对象前,把此引用放入到引用队列中。 程序可通过判断引用队列中是否加入引用,进而来判断引用的对象是否将要被垃圾回收,从而在对象被回收前采取一定的措施。
9. 关键字
9.1 final、finally和finalize
- final: 可以修饰类、变量、方法,修饰类表示该类不能被继承,修饰方法表示该方法不能被重写,修饰变量表示该变量是一个常量不能被重写赋值。
- finally: 一般作用在try-catch代码块中,在处理异常时,通常要将我们一定要执行的代码方法放入到finally代码块中,表示不管是不是出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
- finalize: 是一个方法,属于object类的一个方法,而object类时所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc()方法的时候,由垃圾回收器调用finalize()回收垃圾,一个对象是否可回收的最后进行判断。
9.2 static
- 以static修饰的成员就是类成员,类成员属于整个类,而不属于单个对象。
- static的主要意义是在与创建独立具体对象的域变量或者方法。即使没有创建对象,也可以使用该属性和方法!
- static 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。static的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块总进行。
- 被static修饰的变量或者方法是优先于对象存在的,当一个类加载完毕后,即使没有创建方法,也可以被访问。
9.3 final和static区别
-
static关键字可以修饰成员变量、成员方法、初始化块、内部类,被static修饰的成员是类的成员,它属于类、不属于单个对象。
-
类变量: 被static修饰的成员+ 变量叫类变量(静态变量)。类变量属于类,它随类的信息存储在方法区,并不随对象存储在堆中,类变量可以通过类名来访问,也可以通过对象名来访问,但建议通过类名访问它。
-
类方法: 被static修饰的成员方法叫类方法(静态方法)。类方法属于类,可以通过类名访问,也可以通过对象名访问,建议通过类名访问它。
-
静态块: 被static修饰的初始化块叫静态初始化块。静态块属于类,它在类加载的时候被隐式调用一次,之后便不会被调用了。
-
静态内部类: 被static修饰的内部类叫静态内部类。静态内部类可以包含静态成员,也可以包含非静态成员。静态内部类不能访问外部类的实例成员,只能访问外部类的静态成员。外部类的所有方法、初始化块都能访问其内部定义的静态内部类。
-
-
final关键字可以修饰类、方法、变量。
-
修饰类: final关键字修饰的类不可以被继承。
-
修饰方法: final关键字修饰的方法不可以被重写。
-
修饰变量: final关键字修饰的变量,一旦获得了初始值,就不可以被修改。
-
9.4 this
this本身是一个对象,代表对象本身,可以理解为:指向对象本身的指针。
this用法可以分为3种:
- 普通的直接引用,this相当于指向对象本身的指针;
- 形参与成员名字重名,用this区分:
public Student(String name, int age){
this.name = name;
this.age = age;
}
- 引用本类的构造函数
class Student{
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
public Student(String name, int age) {
this(name);
this.age = age;
}
}
9.5 super三种用法
- 普通直接引用: 与this类似,super相当于是指向当前对象的父类引用,这样就可以通过super.XXX来引用父类的成员。
- 子类中的成员变量或方法与父类中的成员变量或方法同名时,用super区别:
class Person{
protected String name;
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
private String name;
public Student(String name, String name1) {
super(name);
this.name = name1;
}
public void getName(){
System.out.println(this.name); //Child
System.out.println(super.name); //Father
}
}
public class Test {
public static void main(String[] args) {
Student s = new Student("Father","Child");
s.getName();
}
}
- 引用父类的构造方法
- super(参数):调用父类的某一个构造函数。
- this(参数):调用本类中另一种形式的构造函数。
9.6 this和super区别
- super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名) - super()和this()类似均需放在构造方法内第一行。区别是:super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。尽管可以用this调用一个构造器,但却不能调用两个。
- this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
- this()和super()都指的是对象,均不可以在static环境中使用。比如,static变量、static方法、static语句块。
- 本质上,this是一个指向本对象的指针, super是一个Java关键字。