基础概念
Java语言有哪些特点?
- 面向对象(封装、继承、多态)
- 平台无关(java代码编译为
.class
字节码之后由JVM执行,与平台无关) - 支持多线程
- 可靠(具备异常处理和自动内存管理机制)
- 安全(java提供访问权限修饰符、限制程序直接访问系统资源等多重安全防护机制)
- 支持网络编程
- 编译和解释并存
JVM、JDK、JRE
JVM
JVM(java virtual machine)是运行java字节码的虚拟机,针对不同的系统有特定实现,目的是使用相同的字节码,jvm会给出相同的结果。字节码和不同系统的jvm实现是java一次编译、随处运行的关键。
JDK JRE
JDK是java开发工具包,用于创建和编译java的程序,它包含了JRE(Java Runtime Environment),以及编译器javac和其他工具。如 javadoc(文档生成器)、jdb(调试器)、jconsole(监控工具)、javap(反编译工具)等。
JRE 是运行已编译 Java 程序所需的环境,主要包含以下两个部分:
– JVM
– Java基础类库:提供了常用功能和api
什么是字节码?采用字节码的好处是什么?
JVM可以理解的代码就叫做字节码(扩展名是.class
),字节码不面向任何特定处理器,只面向虚拟机,因此java程序无需重新编译就可以在多种操作系统的计算机上运行。
注意:在字节码到机器码的步骤中,JVM首先加载字节码文件,然后通过解释器逐行解释执行,执行速度相对较慢。有些方法和代码块经常被调用,为了提高性能引进了JIT编译器,JIT属于运行时编译,首次编译后会保存字节码对应的机器码,下次可直接使用。
为什么说 Java 语言“编译与解释并存”?
因为 Java 程序执行时要经过先编译,后解释两个步骤,由 Java 编写的程序需要先经过编译步骤,生成字节码(.class 文件),这种字节码必须由 Java 解释器来解释执行。
Java 和 C++ 的区别?
- Java 不提供指针来直接访问内存,程序内存更加安全
- Java 的类是单继承的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是Java接口可以多继承。
- Java 有自动内存管理垃圾回收机制(GC),不需要手动释放无用内存。
- C++同时支持方法重载和操作符重载,但是 Java 只支持方法重载(操作符重载增加了复杂性,这与 Java 最初的设计思想不符)。
移位运算符
移位操作中,被操作的数据被视为二进制数,移位就是将其向左或向右移动若干位的运算。
Java 中有三种移位运算符:
– <<
:左移运算符,向左移若干位,高位丢弃,低位补零。x << n,相当于 x 乘以 2 的 n 次方(不溢出的情况下)。
– >>
:带符号右移,向右移若干位,高位补符号位,低位丢弃。正数高位补 0,负数高位补 1。
– x >> n,相当于 x 除以 2 的 n 次方。
– >>>
:无符号右移,忽略符号位,空位都以 0 补齐。
如果移位的位数超过数值所占有的位数会怎样?
当 int 类型左移/右移位数大于等于 32 位操作时,会先求余(%)后再进行左移/右移操作。也就是说左移/右移 32 位相当于不进行移位操作(32%32=0),左移/右移 42 位相当于左移/右移 10 位(42%32=10)。
基本数据类型
java中有几种基本数据类型?
8种
6种数字类型
– byte,short,int,long
,
– float double
1种字符类型
– char
1种布尔型
– boolean
对应包装类:Byte、Short、 Integer 、Long、Float、Double、**Character**、Boolean
。
基本类型 | 位数 | 字节 | 默认值 | 取值范围 |
---|---|---|---|---|
byte |
8 | 1 | 0 | -128 ~ 127 |
short |
16 | 2 | 0 | -32768 (-2^15) ~ 32767 (2^15 – 1) |
int |
32 | 4 | 0 | -2147483648 ~ 2147483647 |
long |
64 | 8 | 0L | -9223372036854775808 (-2^63) ~ 9223372036854775807 (2^63 -1) |
char |
16 | 2 | ‘\u0000’ | 0 ~ 65535 (2^16 – 1) |
float |
32 | 4 | 0f | 1.4E-45 ~ 3.4028235E38 |
double |
64 | 8 | 0d | 4.9E-324 ~ 1.7976931348623157E308 |
boolean |
1 | – | false | true, false |
基本类型和包装类型的区别?
- 用途: 基本类型多用于常量和局部变量定义。方法参数对象属性中多用包装类型。并且,包装类型可用于泛型,而基本类型不可以。
- 存储方式:
- 基本数据类型 的局部变量存放在 Java 虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被
static
修饰 )存放在 Java 虚拟机的堆(堆/方法区/元空间)中。 - 包装类型 属于对象类型,几乎所有对象实例都存在于堆中。
- 基本数据类型 的局部变量存放在 Java 虚拟机栈中的局部变量表中,基本数据类型的成员变量(未被
- 占用空间: 相比于包装类型(对象类型), 基本数据类型占用的空间往往非常小。默认值:成员变量包装类型不赋值就是
null
,而基本类型有默认值且不是null。
- 比较方式:
- 对于基本数据类型来说,
==
比较的是值。 - 对于包装数据类型来说,
==
比较的是对象的内存地址。所有整型包装类对象之间值的比较,全部使用equals()
方法。
- 对于基本数据类型来说,
自动装箱拆箱
装箱:将基本数据类型用他们对应的引用类型包装起来。调用包装类的valueOf()
方法
拆箱:将包装类型转换为基本数据类型,调用了 xxxValue()
方法。
自动拆装箱就是Java可以在基本数据类型和他们的包装类之间进行自动转换。
浮点数计算精度丢失
原因:计算机是二进制的,而且计算机在表示一个数字时,宽度是有限的,无限循环的小数存储在计算机时,只能被截断,所以就会导致小数精度发生损失的情况。
解决:BigDecimal
可以实现对浮点数的运算,不会造成精度丢失。
超过long整形的整数如何表示?
使用BigInteger
(内部使用 int[]
数组来存储任意大小的整形数据。)
变量
成员变量与局部变量的区别?
区别 | 成员变量 | 局部变量 |
---|---|---|
语法形式 | 属于类(实例或静态变量),可以用 public 、private 、static 等修饰 |
只能在方法、构造器或代码块中定义,不能使用 static 和访问控制修饰符 |
存储方式 | – static 修饰的存储在 方法区(JDK8 之后是 堆) – 没有 static 修饰的这个成员变量是属于实例的。存储在 堆 |
存储在 栈 |
生存时间 | – 实例变量:随对象创建而存在,随对象销毁而消亡 – 静态变量:随类加载而存在,随类卸载而消亡 |
在方法调用时创建,方法执行完后消亡 |
默认值 | 如果未显式赋值,则使用类型默认值(如 int 默认 0 ,boolean 默认 false ) |
局部变量则不会自动赋值 |
注意:成员变量和局部变量都能被 final
所修饰。被 final
修饰的成员变量也必须显式地赋值
静态变量
静态变量也就是被 static
关键字修饰的变量。它可以被类的所有实例共享,无论一个类创建了多少个对象,它们都共享同一份静态变量。也就是说,静态变量只会被分配一次内存,即使创建多个对象
静态变量是通过类名来访问的,例如StaticVariableExample.staticVar
(如果被 private关键字修饰就无法这样访问了)。
字符常量和字符串常量的区别
区别 | 字符常量 | 字符串常量 |
---|---|---|
形式 | 单引号引起的一个字符,如 'A' |
双引号引起的 0 个或若干个字符,如 "Hello" |
含义 | 相当于一个整型值 (ASCII 值),可参与表达式运算 | 代表一个地址值 (该字符串在内存中的存放位置) |
占内存大小 | 2 个字节 | 若干个字节(取决于字符串长度) |
方法
静态方法为什么不能调用非静态成员?
- 静态方法是属于类的,在类加载的时候就会分配内存,可以通过类名直接访问。而非静态成员属于实例对象,只有在对象实例化之后才存在,需要通过类的实例对象去访问。
- 在类的非静态成员不存在的时候静态方法就已经存在了,此时调用在内存中还不存在的非静态成员,属于非法操作。
静态方法和实例方法有何不同?
区别 | 静态方法 | 实例方法 |
---|---|---|
调用方式 | 调用静态方法可以无需创建对象,可以使用 类名.方法名 的方式,也可以使用 对象.方法名 |
只能用对象.方法名 |
访问类成员限制 | 只允许访问静态成员,不允许访问实例成员 | 无限制 |
重载和重写
重载就是同样的一个方法能够根据输入数据的不同,做出不同的处理。
发生在同一个类中(或者父类和子类之间),方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。
重写就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,就要覆盖父类方法
– 重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写。方法名、参数列表必须相同。
– 子类方法返回值类型应比父类方法返回值类型更小或相等,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。
– 如果父类方法访问修饰符为 private/final/static
则子类就不能重写该方法,但是被 static
修饰的方法能够被再次声明。
– 构造方法无法被重写