【java基础】面试常见问题:类和对象,封装继承多态,final关键字,static关键字,类加载过程,双亲委派模型
类和对象
1、谈谈你对java面向对象的理解
答:《java编程思想》这一本书中写到,万物皆可对象。
到底什么是面向对象呢?把数据及对数据的操作方法放在一起,作为一个相互依存的整体——对象。对同类对象抽象出其共性,形成类。类中的大多数数据,只能用到本类的方法进行处理,类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。
举例:
2、java面向对象的特性有哪些?
答:三大特性:封装继承多态
- 封装
封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其他对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节,但可以通过该对象对外的提供的接口来访问对象。
-
继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。 -
多态
多态是同一个行为具有多种不同的表现形式或形态的能力。允许不同类的对象对同一消息做出响应。例如:打印方法相同,但如果传入的参数是彩色打印机,效果为彩色;如果传入的参数是黑白,效果为黑白。
3、谈谈你对String,StringBuffer,StringBuilder的理解
答:这三个类之间的区别主要在两个方面,即运行速度和线程安全这两个方面。
(1)首先说运行速度:
运行速度快慢为:StringBuilder>StringBuffer>String
是什么影响到运行速度呢,究其原因我们看到实现的底层,String类针对于字符串连接过程中,变量+字符串常量,底层操作参考字符串拼接操作。
StringBuilder s=new StringBuilder();
s.append(“s”);
s.append(“d”);
String str=s.toString;
StringBuilder和StringBuffer的对象时变量,对变量进行操作就是直接对该对象进行更改,而不进行创建和回收操作,所以速度要比String快的多
(2)再来说线程安全
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的,如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些线程不安全的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度较快的StringBuilder
总结:
String:使用与少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用于多线程下在字符缓冲区进行大量操作的情况。
4、谈谈你对synchronize关键字的理解
答:这里在多线程那块具体会有解释
5、谈谈你对单例模式的理解(这里分为两部分,一部分是线程安全,一部分是线程不安全)
答:这里会专门写一篇博客来解释单例模式
6、谈谈你对final关键字的理解
答:1、final修饰的类不能被继承/2、final修饰的字符数组一经定义不能被修改
7、谈谈你对static关键字的理解
答:1、static修饰成员变量:
存储位置不同:
静态成员变量:位于方法区,无论多少个对象该变量在内存中都只有一份。与对象无关,调用方式类名.访问,静态变量前没有隐藏的this指针
非静态成员变量:位于堆空间,没new一个对象创建一份,因此有多少个对象该变量在内存就有多少份
注:java中不能定义局部的静态变量;原因是底层的类加载
由jvm得,局部变量是保存到栈中,而静态变量保存于方法区,局部变量出了方法就被栈回收了,而静态变量不会,所以在局部变量前不能加static
private,public这些也不能加。静态变量是定义在类中,方法体外面的。
2、static修饰方法
由于在调用静态方法时,并不会将对象的引用传递过去,因此在静态方法中不能访问对象的非静态成员变量。静态成员方法访问方式:类名.静态方法
由于静态成员方法通常以“类名.静态方法”的形式访问,如果可以访问“非静态成员变量”,那么编译器就无法确定:访问的非静态成员成员变量属于哪个对象,以及在内存中的位置,为避免这种情况的出现,编译器一定不会允许静态成员方法访问非静态成员变量
3、static修饰内部类
这里需要注意静态内部类不含有外部类对象的this引用
public class OutClass{
private String OutClassName;
static class InnerClass{
private String innerClassName;
public InnerClass(String innerClassName){
this.innerClassName=innerClassName;
//错误形式
OutClass.this.outClassName="zs";
}
}
那我们可以怎么访问呢?new OutClass().outClassName
8、谈谈类加载过程
答:
什么时候需要加载一个类呢?
1、new,getstatic,putstatic(设置类的静态字段)或invokestatic(调用一个类的静态方法)这四条字节码指令时,需要先触发其初始化
2、使用java.lang.reflect包的方法对类进行反射调用时,如果没有初始化先触发其初始化
3、当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
4、当虚拟机启动时,用户需要指定一个要执行的主类(包含main()的那个类)
类加载过程:.java文件通过javac(java语言编程编译器)编译成.class文件,然后通过jvm(java解码器)来编译
类加载过程:
1、类装载阶段:磁盘——内存
类加载器主要分为三种:启动类加载器(BootstrapClassLoader)加载的是jre/lib/.jar rt.jar,扩展类加载器(extensionClassLoader)加载的是jre/lib/ext/.jar,应用类加载器(AppClassLoader)
这三个类加载器是父子关系
双亲委派模型:从子类到父类查找之前是否加载过,此时将加载产物Class对象返回出来。如果当前类加载没有加载过,再到父类去查找之前是否加载过,直到*类加载器(bootstrap)然后继续从父类到子类尝试加载,如果加载成功将其产物Class对象返回,当前类加载器加载失败,依次到子类中尝试加载,如果都加载失败,报异常:ClassNotFoundException
2、链接阶段:
(1)验证;验证魔数(标记文件类型)版本号……
(2)准备:给static变量开辟内存,给定类型默认值
(3)解析:将间接引用改为直接引用的过程
3、初始化过程:
静态变量赋值操作
加载——验证——准备——解析——初始化——使用——卸载
9、为什么要有类加载器,自定义类加载器如何实现
答:安全高效,
继承ClassLoad再重写findclass方法
10、什么是双亲委派模型,为什么要遵循双亲委派模型?
答:是JVM的类加载机制——该模型是先检查指定名称的类是否已经加载过,如果加载进入内存,不加载直接返回,如果没有加载过,判断是否有父类加载器,如果拥有父类加载器,那么将会直接将权利移交给父类,由父类代理当前类进行加载该类。或者是调用C++的bootstrap类加载器来加载该类
最后如果三者都没有找到类,那么直接调用当前类加载器的findClass方法来完成类加载。
即,如果需要需要加载自定义的类,那么就需要重写findClass方法。
**优点:**1、安全性,避免用户自己编写的类动态替换java的一些核心类
2、避免类的重复加载
11、多态的实现原理
答:class对象:一个类一个Class对象,保存当前类的类信息,在类的加载过程中的装载阶段的产物。
12、谈谈面向对象的特征之一——多态
答:多态是同一行为具有多种不同的表现形式或形态的能力。允许不同类的对象对同一消息做出响应。
多态的条件:
发生动态绑定的三个条件:继承;方法的重写;向上造型(基类引用派生类对象)
向上造型就是定义基类的引用,引用派生类的对象。People people=new Student();people引用.出来的方法是父类的接口,但是方法的实现是子类的实现方式。向上转型时,子类单独定义的方法会丢失。子类引用不能指向父类对象
多态分为编译时多态和运行时多态;
静多态:编译时的多态,也就是我们所说的方法重载。相同的方法名根据形参类型个数或类型的不同调用不同的方法。在编译器就已经确定要调用的方法。
动多态:指程序中定义的引用变量所引用具体对象类型以及通过该引用变量进行方法调用时在编译器并不确定,而在程序运行期才确定。
多态的优点:
1、可替换性:多态对已经存在的代码有可替换性,例父类Animal类 有吃饭工作的方法子类同样具有;
2、可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能;例:猫除了吃饭工作还可以抓老鼠
3、接口性:多态是父类通过方法声明,向子类提供一个共同接口,由子类来完善或者覆盖它而实现的
13、谈谈方法重载和重写的区别
答:
方法重写:
条件:1、派生类中该方法的返回值和基类同名方法的返回值相同,参数列表相同。
2、派生类中的重写方法的访问权限不能比基类小。权限的顺序为:public,protected默认private
3、基类的abstract方法必须被派生类重写,否则派生类也必须是abstract
基类的final方法不能被派生类重写
方法重载:
是根据参数列表的不同来区分不同的函数,通过编译之后会变成两个不同的函数。相同的方法名,根据形参类型个数或类型的不同调用不同的方法,在编译器间就已经确定要调用的方法
14、子类的初始化顺序
答:父类的静态变量——父类的静态块——子类的静态变量——子类的静态块——父类的实例变量——父类的实例块——父类的构造函数——子类的实例变量——子类的实例块——子类的构造函数
本文地址:https://blog.csdn.net/xintu1314/article/details/107243835
上一篇: JAVA面向对象(二)