java基本面试题

目录

序言

本文内容是整理和收集Java基本问题,材料源于各类平台文章中,本文编写仅作为学习参看使用。

一、java基本常识

1、什么是jvm?

  Jvm就是Java虚拟机的简称,jvm是运行java字节码的虚拟机。Jvm针对不同系统的特定实现,让它们使用相同的字节码,得到相同的结果。

2、什么是字节码?

  在java中,jvm可以理解的代码就叫做字节码。实际上从写java文件到编译成 .class文件,这个点class文件就是字节码文件。它是由java虚拟机(jvm)编译而来。

3、采用字节码的好处是什么?

  Java语言通过字节码的方式,在一定程度上解决了传统解释型语言的执行效率低的问题,同时又保留了解释型语言可移植的特点,所以Java运行时比较高效。
  由于字节码并不针对一种特定的机器,所以Java程序无需重新编译即可在多种不同的操作系统的计算机上运行。

4、JDK和JRE

  JDK是Java Development Kit,它是功能齐全的就Java SDK。它拥有JRE所拥有的一切,还有编译器(javac)和工具(javadoc和jdb等)。它能够创建和编译程序。
  JRE是Java的运行环境。它是运行以编译的Java程序所需的所有内容的集合,包括Java虚拟机(JVM),Java类库,Java命令和其他的一些基本构件。但是他不能用于创建新程序。

5、Java和C++的区别

  都是面向对象语言,都支持封装、对象和多态。
  Java不提供指针直接访问内存,程序更加安全。
  Java的类是单继承的,c++支持多继承。虽然Java的类不可以多继承,但是接口可以多继承。
  Java都自动内存管理机制,不需要程序员手动释放无用内存。

6、重载和重写的区别

  重载:发生于同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。
  重写:发生在父子类中,方法名、参数列表必须相同,返回值类型必须小于等于父类,抛出的异常范围必须小于等于父类;如果父类访问修饰符为private则子类就不能重写该方法。

7、构造器Constructor是否可被override?

  我们知道父类的私有属性和构造方法不能被继承,所以Constructor不能被override(重写),但是可以被重载(overload),所以你可以看到一个类中有多个构造函数的情况。

8、封装与继承与多态

  • 封装:把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问方法,那么这个类也就没有意义了。

  • 继承:使用已存在的类定义作为基础建立新的类的技术,新类的定义可以增加新的数据或功能,也可以用父类的功能,但不能选择性的继承父类。通过使用继承我们能够方便的使用我们以前的代码。
    继承要注意的点:
      1)子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但父类中的私有属性和方法子类是无法访问的,只是拥有。
      2)子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
      3)子类可以用自己的方法实现父类的方法。

  • 多态:程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,这一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

  在java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

9、接口和抽象类的区别是什么?

  • 接口的方法默认就是public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象方法。

  • 接口中的实例变量默认是final类型,而抽象类种就不一定。

  • 一个类要实现接口的话,就要实现接口的所有方法,而抽象类就不一定。

  • 接口不能用new实例化,但可以声明,但必须是引用一个实现该接口的对象。从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为规范。

  • 在JDK 8 中,接口也可以定义静态方法,可以直接调用接口名调用。实现类和实现是不可以调用的。如果同时实现两个接口,接口中定义了一样的默认方法,则必须重写,不然会报错。

10、抽象类必须要有抽象方法吗?抽象类能使用final修饰吗?

  • 抽象类中不一定包含抽象方法,但是包含抽象方法的类一定要被声明为抽象类。

  • 抽象类不能用final修饰。当final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式定义为final方法,这明显违背了抽象类存在的意义了。

11、线程安全性

  • String中的对象是不可变的,就可以理解为常量,线程安全。AbstractStringBuilder 是StringBuilder 与 StringBuilder的公共父类,定义了一些字符串的基本操作,如expandBuilder、append、insert、indexOf等公共方法。StringBuilder对方法加了同步锁或者对调用方法加了同步锁,所以是线程安全的。Stringbuilder并没有对方法进行加同步锁,所以是非线程安全的。性能每次对String类型进行改变的时候,都会生成一个新的String对象。StringBuffer每次都会对StringBuffer对象本省进行操作,而不是生成新的对象并改变对象引用。相同的情况下使用StringBuilder相比使用StringBuffer仅能获得10%~15%左右的性能提升,但却要冒多线程不安全的风险。

  • 操作少量的数据:适用String。

  • 单线程操作字符缓冲区下操作大量数据:适用StringBuilder。

  • 多线程操作字符串缓冲区下操作大量数据:适用StringBuffer。

12、== 与 equals

  • ==:它的作用是判断两个对象的地址是不是相等。即:判断两个对象是不是同一个对象(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)。

  • equals():它的作用是判断两个对象是否相等

  • 情况一:类没有覆盖equals()方法。通过equals()比较两个该类对象时,等价于通过 == 比较这两个对象。

  • 情况二:类覆盖了equals()。一般,我们覆盖equals()方法来比较两个对象的内容相等;若它们的内容相等,则返回true(即,返回这两个对象相等)。

13、hashCode 与 equals

  • 问题:你重写过hashCode和equals吗?为什么重写equals是必须要重写hashCode方法?

  • hashCode介绍:hashCode()的的作用是获取哈希码,也称散列码;实际上它返回的是一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode()定义在JDK的Object.java中,这就意味着Java中任何类都包含都hashCode()函数。散列表存储的是键值对,它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码。

  • 为什么要有hashCode?如果两个对象相等,则hashCode一定也是相等的;两个对象相等,对两个对象分别调用equals方法都返回true;两个对象有相同的hashCode值,它们也不一定是相等的(因为不同对象也可能产生相同的hashCode,这是概率性问题);因此,equals方法被覆盖过,则hashCode方法也必须被覆盖;hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向同样的数据)。

14、什么是反射机制?

  • Java的反射机制在运行状态中,对于任意一个类,都能够知道这个类所有属性和方法;对于任意一个对象,能够能调动它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方发的功能称为Java语言的反射机制。

  • 静态编译:在编译时确定类型,绑定对象。

  • 动态编译:在运行时确定类型,绑定对象。

  • 反射机制的优缺点:
    优点:运行期类型的判断,动态加载类,提高代码的灵活度。
    缺点:性能瓶颈。反射相当于一系列解释操作,通知JVM要做事情,性能比直接的Java代码要慢得多。

15、反射的应用场景

  • 反射是框架设计的灵魂。在我们平时项目开发过程中,基本生很少会直接使用到反射机制,但这并不能说明反射机制没有用,实际上有许多设计、开发斗鱼反射机制有关,一如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用到的Spring/Hibernate等框架也大量使用到了反射机制。

  • 举例:我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;Spring框架也用到很多反射机制,最经典的就是xml配置模式。

  • Spring通过XML配置模式装载Bean过程:
    1)将程序内所有的XML或Properties配置文件加载入内存中;
    2)Java类里面解释xml或Properties里面的内容,得到对应的实体类的字节码字符串及相关的属性信息;
    3)使用反射机制,根据这个字符串获得某个类的Class实例;
    4)动态配置实例的属性。

16、Java中IO流分几种?

  • 按照流的方向分,可以分输入和输出流;

  • 按照操作单元划分,可以分字节流和字符流;

  • 按照流的角色划分,可以分节点流和处理流。

  • InputStream/Reader:所有的输入流的基类,前者是字节输入流,后者是字符输入流。

  • OutputStream/Writer:所有的输出流的基类,前者是字节输出流,后者是字符输出流。

  • 按照操作方式分类结构图:

  • 按照操作对象分类结构图:

17、如何理解面向对象?

  • 类是面向对象中的一个很重要的概念,因为类是很多歌具有相同属性和行为特征的对象所抽象出来的,对象是类的一个实例。

  • 面向对象共有三个特征:封装,继承,多态。

  • 封装:把一些属性和发那个发封装起来,形成一个类;可以隐藏实现细节。提高了代码的复用性。也提高了安全性。封装的意义在于保护或者防止代码或数据被我们无意中破坏。

  • 封装的作用:提高了代码的复用性;隐藏了实现细节,还要对外提供够可以访问的方式,便于调用者的使用。提高了安全性。

  • 继承:是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有类被称做父类,子类能够调用父类的非private修饰的成员,同时还可以自己添加一些新的成员,扩充父类,甚至重写父类已有的方法,使其变现符合子类的特征。

  • 继承的好处:提高了代码的可维护性;提高了代码的可复用性,让类与类之间产生了继承关系。

  • 继承的弊端:类与类之间的耦合度过高。

  • 继承特点:java中类只能够单继承,不能多继承,可以多重继承;封装和继承其实有一个共同的目的就是代码重用。

  • 多态:多态是同一个行为具有多个不同表现形式的能力。多态性是对象多种表现形式的体现,java作为面向对象的语言,同样可以描述一个事物的多种形态。方法的重载和重写都提现了多态性。类中多个方法的重载叫多态,父子类中方法的覆盖也叫多态。多态有方法的多态和对象的多态。

18、Super

  • Super:用来表示当前对象中包含的父类对象空间的引用,调用父类成员变量:super.成员变量;调用方法的成员方法:super.成员方法()。

19、阐述静态变量和实例变量的区别

  • 静态变量也叫类变量,这种变量前加了static修饰符。可以直接用类名调用,也可以用对象调用,而且所有对象的同一个类变量都是共享同一块内存空间。

  • 实例变量也叫对象变量,这种变量没有加static修饰符。智能通过对象调用,而且所有对象的统一个实例是共享不同的内存空间的。

  • 区别在于:静态变量是所有对象共有的,某一个对象将它的值改变了,其他对象再获取它的值,得到的是改变后的值。实例变量则是每一个对象私有的,某一个对象将它的值改变了,不影响其他对象取值的结果,其它对象仍会得到实例变量一开始就被赋予的值。

20、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?

  • 不可以。因为非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用是不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,如果从一个static方法中发出对非static方法的调用,那个非static方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个静态(static)方法内部不可以发出对非静态(non-static)方法的调用

21、java的语言特点

  • 简单性,解释性,面向对象,高性能,分布式处理,多线程,健壮性,动态性,安全性,跨平台性,移植性。
  • 简单性:java没有像C++那样的指针,运算符重载,类的多继承。并且实现了垃圾回收机制,简化了开发这对于内存管理的工作。
  • 面向对象:对象是指封装数据和操作方法的程序实体。Java提供了简单的类机制以及动态接口。表现形式是封装,继承,多态。
  • 跨平台性:java语言开发的软件在Windows/mac/Linux系统下都能运行,只需要在操作系统上安装虚拟机即可。
  • 移植性:如果java直接编译成系统识别的二进制码,可能一个标识在Windows下是1100,二Linux下是1001,这样java在Windows下编译后无法在Linux运行。所以java先编译成字节码(中间码),有JVM来解释执行,而这个jvm对于主流的操作系统都有相应的版本,目的就是将统一的中间码编译成对应操作系统识别的二进制码,然后执行。所以不论你在什么系统中编译的java,得到的都是统一的字节码。

22、Java的基本数据类型有哪些,各占几个字节

基本数据类型 | byte | short | int | float | long | double | boolean | char

  • | - | - | - | - | - | - | - | - |
    占用字节数 | 1 | 2 | 4 | 4 | 8 | 8 | 占一位,而不是字节 | 2

扩展:
引用数据类型:
字符串、数组、类、接口、Lambda等,注意事项:
1)字符串不是基本类型,而是引用类型。
2)浮点型可能只是一个近似值,并非精确值(所以不要用来比较)。
3)数据范围与字节数不一定相关,例如float数据范围比long更加广泛(long只能表示整数,二float表示的是小数),但是float是4字节,long是8字节。
4)浮点数当中默认类型是double。如果一定要使用float类型,需要加上一个后缀F。如果是整数,默认为int类型,如果一定要使用long类型,需要加上一个后缀L。推荐使用大写后缀字母。

23、long(8)与float(4)的取值范围谁大谁小?

  Float的取值范围更大。虽然long是8个字节,float是4个字节,但是float的取值范围比long的取值范围更大,因为float的算法与long的不一样。Long只能表示整数而float表示的是小数。举个例子:1到10之间的整数只有那么几个,那么1到10之间的小数有多少个呢?

24、Java语言中的字符char可以存储一个中文汉字吗?为什么?

  可以的。因为Java默认使用Unicode编码,而在Unicode编码中一个中文汉字占两位,所以char可以存储一个中文汉字。

25、java中到底是传值还是传地址?

  事实上,java中传递的都是值,因为地址也是值。所以不管是传递基本数据类型还是引用数据类型,都是传值。

26、最有效的算出2 * 8 的结果

  2乘8相当于2乘以2的3次方,所以这里只需要将2向左位移3位即可。即:2<<3(向左位移为乘,向右位移为除)。

27、一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?

  • 可以。这么做的目的只有一个,就是不让其他类创建本类对象,交给子类完成。
  • 抽象类:抽象中不一定包含抽象方法,但是有抽象方法的类一定是抽象类。抽象类的子类必须全部重写抽象父类的抽象方法,除非子类也是抽象类。

28、abstract不能与哪些关键字共存?

  • 1)static:abstract修饰的是对象级别,static修饰的是类级别的,对象方法和类方法是冲突的。
  • 2)final:final修饰的是常量级别的,不可被修改。Abstract的目的就是wield让子类实现,显然final的存在会使得abstract变得没有意义。
  • 3)private:private修饰的类或者方法只有自己能使用,子类无法访问,显然和abstract是矛盾的。

29、谈一谈for循环和while的区别

  控制条件语句所控制的那个变量,在for循环结束后,就不能再被访问到了,二while循环结束还可以继续使用,如果你想继续使用,就用while,否则就推荐用for。原因是for循环结束,该变量就从内存中消失,能够提高内存的使用效率。在已知循环次数的时候推荐使用for,循环次数次数未知的时推荐使用while。

30、java面向对象的六大原则(模式设计的六大原则)

  单一职责、开放封闭,里氏替换、依赖倒置、接口隔离、迪米特法则(最少知道原则)。

31、java有什么核心优势让其流行?

  跨平台是JAVA语言的优势,在各个平台生都可以使用java语言。Java语言还具有一下优势:安全性,面向对象,简单性,高性能,分布式,多线程,健壮性。

32、标识符能不能以汉字开头?为什么?

  可以,java规定了标识符要一数字、字母、美元符号和下划线组成并且不能以数字开都。而java默认采用的是Unicode编码,在Unicode编码中一个汉字相当于一个字母,所以可以使用汉字开头。但是日常的开发中不建议使用汉字。并且参照阿里巴巴的编程规范的话,是不能以下划线和美元符号开头或结尾,不能中英文混用(包括拼音),更不能使用汉字。

33、java中有没有goto语句?有没有goto关键字?

  Java中没有goto语句。但是java中goto仍作为保留字,所以有关键字。

34、java语言中整形常量的四种表现形式:

  • 二进制:要求0B或0b开始,如:0B10110。
  • 八进制:要求以0开头,如015。
  • 十进制:不加开头。
  • 十六进制:要求以0X或者0x开头,如:0x15。

35、java中的垃圾回收算法

  引用计数法、引用可达法(根搜索算法)

36、int能否自动转换成byte,short,char?是否一定条件才能转换?

  不能自动转换,需要强制类型转换。

37、java里面for循环中i++与++i的区别

  首先我们应该都知道++i与i++的区别是: ++i 是先执行 i=i+1 再使用 i 的值,而 i++ 是先使用 i 的值再执行 i=i+1;
  在for循环中++i与i++结果并没有区别,但在Java中i++语句是需要一个临时变量取存储返回自增前的值,而++i不需要

for(int i=0; i<10;)
{
    System.out.print(i);
    i++;
    //++i;
}
//0123456789
posted @ 2020-02-01 15:43  落花桂  阅读(487)  评论(0编辑  收藏  举报
返回顶端
Live2D