Java基础常见面试题

1. Java语言的特点

1.简单易学,java语言继承了C++语言的优点,并去掉了C++中比较难的多继承、指针等概念。
2.面向对象,java也是一种面向对象的编程语言,它有三大特性,封装、继承、多态。
3.可移植性,java并不依赖平台,通过java虚拟机可以实现跨平台。
4.编译和解释并存,java程序由java虚拟机编译后生成虚拟机能够理解的代码,然后由解释器将虚拟机代码转换为特定系统的机器码执行。
5.健壮性,java语言的健壮性主要体现在强类型机制、异常处理、垃圾的自动收集等。
6.支持多线程,多线程机制使应用程序在同一时间并行执行多项任务
---以下是暂时不能理解的特性
7.安全性,java的存储分配模型是它防御恶意代码的主要方法之一。
8.分布性,java设计成支持在网络上应用,它是分布式语言。
9.高性能,java是一种先编译后解释的语言,所以它不如全编译性语言快,但设计者制作了“及时”编译程序,这样就可以实现全编译了。
10.动态性,java语言设计成适应于变化的环境,它是一个动态的语言。

2. Java和C++的区别

1.都是面向对象的语言,都支持封装、继承、多态。
2.java不提供指针来直接访问内存,程序内存更加安全。
3.java的类是单继承,C++支持多重继承;虽然java的类不可以多继承,但是接口可以多继承。
4.java有自动内存管理机制,无需程序员手动释放无用内存。

3. JVM和JRE、JDK之间的关系

JVM:其实就是java虚拟机,java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此java语言可以实现跨平台。
JRE:它包括JVM和java程序所需的核心类库等。核心类库主要是java.lang包,包含了运行java程序必不可少的系统类,
	 如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统会自动加载这个包。
	 【如果只想要运行一个开发好的java程序,计算机只需安装JRE即可。】
JDK:它包括了JRE和java的开发工具,如:编译工具(javac.exe),打包工具(jar.exe)等,它是提供给java的开发人员使用的。

具体关系如下图所示

语雀java面试题 java语言面试_语雀java面试题

4. 什么是Java语言的跨平台,原理是什么?

什么是java的跨平台:
	指的是java语言编写的程序,一次编译之后,可以在多个不同系统平台上运行。

跨平台的原理:
	java程序其实是通过java虚拟机在系统平台上运行的,只要该系统安装了相应的java虚拟机,该系统就能运行java程序。

5. 什么是字节码?采用字节码的好处

首先要知道java中的编译器和解释器的作用:
	java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟机器。这台虚拟的机器在任何平台上都能提供给编译程序
一个共同的接口。编译程序只需要面向虚拟机,由虚拟机的编译器编译后,生成虚拟机能够理解的代码,然后由解释器将虚拟机代码转换为特
定系统的机器码执行。

什么是字节码?
	java源程序经过虚拟机编译器编译后产生的文件(即扩展名为.class的文件)。

采用字节码的好处?
	java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以java程序
运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,java程序必须重新编译便可以在多种不同的计算机上运行。

6. Java的基础语法

6.1 java中注释有哪几种形式?

java中有三种注释形式:
//------------------------单行注释:通常用于解释方法内某单行代码的作用。
/* */---------------------多行注释:通常用于解释一段代码的作用。
/** */--------------------文档注释:通常用于生成java开发文档。

用得较多还是单行注释和文档注释,多行注释在实际的开发中使用相对较少。

代码的注释不是越详细越好。实际上好的代码本身就是注释,我们要尽量规范和美化自己的代码来减少不必要的注释。
若编程语言足够有表达力,就不需要注释,尽量通过代码来阐述。

举个例子:
去掉下面复杂的注释,只需要创建一个与注释所言同一事物的函数即可。

// check to see if the employee is eligible for full benefits
if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))

将其替换为

if (employee.isEligibleForFullBenefits())

6.2 标识符和关键字

标识符和关键字的区别
标识符:其实就是一个名字。编写程序时,需要给程序、类、变量、方法等取名字。
关键字:关键字就是被赋予特殊意义的标识符,只能用于特定的地方。

Java语言中关键字有哪些?

分类

关键字

访问控制

private

protected

public

类、方法和变量修饰符

abstract

class

extends

final

implements

interface

native

new

static

strictfq

synchronized

transient

volatile

enum

程序控制

break

continue

return

do

while

if

else

for

instanceof

switch

case

default

assert

错误处理

try

catch

throw

throws

finally

包相关

import

package






基本类型

boolean

byte

char

double

float

int

long

short







变量引用

super

this

void





保留字

goto

const






注意点:
1.所有的关键字都是小写的,在IDE中会以特殊颜色显示。
2.default这个关键字很特殊,即属于程序控制,也属于类、方法和变量修饰符,还属于访问控制。
3.在程序控制中,当switch中匹配不到任何情况时,可以使用defau来编写默认匹配的情况。
4.在类、方法和变量修饰符中,从JDK8开始引入默认方法,可以使用default关键字来定义一个方法的默认实现。
5.在访问控制中,如果一个方法前没有任何修饰符,则默认会有一个default,但是这个修饰符加上了就会报错。
6.虽然true,false和null看起来像关键字但实际上他们是字面值,同时你也不可以作为标识符来使用。
6.2.1 final关键字有什么用?

final可以用来修饰类、属性和方法:

  • final修饰的类不可以被继承。
  • final修饰的方法不可以被重写。
  • final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的。
6.2.2 final、finally、finalize的区别
  • final可以修饰类、变量、方法、修饰类表示该类不能被继承,修饰方法表示该方法不能被重写,修饰变量表示该变量是一个常量不能被重新赋值。
  • finally一般作用在try-catch代码块中,在处理异常的时候,我们将一定要执行的代码放到finally代码块中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
  • finalize是一个方法,属于Object类的一个方法,而Object是所有类的父类,该方法一般由垃圾回收器来调用,当我们调用System.gc()方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可以回收的最后判断。
6.2.3 this关键字的用法

this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。this的用法在java中大体可以分为3种:

  • 普通的直接引用,this相当于指向当前对象本身。
  • 形参与成员变量名字重名时,可以用this来区分:
public Person(String name, int age) {
 this.name = name;
 this.age = age;
 }
  • 引用本类的构造器;this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
class Person{
 private String name;
 private int age;

 public Person() {
 }

 public Person(String name) {
 this.name = name;
 }
 public Person(String name, int age) {
  this(name);
  this.age = age;
 }
 }
6.2.4 super关键字的用法

super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。
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 getInfo(){
 System.out.println(this.name); //Child
 System.out.println(super.name); //Father
 }

 }

 public class Test {
 public static void main(String[] args) {
 Student s1 = new Student("Father","Child");
 s1.getInfo();

 }
 }
  • 引用父类构造器,super(参数):调用父类中的某一个构造器(应该为构造器中的第一条语句)。
6.2.5 this与super的区别
  • this指的是当前对象,而super指的是当前对象的直接父类。
  • 调用构造器的区别:this调用本类构造,务必放在构造方法的第一行。super调用父类构造,务必放在子类构造方法首行。
  • 访问成员变量和方法的区别:this会先去访问本类中是否有此属性或方法,本类没有再去父类中查找,而super是直接访问父类中的属性和方法。

注意点:

1、this和super不能同时出现在一个构造函数里面。
因为this(){};这是调用本类无参构造时,如果系统发现在本类的无参构造的第一行没有this(Xxx xx) {} 有参构造调用 或者super调用,编译器会在无参构造中第一行自动加上super();这时就相当于两次调用super();也就是说父类进行了两次初始化。而实例化一个对象,一个构造器只能调用一次,所以会编译错误。如果在本类的无参构造中又调用了本类的有参构造,那么编译器会在本类的其他构造器的第一行加上super();也同样会编译错误。

2、为什么this调用本类构造,务必放在构造方法的第一行。super调用父类构造,务必放在子类构造方法首行。
首先,子类是从父类继承而来,继承了父类的属性和方法,如果在子类中不完成父类成员的初始化,则子类无法使用,因为在java中不允许调用没初始化的成员。在构造器中是顺序执行的,也就是说必须在第一行进行父类的初始化。而super能直接完成这个功能,因此,this()或者super()必须放在第一行。
其次,如上面第一点说的,this或者super不放在构造器的第一行,编译器也会在构造器中的第一行自动放一个空参的super构造器,其他的构造器也可以调用super或者this,也会造成编译错误。

6.2.6 static关键字

static的独特之处

  • 被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象共享。
  • 在类被第一次加载时,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。
  • static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的。
  • 被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。

static存在的意义

  • 它能创建独立于具体对象的域变量或者方法。即使没有创建对象,也能使用属性调用方法!
  • 形成静态代码块以优化程序性能。static代码可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static的顺序来执行每个static块,并且只会执行一次。为什么说static块可以可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化的操作都放在static代码块中进行。

static应用场景

  • 修饰成员变量
  • 修饰成员方法
  • 静态代码块
  • 修饰类【只能修饰内部类也就是静态内部类】
  • 静态导包

static的注意事项
1、静态只能访问静态。
2、非静态既可以访问非静态的,也可以访问静态的。

6.3 java的运算符

6.3.1 自增运算符(++)和自减运算符(- -)

++和- - 运算符可以放在变量之前,也可以放在变量之后,当运算符放在变量之前时(前缀),先自增/减,再赋值;当运算符放在变量之后时(后缀),先赋值,再自增/减。例如:

b = ++a; 就是先自增(自己增加1),再赋值(赋值给b)
b = a++; 就是先赋值(赋值给b),再自增(自己增加1)
6.3.2 移位运算符

移位运算符时最基本的运算符之一,几乎每种编程语言都包含这一运算符。移位操作中,被操作的数据被视为二进制,移位就是将二进制数向左或者向右移动若干位的运算。

移位运算符在各种框架以及JDK自身的源码中使用还是挺广泛的,HashMap(JDK1.8)中的hash方法的源码就用到了位移运算符(hash方法源码如下)

static final int hash(Object key) {
    int h;
    // key.hashCode():返回散列值也就是hashcode
    // ^ :按位异或
    // >>>:无符号右移,忽略符号位,空位都以0补齐
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
  }

在java代码中使用<<>>>>>转换成的指令码运行起来会更高效些。
掌握最基本的移位运算知识还是很有必要的,不光可以帮助我们在代码中使用,还可以帮助我们理解源码中涉及到移位运算符的代码。

Java中有三种移位运算符:

  • <<:左移运算符,向左移若干位,高位丢弃,低位补零。x<<1,相当于x乘以2(不溢出的情况下)。
  • >>:带符号右移,向右移若干位,高位补符号位,低位丢弃。正数高位补0,负数高位补1。x>>1,相当于x除以2。
  • >>>:无符号右移,忽略符号位,空位都以0补齐。

由于doublefloat在二进制中的表现比较特殊,因此不能来进行移位操作。
移位操作实际上支持的类型只有int long,编译器在对shortbytechar类型进行移位前,都会将其转换为int类型再操作。

如果移位的位数超过数值所占有的位数会怎么样?
当int类型左移/右移位数大于等于32位操作时,会先求余(%)后再进行左移/右移操作。也就是说左移/右移32位相当于不进位操作(32%32=0),左移/右移42相当于左移/右移10位(42%32=10)。当long类型进行左移/右移操作时,由于long对应二进制是64位,因此求余操作的基数也变成了64。

也就是说:x位int类型时,x<<42 等同于x<<10x>>42等同于 x>>42x>>>42 等同于x>>>10

左移运算符代码示例:

int i = -1;
System.out.println("初始数据: " + i);
System.out.println("初始数据对应的二进制字符串: " + Integer.toBinaryString(i));
i <<= 10;
System.out.println("左移 10 位后的数据 " + i);
System.out.println("左移 10 位后的数据对应的二进制字符 " + Integer.toBinaryString(i));

输出结果:

初始数据: -1
初始数据对应的二进制字符串: 11111111111111111111111111111111
左移 10 位后的数据 -1024
左移 10 位后的数据对应的二进制字符 11111111111111111111110000000000

由于左移位数大于等于32位操作时,会先求余(%)后再进行左移操作,所以下面的代码左移42位相当于左移10位(42%32=10),输出结果和前面的代码是一样的。

int i = -1;
System.out.println("初始数据: " + i);
System.out.println("初始数据对应的二进制字符串: " + Integer.toBinaryString(i));
i <<= 42;
System.out.println("左移 10 位后的数据 " + i);
System.out.println("左移 10 位后的数据对应的二进制字符 " + Integer.toBinaryString(i));

右移运算符使用类似。

&、| 、^、~(按位与、按位或、按位异或、按位取反)

  • &(按位与):参加运算的两个数,按二进制位进行与运算。
    运算规则:两个数的二进制同为1,结果才为1,否则为0。
  • |(按位或):参加运算的两个数,按二进制位进行或运算
    运算规则:两个数的二进制只要有一个为1结果就是1。
  • ^(异或运算符):参加运算的两个数,按二进制位进行异或运算
    运算规则:两个数的二进制值不同,结果为1。
  • ~(按位取反):将内存中的补码按位取反(包括符号位),所以先要得到补码。
    1.对正数进行按位取反:原码 = 反码 = 补码 --> 按位取反 --> 减一变成原码 --> 符号位不变再取反得到反码
    2.对负数进行按位取反:原码 --> 保留符号位取反 --> 反码 -->加1 -->补码 -->按位取反包括符号位 --> 正数补码=原码=反码

具体示例:

~1(正数的按位取反运算)

1的原码 0000 0001
1的反码 0000 0001
1的补码 0000 0001
按位取反操作 1111 1110
#负数(因为最高位为1,表示为负数),就需要将其变为原码,补码变为原码,首先先减1
变为原码先减一 1111 1101
#变为原码时,符号位不变
再取反 1000 0010 (-2)

~-1(负数的按位取反运行)
-1的原码 1000 0001
-1的反码 1111 1110
-1的补码 1111 1111
按位取反操作 0000 0000
#因为正数的补码、反码、原码都是一个样。
变为原码 0000 0000 (0)

&与&&的区别

&运算符有两种用法:按位与逻辑与

&&运算符是短路与运算。逻辑与跟短路与的差别非常大,虽然两者都要求运算符左右两端的布尔值都是true,整个表达式的值才是true。&&之所以称为短路与运算,是因为如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。

注意: 逻辑或运算符(|)和短路或运算符(||)的差别也是如此。

6.4 continue、break和return的区别是什么?

在循环结构中,当循环条件不满足或者循环次数达到要求时,循环会正常结束。但是有时候可以需要在循环的过程中,当发生某种条件后,提前终止循环,这就需要用到下面几个关键词。

  • continue:指跳出当前的这一次循环,继续下一次循环。
  • break:指跳出整个循环体,继续执行循环下面的语句。

return是用于跳出所在方法,结束该方法的运行。return一般有两种用法:

  • return;:直接使用return结束方法执行,用于没有返回值函数的方法。
  • return value;:return一个特定值,用于有返回值函数的方法。

下面这段程序的运行结果是?

public static void main(String[] args) {
        boolean flag = false;
        for (int i = 0; i <= 3; i++) {
            if (i == 0) {
                System.out.println("0");
            } else if (i == 1) {
                System.out.println("1");
                continue;
            } else if (i == 2) {
                System.out.println("2");
                flag = true;
            } else if (i == 3) {
                System.out.println("3");
                break;
            } else if (i == 4) {
                System.out.println("4");
            }
            System.out.println("xixi");
        }
        if (flag) {
            System.out.println("haha");
            return;
        }
        System.out.println("heihei");
    }

运行结果:

0
xixi
1
2
xixi
3
haha

6.5 变量

成员变量和局部变量的区别?

  • 语法形式: 从语法形式上看,成员变量属于类的,而局部变量是在代码块或者方法中定义的变量或者是方法的参数;成员变量可以被public, private, static等修饰符所修饰,而局部变量不能被访问控制修饰符及static所修饰;但是,成员变量和局部变量都能被final所修饰。
  • 存储方式: 从变量在内存中的存储方式来看,如果成员变量是使用static修饰的,那么这个成员变量是属于类的,如果没有使用static修饰,这个成员变量是属于实例的。成员变量随着对象的创建而存在,随着对象的消失而消失,而对象存在于堆内存,局部变量是在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。
  • 生存时间: 从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。
  • 默认值: 从变量是否有默认值来看,成员变量如果没有被赋予初始值,则会自动以类型的默认值而赋值(一般情况例外:被final修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。所以局部变量使用前必须赋值。

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片:

语雀java面试题 java语言面试_父类_02

带尺寸的图片:

语雀java面试题 java语言面试_java_03

居中的图片:

语雀java面试题 java语言面试_System_04

居中并且带尺寸的图片:

语雀java面试题 java语言面试_语雀java面试题_05

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
  • 项目
  • 项目
  1. 项目1
  2. 项目2
  3. 项目3


创建一个表格

一个简单的表格是这么创建的:

项目

Value

电脑

$1600

手机

$12

导管

$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列

第二列

第三列

第一列文本居中

第二列文本居右

第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPE

ASCII

HTML

Single backticks

'Isn't this fun?'

‘Isn’t this fun?’

Quotes

"Isn't this fun?"

“Isn’t this fun?”

Dashes

-- is en-dash, --- is em-dash

– is en-dash, — is em-dash

创建一个自定义列表


HTML conversion tool

Authors John Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML。

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 语雀java面试题 java语言面试_父类_06

语雀java面试题 java语言面试_父类_07

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章


Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid


  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:


张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五


这将产生一个流程图。:


链接




长方形

圆角长方形

菱形


  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:


Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no


  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎
  2. 注脚的解释 ↩︎