微信微信官方账号里有Java17种生态技术面试题集合。
Java概述
何为编程
编程是让计算机用程序设计语言编写程序代码,以解决某个问题 最终得到结果的过程。
为了使计算机能够理解人的意图,人类必须理解需要解决的问题 通过计算机可以理解的形式和手段告诉计算机,使计算机能够根据人的指令一 一步一步地工作,完成特定的任务。人与计算机之间的交流过程是编辑 程。
什么是Java
Java它不仅吸收了面向对象的编程语言C 语言的各种优势也被抛弃了 C 多继承、指针等概念难以理解,所以Java语言功能强大,简单 用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象 象理论允许程序员以优雅的思维方式进行复杂的编程 。
jdk1.后三个版本
- Java SE(J2SE,Java 2 Platform Standard Edition,标准版) Java SE 以前称为 J2SE。它允许在桌面、服务器、嵌入式环境和实时环境中开发和部署 用的 Java 应用程序。Java SE 包含了支持 Java Web 并为服务开发类Java EE和Java ME提供基础。
- Java EE(J2EE,Java 2 Platform Enterprise Edition,企业版) Java EE 以前称为 J2EE。企业版帮助开发和部署可移植、强大、可伸缩、安全的服务器 端Java 应用程序。Java EE 是在 Java SE 它提供的基础 Web 服务,组件模型, 管理和通信 API,企业级面向服务体系结构可用于实现(service-oriented architecture,SOA)和 Web2.0应用程序。2018年2月,Eclipse 宣布正式将 JavaEE 更名 为 JakartaEE
- Java ME(J2ME,Java 2 Platform Micro Edition,微型版) Java ME 以前称为 J2ME。Java ME 移动设备和嵌入式设备(如手机)PDA、电视 运行在机顶盒和打印机上的应用程序提供了一个强大而灵活的环境。Java ME 包括灵活使用 户界面、强大的安全模型、许多内置的网络协议以及动态下载的网络和离线应用程序 丰富的支持。基于 Java ME 标准化的应用程序标准化的应用程序,只需编写一次 利用各设备的本机功能。
JVM、JRE和JDK的关系
JVM
Java Virtual Machine是Java虚拟机,Java不同的平面程序需要在虚拟机上运行 台湾有自己的虚拟机,所以Java语言可以实现跨平台。
JRE
Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。 主要是心类库java.lang包:包含操作Java程序必不可少的系统类别,如基本数 根据类型、基本数学函数、字符串处理、线程、异常处理等,系统缺乏加载此包
如果你想运行一个好的开发Java程序在计算机中安装程序JRE即可。
JDK
Java Development Kit是提供给Java开发人员使用的,包括Java的开发 还包括工具JRE。所以安装了JDK,不需要单独安装JRE是的。开发人员 具:编译工具(javac.exe),打包工具(jar.exe)等
[外链图片存储失败,源站可能有防盗链机制,建议保存图片直接上传(img-SIKaQSOH-1652777778560)(01-Java基础知识面试题(2020年最新版).assets/image-20201106172325865.png)]
什么是跨平台?原理是什么?
所谓跨平台,是指java一次编译后,语言编写程序可以在多个系统平台上使用 运行。
实现原理:Java程序是通过java只要系统能安装虚拟机在系统平台上运行 装相应的java该系统可以运行虚拟机java程序。
Java语言的特点是什么?
简单易学(Java语言的语法与C语言和C 语言非常接近)
面向对象(包装、继承、多态)
平台无关性(Java虚拟机实现平台无关性)
支持网络编程非常方便(Java语言诞生本身就是为了简化网络编程设计)
支持多线程(多线程机制使应用程序同时执行多项任务)
健壮性(Java强型语言机制、异常处理、垃圾自动收集等。
安全性
什么是字节码?使用字节码的最大好处是什么?
:Java虚拟机编译器编译后产生的源代码(即扩展到.class的文 零件),它不面向任何特定的处理器,只面向虚拟机。
Java通过字节码,语言在一定程度上解决了传统解释语言执行效率低的问题 问题保留了解释性语言可移植的特点。Java程序运行效率高, 而且,由于字节码不是针对特定机器的,Java程序不需要重新编译 在多种不同的计算机上运行。
Java虚拟机的概念被引入,即在机器和编译程序之间抽象的虚拟机 器。在任何平台上,虚拟机都为编译程序提供了一个共同的接口。编译程 序列只需面向虚拟机,生成虚拟机可以理解的代码,然后由解释器代替虚拟机 代码转换为特定系统的机器代码执行。在Java虚拟机理解的代码称为字节 码(即扩展为.class文件),它不特定的处理器,只面向虚拟机。每 平台的解释器是不同的,但虚拟机是相同的。Java编译了源程序 编译成字节码后,字节码由虚拟机解释执行,虚拟机将每个字节执行 将代码交给解释器,解释器将其翻译成特定机器上的机器代码,然后将其运输到特定机器上 好吧,这就是上面提到的Java特征的编译与解释并存。
Java源代码‐‐‐‐>编译器‐‐‐‐>jvm可执行的Java字节码(即虚拟指令)‐‐‐‐>jvm‐‐‐‐>jvm中 解释器‐‐‐‐‐>机器可执行的二进制机器码‐‐‐‐>程序运行。
什么是Java主类程序?应用程序和小程序有什么区别?
一个程序可以有多个类,但只有一个类是主类。在Java这个主在应用程序中 类是指包含main()方法类。而在Java在小程序中,这个主要类别是从系统中继承的 类JApplet或Applet的子类。应用程序主类不一定要求public类,但小程序 主类要求必须是public类。主类是Java程序执行的入口点。
Java应用程序和小程序有什么区别?
简单地说,应用程序是从主线程开始的main()方法)。applet小程序没有main 该方法主要嵌入浏览器页面(调用)init()线程或run()启动)嵌入浏览 览器这点跟flash类似的小游戏。
Java和C 的区别
我知道很多人都没学过C ,但是面试官就是没事喜欢带我们去Java和C 比呀! 没办法!!!就算没学过!C ,也要写下来!
- 所有面向对象的语言都支持包装、继承和多态化
- Java直接访问内存而不提供指针更安全
- Java的类是单继承的,C 尽管如此Java不能多继承,但是 接口可以多继承。
- Java有自动内存管理机制,程序员无需手动释放无用内存
Oracle JDK 和 OpenJDK 的对比
- Oracle JDK版本每三年发布一次,OpenJDK每三个月发布一次版本 次;
- OpenJDK 它是一模型,完全开源,Oracle JDK是 OpenJDK实现并非完全开源;
- Oracle JDK 比 OpenJDK 更稳定。OpenJDK和Oracle JDK的代码几乎 相同,但Oracle JDK有更多的类别和一些错误的修复。所以,如果你想开发企业, 工业/商业软件,我建议你选择Oracle JDK,因为它经过了彻底的测试和稳定性 定。在某些情况下,有些人提到使用它OpenJDK 可能会遇到很多应用程序 但是,只需切换到序崩问题Oracle JDK能解决问题;
- 在响应性和JVM性能方面,Oracle JDK与OpenJDK比提供更好 性能;
- Oracle JDK不会为即将到来的版本提供长期支持,用户必须每次都通过 更新到最新版本以获得最新版本的支持;
- Oracle JDK根据二进制代码许可协议获得许可OpenJDK根据GPL v许可证获得许可证。
基础语法
数据类型
Java有哪些数类型
:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类 型,在内存中分配了不同大小的内存空间。
:
基本数据类型
- 数值型 整数类型(byte,short,int,long) 浮点类型(float,double)
- 字符型(char)
- 布尔型(boolean)
引用数据类型
- 类(class)
- 接口(interface)
- 数组([])
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rhnpc8dt-1652777778566)(01-Java基础知识面试题(2020最新版).assets/image-20201020121024259.png)]
switch 是否能作用在 byte 上,是否能作用在 long 上,是否 能作用在 String 上
在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版 本中都是不可以的
用最有效率的方法计算 2 乘以 8
2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次 方)。
Math.round(11.5) 等于多少?Math.round(-11.5) 等于多少
Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍 五入的原理是在参数上加 0.5 然后进行下取整。
loat f=3.4;是否正确
不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于 下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转 换float f =(float)3.4; 或者写成 float f =3.4F;。
short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗
对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。 而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。
编码
Java语言采用何种编码方案?有何特点?
Java语言采用Unicode编码标准,Unicode(标准码),它为每个字符制订了一 个唯一的数值,因此在任何的语言,平台,程序都可以放心的使用。
注释
什么Java注释
定义:用于解释说明程序的文字
分类
- 单行注释 格式: // 注释文字
- 多行注释 格式: /* 注释文字 */
- 文档注释 格式:/** 注释文字 */
作用
在程序中,尤其是复杂的程序中,适当地加入注释可以增加程序的可读性,有利 于程序的修改、调试和交流。注释的内容在程序编译的时候会被忽视,不会产生 目标代码,注释的部分不会对程序的执行结果产生任何影响。 注意事项:多行和文档注释都不能嵌套使用。 访问修饰符
访问修饰符 public,private,protected,以及不写(默认)时的 区别
:Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访 问。Java 支持 4 种不同的访问权限。
:
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部 类)
- default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用 任何修饰符。使用对象:类、接口、变量、方法。
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意: 不能修饰类(外部类)。
- public : 对所有类可见。使用对象:类、接口、变量、方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5ftxQAP-1652777778568)(01-Java基础知识面试题(2020最新版).assets/image-20201020130327174.png)]
运算符
&和&&的区别
&运算符有两种用法:(1)按位与;(2)逻辑与。
&&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要 求运算符左右两端的布尔值都是true 整个表达式的值才是 true。&&之所以称 为短路运算,是因为如果&&左边的表达式的值是 false,右边的表达式会被直 接短路掉,不会进行运算。
注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。
关键字
Java 有没有 goto
goto 是 Java 中的保留字,在目前版本的 Java 中没有使用。
final 有什么用?
用于修饰类、属性和方法;
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的
final finally finalize区别
- final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表示该变量是一个常量不能被重新赋值。
- finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
- finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的最后判断。
this关键字的用法
this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指 针。
this的用法在java中大体可以分为3种:
1.普通的直接引用,this相当于是指向当前对象本身。
2.形参与成员名字重名,用this来区分:
1 public Person(String name, int age) {
2 this.name = name;
3 this.age = age;
4 }
3.引用本类的构造函数
1 class Person{
2 private String name;
3 private int age;
4
5 public Person() {
6 }
7
8 public Person(String name) {
9 this.name = name;
10 }
11 public Person(String name, int age) {
12 this(name);
13 this.age = age;
14 }
15 }
super关键字的用法
super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离 自己最近的一个父类。
super也有三种用法:
1.普通的直接引用 与this类似,super相当于是指向当前对象的父类的引用,这样就可以用 super.xxx来引用父类的成员。 2.子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区 分
1 class Person{
2 protected String name;
3
4 public Person(String name) {
5 this.name = name;
6 }
7
8 }
9
10 class Student extends Person{
11 private String name;
12
13 public Student(String name, String name1) {
14 super(name);
15 this.name = name1;
16 }
17
18 public void getInfo(){
19 System.out.println(this.name); //Child
20 System.out.println(super.name); //Father
21 }
22
23 }
24
25 public class Test {
26 public static void main(String[] args) {
27 Student s1 = new Student("Father","Child");
28 s1.getInfo();
29
30 }
31 }
3.引用父类构造函数
super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
this与super的区别
- super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
- this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
- super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
- super()和this()均需放在构造方法内第一行。
- 尽管可以用this调用一个构造器,但却不能调用两个。
- this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括: static变量,static方法,static语句块。
- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
static存在的主要意义
static的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法!
static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候 执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
static的独特之处
1、被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享。
怎么理解 “被类的实例对象所共享” 这句话呢?就是说,一个类的静态成员,它是属于大伙的【大伙指的是这个类的多个对象实例,我们都知道一个类可以创建多个实例!】,所有的类对象共享的,不像成员变量是自个的【自个指的是这个类的单个实例对象】…我觉得我已经讲的很通俗了,你明白了咩?
2、在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。
3、static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!
4、被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。
static应用场景
因为static是被类的实例对象所共享,因此如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量。
因此比较常见的static应用场景有:
1、修饰成员变量 2、修饰成员方法 3、静态代码块 4、修饰类【只能修饰内部类也就是静态内部类】 5、静态导包
static注意事项
1、静态只能访问静态。 2、非静态既可以访问非静态的,也可以访问静态的。
流程控制语句
break ,continue ,return 的区别及作用
break 跳出总上一层循环,不再执行循环(结束当前的循环体)continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件)
return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)
在 Java 中,如何跳出当前的多重嵌套循环
在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环。例如:
1 public static void main(String[] args) {
2 ok:
3 for (int i = 0; i < 10; i++) {
4 for (int j = 0; j < 10; j++) {
5 System.out.println("i=" + i + ",j=" + j);
6 if (j == 5) {
7 break ok;
8 }
9
10 }
11 }
12 }
面向对象
面向对象概述
面向对象和面向过程的区别
面向过程:
优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,能是最重要的因素。 缺点:没有面向对象易维护、易复用、易扩展
面向对象:
优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
缺点:性能比面向过程低 面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步 一步的实现。
面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。
面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。
面向对象三大特性
面向对象的特征有哪些方面
**面向对象的特征主要有以下几个方面: **
**抽象:**抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行 为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是 什么。
-
封装 : 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如 果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没 有提供给外界访问的方法,那么这个类也没有什么意义了。
-
继承 : 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新 的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用 继承我们能够非常方便地复用以前的代码。
关于继承如下 3 点请记住:
1.子类拥有父类非 private 的属性和方法。
2.子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3.子类可以用自己的方式实现父类的方法。
-
多态 : 所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出 的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到 底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的 方法,必须在由程序运行期间才能决定。
在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口 (实现接口并覆盖接口中同一方法)。
其中Java 面向对象编程三大特性:封装 继承 多态
:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便 于使用,提高复用性和安全性。
:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以 增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通 过使用继承可以提高代码复用性。继承是多态的前提。
**关于继承如下 3 点请记住: **
- 子类拥有父类非 private 的属性和方法。
- 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提 高了程序的拓展性。
在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口 (实现接口并覆盖接口中同一方法)。
方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重 写(override)实现的是运行时的多态性(也称为后绑定)。
一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是 哪个类中实现的方法,必须在由程序运行期间才能决定。运行时的多态是面向对 象精髓的东西,要实现多态需要做两件事:
- 方法重写(子类继承父类并重写父类中已有的或抽象的方法);
- 对象造型(用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据 子类对象的不同而表现出不同的行为)。
什么是多态机制?Java语言是如何实现多态的?
所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出 的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒 底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的 方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这 样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而 导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时 所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。 多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的 重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不 同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来 实现的,也就是我们所说的多态性
Java实现多态有三个必要条件:继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的 方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具 备技能调用父类的方法和子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现 代码处理不同的对象,从而达到执行不同的行为。
对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类 对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但 是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
面向对象五大基本原则是什么(可选)
- 单一职责原则SRP(Single Responsibility Principle)类的功能要单一,不能包罗万象,跟杂货铺似的。 开放封闭原则OCP(Open-Close Principle)
- 一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼, 一万个不乐意。
- 里式替换原则LSP(the Liskov Substitution Principle LSP)子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
- 依赖倒置原则DIP(the Dependency Inversion Principle DIP)高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的抽象是中国人,而不是你是xx村的。
- 接口分离原则ISP(the Interface Segregation Principle ISP) 设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有 打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的 多。
类与接口
抽象类和接口的对比
抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。 从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
- 接口和抽象类都不能实例化
- 都位于继承的顶端,用于被其他实现或继承
- 都包含抽象方法,其子类都必须覆写这些抽象方法
参数 | 抽象类 | 接口 |
---|---|---|
声明 | 抽象类使用abstract关键字声明 | 接口使用interface关键字声明 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现 | 子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现 |
构造器 | 抽象类可以有构造器 | 接口不能有构造器 |
访问修饰符 | 抽象类中的方法可以是任意访问修饰符 | 接口方法默认修饰符是public。并且不允许定义为 private 或者 protected |
多继承 | 一个类最多只能继承一个抽象类 | 一个类可以实现多个接口 |
字段声明 | 抽象类的字段声明可以是任意的 | 接口的字段默认都是 static 和 final 的 |
:Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间 的差异。
现在,我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。 接口和抽象类各有优缺点,在接口和抽象类的选择上,必须遵守这样一个原则:
- 行为模型应该总是通过接口而不是抽象类定义,所以通常是优先选用接口,尽量 少用抽象类。
- 选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用 的功能。
普通类和抽象类有哪些区别?
- 普通类不能包含抽象方法,抽象类可以包含抽象方法。
- 抽象类不能直接实例化,普通类可以直接实例化。
抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承, 这样彼此就会产生矛盾,所以 final 不能修饰抽象类
创建一个对象用什么关键字?对象实例与对象引用有何不同?
new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实 例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根 绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以 用n条绳子系住一个气球)
变量与方法
成员变量与局部变量的区别有哪些
变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上 讲,变量其实是内存中的一小块区域 成员变量:方法外部,类内部定义的变量 局部变量:类的方法中的变量。 成员变量和局部变量的区别
作用域
成员变量:针对整个类有效。
局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)
存储位置
成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。
生命周期
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:当方法调用完,或者语句结束后,就自动释放。
初始值
成员变量:有默认初始值。
局部变量:没有默认初始值,使用前必须赋值。
使用原则
在使用变量时需要遵循的原则为:就近原则 首先在局部范围找,有就使用;接着在成员位置找。
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构 造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了 有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定 的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构 造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
在调用子类构造方法之前会先调用父类没有参数的构造方法,其 目的是?
帮助子类做初始化工作。
一个类的构造方法的作用是什么?若一个类没有声明构造方法, 改程序能正确执行吗?为什么?
主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构 造方法也会有默认的不带参数的构造方法。
构造方法有哪些特性?
名字与类名相同;
没有返回值,但不能用void声明构造函数;
生成类的对象时自动执行,无需调用。
静态变量和实例变量区别
静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会 有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。
实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量 是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。
静态变量与普通变量区别
static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有 的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始 化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副 本,各个对象拥有的副本互不影响。
还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。
静态方法和实例方法有何不同?
静态方法和实例方法的区别主要体现在两个方面:
-
在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使 用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调 用静态方法可以无需创建对象。
-
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量 和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此 限制
在一个静态方法内调用一个非静态成员为什么是非法的?
由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静 态变量,也不可以访问非静态变量成员。
什么是方法的返回值?返回值的作用是什么?
方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提 是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的 操作!
内部类
什么是内部类?
在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内 部类本身就是类的一个属性,与其他属性定义方式一致。
内部类的分类有哪些
内部类可以分为四种:
静态内部类
定义在类内部的静态类,就是静态内部类。
1 public class Outer {
2
3 private static int radius = 1;
4
5 static class StaticInner {
6 public void visit() {
7 System.out.println("visit outer static variable:" + radius);
8 }
9 }
10 }
静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量; 静态内部类的创建方式,new 外部类.静态内部类(),如下:
1 Outer.StaticInner inner = new Outer.StaticInner();
2 inner.visit
成员内部类
定义在类内部,成员位置上的非静态类,就是成员内部类。
1 public class Outer {
2
3 private static int radius = 1;
4 private int count =2;
5
6 class Inner {
7 public void visit() {
8 System.out.println("visit outer static variable:" + radius);
9 System.out.println("visit outer variable:" + count);
10 }
11 }
12 }
成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公 有。成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类(),如 下:
1 Outer outer = new Outer();
2 Outer.Inner inner = outer.new Inner();
3 inner.visit();
局部内部类
定义在方法中的内部类,就是局部内部类
1 public class Outer {
2
3 private int out_a = 1;
4 private static int STATIC_b = 2;
5
6 public void testFunctionClass(){
7 int inner_c =3;
8 class Inner {
9 private void fun(){
10 System.out.println(out_a);
11 System.out.println(STATIC_b);
12 System.out.println(inner_c);
13 }
14 }
15 Inner inner = new Inner();
16 inner.fun();
17 }
18 public static void testStaticFunctionClass(){
19 int d =3;
20 class Inner {
21 private void fun(){
22 // System.out.println(out_a); 编译错误,定义在静态方法中的局部类不可以访问外
部类的实例变量
23 System.out.println(STATIC_b);
24 System.out.println(d);
25 }
26 }
27 Inner inner = new Inner();
28 inner.fun();
29 }
30 }
定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法 中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应 方法内,new 内部类(),如下:
1 public static void testStaticFunctionClass(){
2 class Inner {
3 }
4 Inner inner = new Inner();
5 }
匿名内部类
匿名内部类就是没有名字的内部类,日常开发中使用的比较多。
1 public class Outer {
2
3 private void test(final int i) {
4 new Service() {
5 public void method() {
6 for (int j = 0; j < i; j++) {
7 System.out.println("匿名内部类" );
8 }
9 }
10 }.method();
11 }
12 }
13 //匿名内部类必须继承或实现一个已有的接口
14 interface Service{
15 void method();
16 }
除了没有名字,匿名内部类还有以下特点:
- 匿名内部类必须继承一个抽象类或者实现一个接口。
- 匿名内部类不能定义任何静态成员和静态方法。
- 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方 法。
匿名内部类创建方式:
1 new 类/接口{
2 //匿名内部类实现部分
3 }
内部类的优点
我们为什么要使用内部类呢?因为它有以下优点:
- 一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
- 内部类不为同一包的其他类所见,具有很好的封装性;
- 内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
- 匿名内部类可以很方便的定义回调。
内部类有哪些应用场景
-
一些多算法场合
-
解决一些非面向对象的语句块。
-
适当使用内部类,使得代码更加灵活和富有扩展性。
-
当某个类除了它的外部类,不再被其他的类使用时。
局部内部类和匿名内部类访问局部变量的时候,为什么变量必须 要加上final?
局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final呢? 它内部原理是什么呢?
先看这段代码:
1 public class Outer {
2
3 void outMethod(){
4 final int a =10;
5 class Inner {
6 void innerMethod(){
7 System.out.println(a);
8 }
9
10 }
11 }
12 }
以上例子,为什么要加final呢?是因为生命周期不一致, 局部变量直接存储在 栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变 量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final, 可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。
内部类相关,看程序说出运行结果
1 public class Outer {
2 private int age = 12;
3
4 class Inner {
5 private int age = 13;
6 public void print() {
7 int age = 14;
8 System.out.println("局部变量:" + age);
9 System.out.println("内部类变量:" + this.age);
10 System.out.println("外部类变量:" + Outer.this.age);
11 }
12 }
13
14 public static void main(String[] args) {
15 Outer.Inner in = new Outer().new Inner();
16 in.print();
17 }
18
19 }
运行结果:
1 局部变量:14
2 内部类变量:13
3 外部类变量:12
重写与重载
构造器(constructor)是否可被重写(override)
构造器不能被继承,因此不能被重写,但可以被重载。
重载(Overload)和重写(Override)的区别。重载的方法能 否根据返回类型进行区分?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态 性,而后者实现的是运行时的多态性。
重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不 同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回 类型进行区分
重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛 出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类 方法访问修饰符为private则子类中就不是重写。
对象相等判断
== 和 equals 的区别是什么
== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同 一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)
equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况: 情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时, 等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象 的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
举个例子:
1 public class test1 {
2 public static void main(String[] args) {
3 String a = new String("ab"); // a 为一个引用
4 String b = new String("ab"); // b为另一个引用,对象的内容一样
5 String aa = "ab"; // 放在常量池中
6 String bb = "ab"; // 从常量池中查找
7 if (aa == bb) // true
8 System.out.println("aa==bb");
9 if (a == b) // false,非同一对象
10 System.out.println("a==b");
11 if (a.equals(b)) // true
12 System.out.println("aEQb");
13 if (42 == 42.0) { // true
14 System.out.println("true");
15 }
16 }
17 }
说明:
- String中的equals方法是被重写过的,因为object的equals方法是比较的对象的 内存地址,而String的equals方法比较的是对象的值。
- 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要 创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建 一个String对象。
hashCode 与 equals (重要)
HashSet如何检查重复
两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
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 first java》 第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速 度。
hashCode()与equals()的相关规定
如果两个对象相等,则hashcode一定也是相同的 两个对象相等,对两个对象分别调用equals方法都返回true 两个对象有相同的hashcode值,它们也不一定是相等的
因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖
hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写
hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指 向相同的数据)
对象的相等与指向他们的引用相等,两者有什么不同?
对象的相等 比的是内存中存放的内容是否相等而 引用相等 比较的是他们指向的 内存地址是否相等。
值传递
当一个对象被当作参数传递到一个方法后,此方法可改变这个对 象的属性,并可返回变化后的结果,那么这里到底是值传递还是 引用传递
是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一 个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被 调用过程中被改变,但对对象引用的改变是不会影响到调用者的
为什么 Java 中只有值传递
首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术 语。 它用 来描述各种程序设计语言(不只是Java)中方法参数传递方式。
下面通过 3 个例子来给大家说明
example 1
1 public static void main(String[] args) {
2 int num1 = 10;
3 int num2 = 20;
4
5 swap(num1, num2);
6
7 System.out.println("num1 = " + num1);
8 System.out.println("num2 = " + num2);
9 }
10
11 public static void swap(int a, int b) {
12 int temp = a;
13 a = b;
14 b = temp;
15
16 System.out.println("a = " + a);
17 System.out.println("b = " + b);
18 }
结果:
1 a = 20
2 b = 10
3 num1 = 10
4 num2 = 20
解析:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a8SCqJEh-1652777778569)(01-Java基础知识面试题(2020最新版).assets/image-20201106190311218.png)]
在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、 b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于 num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。
通过上面例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而 对象引用作为参数就不一样,请看 example2.
example 2
1 public static void main(String[] args) {
2 int[] arr = { 1, 2, 3, 4, 5 };
3 System.out.println(arr[0]);
4 change(arr);
5 System.out.println(arr[0]);
6 }
7
8 public static void change(int[] array) {
9 // 将数组的第一个元素变为0
10 array[0] = 0;
11 }
结果:
1 1
2 0
解析:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TwAuzjZO-1652777778569)(01-Java基础知识面试题(2020最新版).assets/image-20201106190416793.png)]
array 被初始化 arr 的拷贝也就是一个对象的引用,也就是说 array 和 arr 指向 的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象 上。
通过 example2 我们已经看到,实现一个改变对象参数状态的方法并不是一件 难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时 引用同一个对象。
很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调 用和引用调用。有些程序员(甚至本书的作者)认为Java程序设计语言对对象 采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍 性,所以下面给出一个反例来详细地阐述一下这个问题。
example 3
1 public class Test {
2
3 public static void main(String[] args) {
4 // TODO Auto‐generated method stub
5 Student s1 = new Student("小张");
6 Student s2 = new Student("小李");
7 Test.swap(s1, s2);
8 System.out.println("s1:" + s1.getName());
9 System.out.println("s2:" + s2.getName());
10 }
11
12 public static void swap(Student x, Student y) {
13 Student temp = x;
14 x = y;
15 y = temp;
16 System.out.println("x:" + x.getName());
17 System.out.println("y:" + y.getName());
18 }
19 }
结果:
1 x:小李
2 y:小张
3 s1:小张
4 s2:小李
解析:
交换之前:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSJU1tsi-1652777778570)(01-Java基础知识面试题(2020最新版).assets/image-20201106190608690.png)]
交换之后:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FMKYfAxS-1652777778571)(01-Java基础知识面试题(2020最新版).assets/image-20201106190619059.png)]
通过上面两张图可以很清晰的看出: 方法并没有改变存储在变量 s1 和 s2 中的 对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交 换的是这两个拷贝
总结
Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。
下面再总结一下Java中方法参数的使用情况:
- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
- 一个方法可以改变一个对象参数的状态。
- 一个方法不能让对象参数引用一个新的对象。
值传递和引用传递有什么区别
值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷 贝,也就是说传递后就互不相关了。 引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引 用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说 传递前和传递后都指向同一个引用(也就是同一个内存空间)。
Java包
JDK 中常用的包有哪些
- java.lang:这个是系统的基础类;
- java.io:这里面是所有输入输出有关的类,比如文件操作等;
- java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
- java.net:这里面是与网络有关的类;
- java.util:这个是系统辅助类,特别是集合类;
- java.sql:这个是数据库操作的类。
import java和javax有什么区别
刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来说