1、JVM vs JDK vs JRE
①Java虚拟机(JVM)是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的JVM实现是Java语言“一次编译,随处可以运行”的关键所在。JVM并不是只有一种!只要满足JVM规范,每个公司、组织或者个人都可以开发属于自己的专属JVM。
速记:JVM-Java虚拟机-运行Java字节码-不同系统相同字节码相同结果-JVM不只有一个
②JDK(Java Development Kit)是功能齐全的JavaSDK,拥有JRE所拥有的一切,还有编译器(javac)和工具(如javadoc、jdb)。它能够创建和编译程序。
速记:JDK-功能齐全JavaSDK-能够创建和编译程序
③JRE是Java运行时环境,它是运行已编译Java程序所需的所有内容的集合,包括Java虚拟机(JVM),Java类库,Java命令和其他的一些基础构件。但是,它不能用于创建新程序。
速记:JRE-Java运行时环境-不能创建程序
拓展:如果只是运行Java程序,安装JRE即可,如果需要Java编程方面的工作,则需要JDK。但这不是绝对的,当要使用JSP部署Web应用程序时,从技术上讲只是在应用程序服务器中运行Java程序,但应用程序服务器会将JSP转换为Java servlet,并且需要使用JDK来编译servlet。
2、什么是字节码?采用字节码的好处是什么?
在Java中,JVM可以理解的代码就叫做字节码(即扩展名为.class的文件),它不面向任何特定的处理器,只面向虚拟机。Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植性的特点。由于字节码并不针对一种特定的机器,因此,Java程序无须重新编译便可在不同操作系统的计算机上运行。
Java程序从源代码到运行的过程:.java->javac编译->.class->解释器&JIT->机器码
注:在 .class->机器码 这一步中,JVM类加载器先加载字节码文件,然后通过解释器逐行解释执行,这种方式效率低,而且有些方法和代码块是经常需要被调用(即热点代码),所以引进了JIT编译器,JIT属于运行时编译。当JIT编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。这也解释了为什么Java是编译与解释共存的语言。
速记:字节码-JVM能理解的代码-.class文件-不面向处理机只面向虚拟机-解决传统解释型语言效率低但保留其可移植性-好处为Java程序无需重新编译便可在不同操作系统的计算机上运行
Java是编译与解释共存的语言-JIT运行时编译-JIT完成第一次编译后保留字节码对应的机器码
3、为什么不全部使用AOT(编译器)呢?
JDK支持分层编译和AOT协作使用,AOT可以提前编译节省启动时间。举个例子:CGLIB动态代理使用的是ASM技术,这种技术原理是运行时直接在内存中生成并加载修改后的字节码文件,如果全部使用AOT提前编译,就不能使用ASM技术。为了支持Java语言的动态特性,所以选择使用JIT即即时编译器。
速记:不用AOT-为了支持Java语言的动态特性
4、为什么说Java语言“编译与解释并存”?
高级编程语言按程序的执行方式可分为两类:
①编译型:编译型语言会通过编译器将源代码一次性翻译成可被该平台执行的机器码。一般情况下,编译语言的执行速度比较快,开发效率比较低。常见的编译性语言有C、C++、Go等。
②解释型:解释型语言会通过解释器一句一句的将代码解释为机器代码后再执行。解释型语言开发效率比较快,执行速度比较慢。常见的解释型语言有Python、JavaScript、PHP等。
Java语言既有编译型语言的特征,也具有解释型语言的特征。因为Java程序要经过先编译,后解释两个步骤,由Java编写的程序需要先经过编译步骤,生成字节码,这种字节码必须由Java解释器来解释执行。
速记:Java语言“编译与解释”并存-具有两种特性-先编译成字节码再解释为机器码
编译型语言-生成目标代码-速度快效率低;解释型语言-一句一句-不生成目标代码-速度慢效率高
5、Oracle JDK vs Open JDK
①Open JDK存储库中的源代码与用于构建Oracle JDK的代码非常接近,Oracle JDK版本的构建过程是基于Open JDK7构建的,只添加了几个部分。
②Oracle JDK大概6个月发布一次版本,而Open JDK大概三个月发布一次版本,因此Oracle JDK相对更稳定。
③Open JDK是一个参考模型并且完全开源,而Oracle JDK是Open JDK的一个实现,并不是完全开源。
④在响应性和JVM性能方面,Oracle JDK更好
⑤Oracle JDK不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本
⑥Oracle JDK使用BCL/OTN协议获得许可,而OpenJDK根据GPL v2许可获取许可。
速记:Oracle JDK基于Open JDK7构建-Oracle JDK更稳定,性能更好-Open JDK为参考模型并且完全开源-Oracle JDK不会为新发布版本提供长期支持
6、Java语言关键字有哪些?
①访问控制:private,protected,public...
②类,方法和变量修饰符:abstract,class,extends,final,implements,interface,native,new,static,strictfp,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,int,short,long,double,float,char
⑦变量引用:super,this,void
⑧保留字:goto,const
注:default很特殊,属于程序控制、类,方法和变量修饰符、访问控制三种
--在程序控制中,当switch匹配不到任何情况,使用default编写默认匹配
--在类,方法和变量修饰符中,从JDK8开始有默认方法,用default来定义
--在访问控制中,如果一个方法前没有任何修饰符,默认有一个修饰符default,但是这个修饰符加上就会报错
注意:虽然true,false和null看起来像关键字但它们是字面量,同时也不能用作标识符。
7、自增(++)自减(--)运算符
++和--运算符可以放在变量之前,也可以放在变量之后,当运算符放在变量之前时(前缀),先自增/自减,再赋值;当运算符放在变量之后时(后缀),先赋值,再自增/自减。
速记:++a先加后赋值,a++先赋值后加
8、成员变量和局部变量的区别?
①语法形式:成员变量是属于类的,而局部变量是在代码块或方法中定义的变量或是方法的参数;成员变量可以被public,private,static等修饰符修饰,而局部变量不可以,但是,成员变量和局部变量都能被final所修饰。
②存储方式:从变量在内存中的存储方式来看,如果成员变量是static修饰的,那么这个成员变量是属于类的,如果没有static修饰,这个成员变量是属于实例的。而对象存在于堆内存中,局部变量存在于栈内存中。
③生存时间:成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动生成,随着方法的调用结束而消亡。
④默认值:从变量是否有默认值来看,成员变量如果没有被负初始值,则会自动以类型的默认值而赋值(一种情况例外:被final修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。
速记:成员变量属于类,局部变量属于方法或代码块-对象存在堆内存,局部变量存在栈内存-成员变量与类创建有关,局部变量与方法调用有关-成员变量一般有默认值,而局部变量没有默认值(语法形式、存储方式、生存时间、默认值)
9、静态变量有什么作用?
静态变量可以被类的所有实例共享。无论一个类创建了多少个对象,它们都共享同一份静态变量。通常情况下,静态变量会被final关键字修饰成常量。
速记:静态变量-被类的所有实例共享
10、字符型常量和字符串常量的区别?
①形式:字符型常量是单引号引起的一个字符,字符串常量是双引号引起的0个或若干个字符。
②含义:字符常量相当于一个整数值(ASCII值),可以参加表达式运算;字符串常量代表一个地址值(该字符串在内存中存放的位置)。
③占内存大小:字符常量只占2个字节;字符串常量占若干个字节。
注:char在Java中占两个字节。
速记:字符常量单引号,字符串常量双引号-字符常量整数值,字符串常量地址值-字符常量2字节,字符串常量若干字节(形式、含义、占内存大小)
11、静态方法和实例方法有何不同?
①调用方式:在外部调用静态方法时,可以采用类名.方法名,也可采用对象.方法名(不推荐),而实例方法只能采用对象.方法名。也就是说,调用静态方法无需创建对象。
②访问类成员是否存在限制:静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),不允许访问实例成员(即实例成员变量和实例方法),而实例方法不存在这个限制。
速记:静态方法用类名.方法名调用,实例方法用对象.方法名调用-静态方法的调用无需创建对象-静态方法访问只能访问类成员,不能访问实例成员,实例方法即可访问类成员,也可访问实例成员
12、重写和重载有什么区别?
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理。
重载发生在一个类中(或者父类和子类之间),方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法。
重写时方法名、参数列表必须相同,子类方法返回值类型应比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。(方法重写要遵循“两同两小一大”)
重写时,如果父类方法修饰符为private/final/static,则子类不能重写该方法,但是被static修饰的方法能够被再次声明。
构造方法无法被重写。
区别点 | 重载方法 | 重写方法 |
---|---|---|
发生范围 | 同一个类 | 子类 |
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可修改 | 子类方法返回值类型应比父类方法返回值类型更小或相等 |
异常 | 可修改 | 子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或者相等 |
访问修饰符 | 可修改 | 子类的访问权限应比父类的访问权限更大或者相等 |
发生阶段 | 编译期 | 运行期 |
速记:重载参数列表不同,重写参数列表相同-重写遵循“两同两小一大”-重载在同类,重写在子类
13、什么是可变长参数?
可变长参数就是允许在调用方法时传入不定长度的参数。例:String...args可以接受0个或多个参数。可变长参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数。
遇到方法重载的情况时,会优先匹配固定参数的方法,因为固定参数的方法匹配度更高。
另外,Java的可变长参数编译后实际会被转换成一个数组。
速记:可变长参数-String...args-只能放在函数最后-方法重载时优先匹配固定参数-编译转换为数组
14、Java中的基本数据类型有哪些?
Java中有8种基本数据类型,分别为
6种数字类型:①4种整数型:byte、short、int、long ②2种浮点型:float、double
1种字符类型:char 1种布尔型:boolean
基本类型 | 位数 | 字节 | 默认值 | 取值范围 |
byte | 8 | 1 | 0 | -128~127 |
short | 16 | 2 | 0 | -32768 ~ 32767 |
int | 32 | 4 | 0 | -2147483648 ~ 2147483647 |
long | 64 | 8 | 0L | -9223372036854775808 ~ 9223372036854775807 |
float | 32 | 4 | 0f | 1.4E-45 ~ 3.4028235E38 |
double | 64 | 8 | 0d | 4.9E-324 ~ 1.7976931348623157E308 |
char | 16 | 2 | 'u0000' | 0 ~ 65535 |
boolean | 1 | false | true\false |
注意:①Java中使用long类型的数据一定要在数值后面加上L,否则将作为整型解析。
②char单引号,String双引号。
这八种基本类型对应的包装类分别为:
Byte、Short、Integer、Long、Float、Double、Character、Boolean
15、基本类型和包装类型的区别?
①成员变量包装类型不赋值就是null,而基本类型有默认值且不是null。
②包装类型可用于泛型,而基本类型不可以。
③基本数据类型的局部变量存放在Java虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被static修饰)存放在Java虚拟机的堆中。包装类型属于对象类型,几乎所有对象实例都存在于堆中。
④相对于对象类型,基本数据类型占用的空间非常小。
注意:基本数据类型存放在栈中是一个常见的误区!基本数据类型的成员变量如果没有被static修饰的话,就存放在堆中。
速记:基本类型有默认值,包装类默认为null-包装类可用于泛型-包装类存在堆,基本类型局部变量存在栈中-基本类型占空间小
标签:面试题,Java,字节,JDK,常见,编译,方法,变量 From: https://blog.csdn.net/qq_63898506/article/details/140644478