最近在准备秋招,收集整理了Java程序员面试笔试的常见问题,供大家分享,欢迎批评指正!
本文的主要内容:
- 谈谈对JVM、JDK和JRE的理解(JRE和JDK的区别是什么?)什么是字节码?
- Java语言的优点,和C++的异同?
- 重载和重写的区别?
- 对main方法的认识
- 谈谈对构造函数的认识
- java程序初始化的顺序
- 值传递与引用传递
- ==与equal方法
- hashcode与equal
- String、StringBuffer与StringBuilder的异同
一、JVM、JDK与JRE
1.什么是JVM?
Java虚拟机(JVM)是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现(Windows、Linux、macOS),目前是使用相同的字节码,它们都会给出相同的结果。
2.什么是字节码?采用字节码的好处?
在Java中,JVM可以理解的代码就是字节码(拓展名为.class的文件),它不面向任何特定的处理器,只面向虚拟机。java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且由于字节码并不针对一种特定的及其,因此,Java程序无须重新编译即可在多种不同操作系统的计算机上运行。
3.Java程序从源程序到运行的步骤?
4.JDK和 JRE的区别
JDK:Java Development Kit,Java开发工具包,提供了Java开发和运行的环境。可以创建和编译程序。
JRE:Java Runtime Environment,Java运行环境,为Java的运行提供了所需的环境,包括JVM、java类库和其他的基础构件。不能用于创建新程序
具体来说JDK其实包含了JRE,还包含了编译Java源码的编译器javac,还包含了很多Java程序调试和分析的程序。
二、Java语言的优点
- 纯面向对象的编程语言
- 平台无关性
- 提供了很多内置的类库
- 提供了对WEB应用开发的支持
- 具有很好的安全性和健壮性
Java和C++的异同?
- 都是面向对象的语言,都支持封装、继承、多态
- Java不提供指针直接访问内存,程序内存更加安全
- Java的类是单继承(但可以利用接口实现多重继承),C++支持多重继承
- Java有内存管理机制,不需要程序员手动释放无用内存
三、谈谈对public static void main(String[] args)方法的认识
1.main方法为Java程序的入口方法
2.字符串参数args为开发人员在命令行状态下与程序交互提供了手段
3.main方法的格式问题?
- public和static可以互换位置
- 可把main方法定义为final
- 可用synchronized修饰
- 不可用abstract修饰
- 必须保证main方法的返回值为void,并有static、public修饰
4.同一个.java方法中是否能有多个main方法?
每个类中都可以定义main方法,但只有与文件名相同且用public修饰的main方法才能作为程序的入口。
四、java程序初始化顺序?
1.三个原则:
- 静态对象(变量)优于非静态对象(变量)初始化
- 父类优于子类初始化
- 按照成员变量定义先后顺序初始化
2.执行顺序:父类静态变量——父类静态代码块——子类静态变量——子类静态代码块——父类非静态变量——父类非静态代码块——父类构造函数——子类非静态变量——子类非静态代码块——子类构造函数
五、Java作用域有哪些
作用域 | 当前类 | 同一package | 子类 | 其他package |
public | 可见 | 可见 | 可见 | 可见 |
protected | 可见 | 可见 | 可见 | 不可见 |
default | 可见 | 可见 | 不可见 | 不可见 |
private | 可见 | 不可见 | 不可见 | 不可见 |
修饰符只能修饰成员变量,不能修饰局部变量。
private、protected不能修饰类
六、一个java文件中是否可以定义多个类
一个Java文件可以定义多个类,但最多只有一个类被public修饰,并且这个类的类名必须与文件名相同。若这个文件中没有public的类,则文件名随便是哪个类的类名即可。
需要注意的是,当使用javac命令编译.java文件时,会为每个类都生成一个.class文件。
七、谈谈构造函数
构造函数是一种特殊的函数,用来在对象实例化时初始化对象的成员变量。构造函数的特点:
1.必须与类名相同,不能有返回值。
2.每个类可以有多个构造器,当开发人员没提供构造器时,编译器会提供一个无参的默认构造器,该构造器不会执行任何代码。
3.构造器可以有0,1,2,3,,,个参数
4.构造器总是伴随着new操作一起调用,不能由程序编写者直接调用。构造函数在对象实例化时会被自动调用,且只运行一次。
5.主要作用:完成对象的初始化工作。
6.构造函数不能被继承,不能被覆盖,可以被重载
7.当父类和子类都没有定义构造函数时,编译器会给父类和子类都生成默认的无参构造器。默认构造器的修饰符只跟当前类的修饰符有关。
8.子类可通过super关键字显示的调用父类的构造函数。父类没有提供无参构造器时,子类构造函数必须显示调用父类构造函数;父类有无参构造函数,子类为显示调用父类构造函数时,编译器会默认调用父类的无参构造函数。
八、package的作用是什么?
1.提供多层命名空间,解决命名冲突。
2.对类按功能分类,使项目组织更加清晰
九、面向对象的有哪些特征?
- 抽象、
- 继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,通过继承我们能够十分方便的实现代码的复用。
- 封装:将一个对象的属性私有化,同时提供一些可以被外界访问的属性和方法。
- 多态:所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用发出的方法调用哪个类中实现的方法,必须由程序运行期间才确定。在Java中实现多态的方式有两种:继承(通过子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)
十、什么是继承?
继承是面向对象的重要特性之一。通过继承,子类可以使用父类的一些成员变量和方法,从而提高代码的复用率,提高开发效率。继承有如下特性:
- Java语言不支持多重继承
- 子类只能继承父类非私有的成员变量和方法
- 当父类和子类成员变量或方法签名相同时,子类的成员变量或方法签名会覆盖父类,不会继承。
十一、什么是多态?
Java提供了编译时多态和运行时多态两种机制。前者通过方法重载实现的,后者通过方法覆盖实现(上面已经提到)。
十二、重载和重写的区别?
1.重载:发生在同一个类中
- 重载通过不同的的方法参数来区分
- 不能通过方法的访问权限、返回值、抛出异常类型区分
2.重写:发生在父子类中
- 方法名、参数列表相同
- 返回值范围小于父类
- 抛出异常范围小于父类
- 访问修饰符范围大于父类
十三、抽象类与接口的区别?抽象类必有要有抽象方法么?
1.抽象类和接口的区别?
- 接口的方法默认都是public,所有的方法在接口中不能有实现(Java8开始接口可以有默认的实现),而抽象类中可以有非抽象方法。
- 接口中的成员变量默认都是final类型
- 一个类可以实现多个接口,但最多只能继承一个抽象类
- 一个类实现接口的话要实现接口的所有方法,而抽象类不一定。
- 接口不能用 new 实例化,但可以声明,但是必须引用一个实现该接口的对象。从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。
2.抽象类必须要有抽象方法么?
抽象类中不一定包含抽象方法,但包含抽象方法的类一定是抽象类。
3.抽象类能使用final修饰么?
抽象类不能用final修饰,当final修饰一个类时,表明这个类不能被继承,违背了抽象类存在的意义。
十四、内部类有哪些?
十五、如何获父类名
this.getClass().getSuperClass().getName()
十六、this和super的区别?
this用来指向当前实例对象,super用来访问父类的方法或成员变量。
当子类构造函数需要显示调用父类构造函数时,super()必须为构造函数的第一条语句。
十七、break、continue、return的区别?
break用于直接强行跳出当前循环,不再执行剩余代码,多层循环嵌套中,break出现在内层循环时,它将仅仅只终止内循环,不影响外层循环。(跳出多层循环,可使用带有标识的break语句)。
continue用于停止当次循环,回到循环起始处,进入下一次循环操作。
return用来表示从一个方法返回,可以使程序控制返回到调用方法的地方。
十八、变量命名规则
Java语言中,变量名、函数名统称为标识符,标识符只能有字母、数字、下划线和$符号组成,第一个字符不能是数字。
十九、final、finally、finalize
1.final
- final变量:对于基本数据类型final使数值恒定不变;Java允许声明为final但又未给初值的域(空白final),但必须确保使用前被初始化;如果修饰引用类型变量,则在对其初始化之后便不能再让其指向另一个对象。
- final方法:被final修饰的方法,该方法不允许任何子类重写这个方法,但子类仍可以使用这个方法。
- final类:被final修饰的类不能被继承,final类中的所有的成员方法都会被隐式的指定为final方法(不能被重写)。final类中的成员变量可以根据需要设为final。
2.finally:finally表示异常处理的一部分,表示该部分一定会在最后被执行
3.finalize:finalize方法是Object提供的实例方法,垃圾回收器执行时会调用回收对象的finalize方法。它时Object类中定义的,因此所有的类都继承了它。子类可以覆盖finalize方法实现对其它资源的回收。
二十、谈谈static关键字?
static关键字的基本作用,简而言之就是:方便在没有创建对象的情况下进行调用(方法/变量)。以下摘自《Java编程思想》
static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法,这实际上真是static方法的主要用途。
1.static方法:static方法一般被称为静态方法,静态方法不依赖于任何对象,所以静态方法中不能使用this和super。静态方法中不能访问非静态的成员变量和方法。反过来可以。
2.static变量:静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当类初次加载时会被初始化。而非静态变量是对象所拥有的的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
static不能用来修饰局部变量。
3.static代码块:类加载的时候静态代码会执行一次。很多时候会将只需要进行一次的初始化操作放在static代码块中进行,以提高系统性能。
二十一、Java有哪些基本数据类型
数据类型 | boolean | byte | char | short | Int | long | float | double |
字节长度 | 1 | 1 | 2 | 3 | 4 | 8 | 4 | 8 |
封装器类 | Boolean | Byte | Character | Short | Integer | Long | Float | Double |
二十二、值传递与引用传递
按值传递:表示方法接收的是调用者提供的值。引用传递:表示方法接收的是调用者提供的变量的地址。一个方法可以修改传递引用多对应的变量值,而不能修改传递调用所对应的变量值。
Java语言总是按值传递。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。
二十三、String str = “abc”与String str1 = new String(“abc”)一样么?二者相等么?
这两种的创建方式有差别
- String str = “abc”,这种创建方式先检查字符串常量池中有无“abc”,如果字符串常量池中没有,则创建一个,然后str指向字符串常量池中的对象,如果有,则直接将str指向字符串常量池中的“abc”。
- 第二种是直接在堆内存空间创建一个新的对象
str与str1不相等,因为一个是堆内存中的String对象,一个是常量池中的对象
二十四、String、StringBuffer、StringBuilder的区别?String为何是不可变的?
1.可变性:String类中使用了final关键字修饰字符串数组保存字符串,private final char value[],所以String对象时不可变的。StringBuffer和StringBuilder都继承自AbstractStringBuilder类,AbstractStringBuilder使用字符串数组保存字符串,但没final修饰,所以是可变的。
2.线程安全性:String中对象时不可变的,可以理解为常量,线程安全。StringBuffer对方法加了同步锁,线程安全。StringBuilder没有对方法加同步锁,非线程安全。
3.性能:每次对String类型的改变都是会重新生成一个String对象,然后指针指向新的String对象。StringBuffer和StringBulider都是对本身进行操作,不会改变对象的引用,形同情况下,StringBuilder会比StringBuffer获得10%—15%的性能提升。
使用总结:
- 操作数据少使用String
- 单线程下操作大量数据使用StringBuilder
- 多线程操作大量数据使用StringBuffer
二十五、==与equal
1.==:它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。
基本数据类型:==比较的是值。
引用数据类型:==比较的是内存的地址
2.equal():它的作用也是判断两个对象是否相等。有两种情况:
- 类没有覆盖equal()方法,则通过equal()比较两个对象时,等价通过“==”比较这两个对象。
- 类覆盖了equal()方法。一般,我们都覆盖了equal()方法比较两个对象的内容是否相等;相等则返回true。
String的equal方法被重写过,比较的是值。
二十六、hashCode与equal
1.hashcode():hashCode()的作用是获取哈希码,也称为散列码。它实际返回的是一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
2.hashCode()的作用?
hashCode()定义在JDK的Object.java中,这就说Java中任何类都拥有hashCode函数。但是仅仅当创建并使用某个类的散列表时,该类的hashCode()才有作用。
HashSet中如何检查重复:当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()
方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
3.hashCode与equal()
- 如果两个对象相等,则hashcode一定相同
- 如果两个对象相等,对两个对象分别调用equal方法都返回ture;
- 两个对象有相同的hashcode值,他们不一定相等
- equal方法覆盖过,hashcode也必须被覆盖
- hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
推荐阅读:Java hashCode() 和 equals()的若干问题解答