Java常见面试题整理【1】

1. 什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? 

	java的跨平台不是java源程序的跨平台 ,如果是这样,那么所以语言都是跨平台的, java源程序先经过javac编译器编译成二进制的.class字节码文件(java的跨平台指的就是.class字节码文件的跨平台,.class字节码文件是与平台无关的),.class文件再运行在jvm上,java解释器(jvm的一部分)会将其解释成对应平台的机器码执行,所以java所谓的跨平台就是在不同平台上安装了不同的jvm,而在不同平台上生成的.class文件都是一样的,而.class文件再由对应平台的jvm解释成对应平台的机器码执行。
	再解释下机器码和字节码的区别: 
	一,机器码,完全依附硬件而存在~并且不同硬件由于内嵌指令集不同,即使相同的0 1代码 意思也可能是不同的~换句话说,根本不存在跨平台性~比如~不同型号的CPU,你给他个指令10001101,他们可能会解析为不同的结果。
	二,我们知道JAVA是跨平台的,为什么呢?因为他有一个jvm,不论哪种硬件,只要你装有jvm,那么他就认识这个JAVA字节码,至于底层的机器码,咱不用管,有jvm搞定,他会把字节码再翻译成所在机器认识的机器码。

2. JDK和JRE的区别是什么?


 JRE: Java Runtime Environment  
 JDK:Java Development Kit
 JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。
 JDK顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。
 如果你需要运行java程序,只需安装JRE就可以了。如果你需要编写java程序,需要安装JDK。

3. ”static”关键字是什么意思?Java中是否可以覆盖(override)一个private或者是static的方法?

首先是static关键字,static原意是“静态的”。

①static可以修饰内部类,但是不能修饰普通类。静态内部类的话可以直接调用静态构造器(不用对象)。


②static修饰方法, static 方法就是没有 this 的方法。在 static 方法内部不能调用非静态方法,反过来是可以的。因为静态的成员属于类,随着类的加载而加载到静态方法区内存,当类加载时,此时不一定有实例创建,没有实例,就不可以访问非静态的成员。类的加载先于实例的创建。 而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用 static 方法。这实际上正是 static 方法的主要用途。 方便在没有创建对象的情况下来进行调用(方法/变量)。

最常见的static方法就是main,因为所有对象都是在该方法里面实例化的,而main是程序入口,所以要通过类名来调用。还有就是main中需要经常访问随类加载的成员变量。

③static修饰变量,就变成了静态变量,随类加载一次,可以被多个对象共享。

④static修饰代码块,形成静态代码块,用来优化程序性能,将需要加载一次的代码设置成随类加载,静态代码块可以有多个。

Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。
还有私有的方法不能被继承,子类就没有访问权限,肯定也是不能别覆盖的。

4. Java支持的数据类型有哪些?什么是自动拆装箱?


  

基本数据类型:

整数值型:byte,short,int,long, 字符型:char

浮点类型:float,double

布尔型:boolean

整数默认int型,小数默认是double型。Float和long类型的必须加后缀。
首先知道String是引用类型不是基本类型,引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中。引用类型包括类、接口、数组等。String类还是final修饰的。
 而包装类就属于引用类型,自动装箱和拆箱就是基本类型和引用类型之间的转换,至于为什么要转换,因为基本类型转换为引用类型后,就可以new对象,从而调用包装类中封装好的方法进行基本类型之间的转换或者toString(当然用类名直接调用也可以,便于一眼看出该方法是静态的),还有就是如果集合中想存放基本类型,泛型的限定类型只能是对应的包装类型。

5. Java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?

方法重写的原则:

  1. 重写方法的方法名称、参数列表必须与原方法的相同,返回类型可以相同也可以是原类型的子类型(从Java SE5开始支持)。
  2. 重写方法不能比原方法访问性差(即访问权限不允许缩小)。
  3. 重写方法不能比原方法抛出更多的异常。
  4. 被重写的方法不能是final类型,因为final修饰的方法是无法重写的。
  5. 被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写。
  6. 被重写的方法不能为static。如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足重写条件,那么会发生编译错误;反之亦然。即使父类和子类中的方法都是静态的,并且满足重写条件,但是仍然不会发生重写,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配。
  7. 重写是发生在运行时的,因为编译期编译器不知道并且没办法确定该去调用哪个方法,JVM会在代码运行的时候作出决定。

方法重载的原则:

  1. 方法名称必须相同。
  2. 参数列表必须不同(个数不同、或类型不同、参数类型排列顺序不同等)。
  3. 方法的返回类型可以相同也可以不相同。
  4. 仅仅返回类型不同不足以成为方法的重载。
  5. 重载是发生在编译时的,因为编译器可以根据参数的类型来选择使用哪个方法。

重写和重载的不同:

  1. 方法重写要求参数列表必须一致,而方法重载要求参数列表必须不一致。
  2. 方法重写要求返回类型必须一致(或为其子类型),方法重载对此没有要求。
  3. 方法重写只能用于子类重写父类的方法,方法重载用于同一个类中的所有方法。
  4. 方法重写对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制。
  5. 父类的一个方法只能被子类重写一次,而一个方法可以在所有的类中可以被重载多次。
  6. 重载是编译时多态,重写是运行时多态。

6. Java中,什么是构造方法?什么是构造方法重载?什么是复制构造方法?

    java中的构造函数是为了初始化对象的,构造函数的函数名和类名一致,默认的构造函数没有参数,没有返回值,构造函数的函数体内,没有内容。构造函数的重载是函数名与类名相同,参数类型不同,参数不同。同样的作用也是为了初始化对象的,当新对象被创建的时候,构造函数会被调用。

  
关于复制构造函数:C++中的复制构造函数通常有三种作用
1.对象作为函数参数
2.对象作为函数返回值
3.使用一个对象对另一个对象初始化。
C++语法允许用户定义自己的复制构造函数以实现自定义的复制,比如说进行深复制。Java并不支持这样的复制构造函数。但是这并不代表Java中没有这种机制,在Java中Object类的clone()方法就是这种机制的体现。而且通过以上三种方式对Java对象进行的操作都是对引用的操作,不像C++里面是对原对象的操作,因此Java中也不需要考虑需要使用复制构造函数这种问题。

7.  接口和抽象类的区别是什么?

从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。

1.抽象类可以有构造方法,接口中不能有构造方法。 
2.抽象类中可以有普通成员变量,接口中没有。
3.抽象类中可以包含非抽象的普通方法,接口中所有方法必须都是抽象的。 
4.抽象类中的抽象方法的访问类型可以是public,protected,但接口中的抽象方法只能是public,并且默认为
  public abstract类型。
5.抽象类中可以包含静态方法,接口中不能有。
6.抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是
  public staticfinal类型。
 7.一个类可以实现多个接口,但只能继承一个抽象类。

8.  什么是值传递和引用传递?

值传递是指将值的副本传递给调用的函数,调用的函数可以改变副本的值,但是并不会影响main函数中的原值。 引用传值,传递的是对象的引用,同一个引用指向相同的实体,所以改变引用指向实体的值,可以影响main函数中实体的值。
 

一:搞清楚 基本类型 和 引用类型的不同之处

int num = 10;
String str = "hello";


如图所示,num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。

二:搞清楚赋值运算符(=)的作用

num = 20;
str = "java";

对于基本类型 num ,赋值运算符会直接改变变量的值,原来的值被覆盖掉。
对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。
如上图所示,"hello" 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)
 
三:调用方法时发生了什么?参数传递基本上就是赋值操作。
第一个例子:基本类型

void foo(int value) {
    value = 100;
}
foo(num); // num 没有被改变

第二个例子:没有提供改变自身方法的引用类型

void foo(String text) {
    text = "windows";
}
foo(str); // str 也没有被改变

第三个例子:提供了改变自身方法的引用类型

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("4");
}
foo(sb); // sb 被改变了,变成了"iphone4"。

第四个例子:提供了改变自身方法的引用类型,但是不使用,而是使用赋值运算符。

StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"。

重点理解为什么,第三个例子和第四个例子结果不同?

下面是第三个例子的图解:
 
builder.append("4")之后
 
下面是第四个例子的图解:
 
builder = new StringBuilder("ipad"); 之后



©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页