一、Java基础概念与常识
1.面向过程和面向对象的区别
面向过程:在解决问题的时候以整个问题为核心,强调的是问题流程和顺序。它将问题分解出来,进行分析之后,一步一步去解决。
面向对象:在解决问题的时候是以问题中涉及的对象为核心,强调的是问题主体。它将问题中涉及到的对象抽取出来,并赋予对象相应的特征和行为,再按照解决问题的流程将问题将进行解决。
举一个用洗衣机来洗衣服的例子:
面向过程:放入脏衣服→放入洗衣液→启动洗衣机→洗衣服→脱水→拿出衣服晾晒
面向对象:抽取出洗衣机和人两个对象,洗衣机有洗衣服和脱水两个行为,人有放入脏衣服、放入洗衣液、启动洗衣机、拿出衣服晾晒的行为,然后再按照顺序进行即可。
2.Java语言的特点
① 面向对象(具有封装、继承和多态的特性)
② 跨平台(因为有虚拟机的存在,所以可以实现跨平台)
③ 可靠性(有异常处理和自动内存管理机制)
④ 安全性(提供了多重安全防护机制:如使用访问权限修饰符来控制类、方法和变量的访问权限、使用类加载器限制程序直接访问操作系统资源)
⑤ 高性能(通过即时编译器将Java字节码转换为本地机器码执行,使得Java在性能上接近于编译型语言)
⑥ 编译与解释并存(首先通过编译器将源代码编译生成字节码【.class文件】,然后由 JVM 对字节码进行解释执行)
3.JavaSE和JavaEE
JavaSE(Java Platform,Standard Edition): Java 平台标准版,Java SE 提供了基础的 Java 编程语言和 API 库,可以满足大多普通应用程序的需求。用于开发桌面和普通的企业应用程序。
Java EE(Java Platform, Enterprise Edition ):Java 平台企业版,在Java SE基础上扩展了一系列企业级组件和技术,例如 Servlet、JSP、JDBC、JPA、JMS 等。 用于构建分布式、可扩展、安全的应用程序,例如 Web 应用程序。
4.JDK 、JRE、JVM
JDK :Java开发工具包(Java Development Kit)。能够创建和编译 Java 程序。包含了 JRE、编译器 javac 、一些其他工具比如 javadoc(文档注释工具)、jdb(调试器)等等
JRE:是 Java 运行时环境(Java Runtime Environment)。是运行已编译 Java 程序所需的所有内容的集合,主要包括 Java 虚拟机、Java 基础类库
JVM:Java 虚拟机是用来运行 Java 字节码的。JVM 有针对不同系统的有特定实现,作用是当使用相同的字节码,它们都会给出相同的结果。不同系统的 JVM 实现是 Java 语言“一次编译,处处运行”的关键所在。
三者的关系图:
二、运算符
1.常见运算符
+(加)、-(减)、x(乘)、/(除)、%(取余)
2.自增自减运算符
(a = 5,b = 6,c = 0)
++i:i先加一再进行运算,c = ++b+a,c = 7+5 = 12
--i:i先减一再进行运算,c = ++b-a,c = 7-5 = 2
i++:先进行运算i再加一,c = b+(a++),c = 6+5 = 11,结束后a = 6
i--:先进行运算i再减一,c = b+(a--),c = 6-5 = 1, 结束后a = 4
3.位移运算符
<<(左移):不溢出的情况下,向左移,高位丢弃,低位补0。x << 1,
相当于 x 乘以 2
>>(带符号右移):带符号右移,向右移,高位补符号位,低位丢弃。符号位正数高位补 0,负数高位补 1。x >> 1,
相当于 x 除以 2。
>>>(无符号右移):无符号右移,忽略符号位,空位都以 0 补齐。
三、基本数据类型(8种)和包装数据类型
1.基本数据类型
整数型:byte、short、int、long
小数型:float、double
字符型:char
布尔型:boolean
它们所占的字节和取值范围具体如下:
数据类型 | 字节数 | 取值范围 |
---|---|---|
byte | 1 | -128 到 127 |
short | 2 | -32,768 到 32,767 |
int | 4 | -2,147,483,648 到 2,147,483,647 |
long | 8 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
float | 4 | 大约 ±3.40282347E+38F(有效位数为 6-7 位) |
double | 8 | 大约 ±1.79769313486231570E+308(有效位数为 15 位) |
char | 2 | Unicode 字符集范围,即 0 到 65,535 |
boolean | 具体和虚拟机有关 | true 或 false |
2.包装数据类型
Byte:对应 byte 类型。
Short:对应 short 类型。
Integer:对应 int 类型。
Long:对应 long 类型。
Float:对应 float 类型。
Double:对应 double 类型。
Character:对应 char 类型。
Boolean:对应 boolean 类型。
基本数据类型和包装数据类型的区别:
基本数据类型 | 包装数据类型 | |
---|---|---|
数据类型 | 存储数据值 | 存储的是对象引用 |
存储位置 | 栈内存 | 堆内存 |
默认值 | 有 | null(即没有值) |
空值处理 | 不能直接赋值为 null | 支持 |
包装功能 | 无 | 提供实用方法(可以进行类型转换、数值操作) |
性能开销 | 较小 | 较大 |
总的来说,基本数据类型适合存储简单的数据值,操作效率高;而包装数据类型适用于需要进行类型转换、空值处理等高级操作的场景;在性能开销方面,虽然包装类型的性能开销相对较大,但在实际编程中通常不会对性能产生明显的影响。在选择使用哪种类型时,需要根据具体的需求和性能要求进行权衡。另外,Java 5 之后引入了自动装箱、拆箱机制,可以方便地在基本数据类型和包装数据类型之间进行转换,更加灵活和方便。
3.装箱与拆箱
装箱:将基本数据类型转换为对应的包装数据类型,原理是通过调用对应包装类的valueOf()方法来实现的,该方法接收一个基本类型数据作为参数,并返回对应的包装类对象。例如,Integer.valueOf(int)方法会将int类型的数据转换为对应的Integer对象。
拆箱:将包装数据类型转换为对应的基本数据类型,原理是通过调用包装类对象的xxxValue()方法(例如,intValue()、doubleValue()等)来实现的。这些xxxValue()方法会返回对应的基本类型数据。例如,Integer.intValue()方法会返回Integer对象所包含的int类型数据。
Integer i = 1; // 装箱:Integer i = 1 等价于 Integer i = Integer.valueOf(1);
int n = i; // 拆箱:int n = i 等价于 int n = i.intValue();
四、变量和常量
1.变量
成员变量:定义在类中,可以直接通过类的实例访问。它们的作用范围是整个类,可以在类的任意方法、构造方法以及代码块中使用。
局部变量:局部变量定义在方法、构造方法或代码块中,只能在所属的方法、构造方法或代码块中访问。它们的作用范围是有限的,当所属的方法、构造方法或代码块执行完毕后,局部变量就会被销毁。
静态变量:是定义在类中,使用 static 关键字修饰的一种变量,也称为类变量。与成员变量不同,静态变量是属于整个类的,而不是属于某个对象的。在Java程序执行的过程中,静态变量只会被初始化一次,以后每次访问该变量时都不需要重新初始化。
下面是成员变量、局部变量和静态变量之间的区别以及它们在不同方面的特点:
特点 | 成员变量 | 局部变量 | 静态变量 |
---|---|---|---|
定义位置 | 类中,在方法外部 | 方法、构造方法或代码块内 | 类中,使用 static 关键字修饰 |
作用范围 | 整个类 | 所属的方法、构造方法或代码块 | 整个类,可以通过类名直接访问 |
存储位置 | 对象的堆内存 | 方法栈帧 | 方法区中的静态存储区 |
生命周期 | 随对象的生命周期 | 随所属方法的执行周期 | 随类的加载和卸载 |
默认值 | 有默认值 | 无默认值 | 有默认值 |
访问方式 | 通过对象或实例访问 | 仅在所属方法、构造方法或代码块中可见 | 可通过类名直接访问 |
是否需要实例化 | 需要实例化对象才能调用 | 不需要实例化对象就可以调用 | 不需要实例化对象就可以调用 |
共享性 | 每个对象拥有独立的副本 | 每次方法调用都会创建新的局部变量 | 所有对象共享同一份变量 |
线程安全性 | 需要额外的同步措施 | 无需同步措施 | 需要额外的同步措施 |
2.常量
字符型常量:由单个字符组成,使用单引号 ' ' 表示,例如:'A'、'9'、'@';
字符串常量:由多个字符组成,使用双引号 " " 表示,例如:"Hello"、"World"。
以下是字符型常量和字符串常量的区别:
区别 | 字符型常量 | 字符串常量 |
---|---|---|
定义方式 | 使用单引号 ' ' 表示 | 使用双引号 " " 表示 |
数据类型 | char(占用2个字节的内存空间) | String(会占用较多的内存空间) |
存储方式 | 单个字符 | 多个字符组成的字符串 |
转义字符 | 不支持转义字符 | 支持转义字符 |
可变性 | 不可变(即定义后不能修改其值) | 不可变 |
五、方法
1.实例方法和静态方法
实例方法:是指没有使用 static 关键字修饰的方法,属于实例的行为,可以访问实例变量和其他实例方法,并且需要通过对象来调用。实例方法不能直接通过类名调用,必须先创建对象才能调用。
静态方法:是指使用 static 关键字修饰的方法,属于类的行为,其中不包含对任何对象的引用。静态方法可以通过类名直接访问,不需要通过对象来调用,并且不能访问非静态成员变量和非静态方法。在静态方法内部也不能使用 this 关键字获取当前对象的引用。
两者的区别:
区别 | 静态方法 | 实例方法 |
---|---|---|
调用方式 | 使用类名调用 | 使用对象调用 |
可以使用对象内的变量和方法 | 不能 | 可以 |
可以使用类内的静态变量和方法 | 可以 | 可以 |
是否需要创建对象 | 不需要 | 需要 |
是否能访问实例变量和方法 | 不能 | 可以 |
2.重载和重写
重载:指的是在同一个类中,可以有多个同名的方法,但它们的参数列表必须不同(个数、类型或者顺序)。重载方法可以具有不同的返回类型,但返回类型不能作为重载方法的区分标准。
重写:指的是在子类中对父类的方法进行重新定义。子类可以根据需要重新实现继承自父类的方法,并且方法签名(方法名和参数列表)必须与父类中被重写的方法相同。重写方法的返回类型、修饰符和异常声明必须与父类方法保持一致或为其子类。
两者的区别:
区别 | 重载 | 重写 |
---|---|---|
定义位置 | 同一个类中 | 子类中 |
方法名称 | 相同 | 相同 |
参数列表 | 不同 | 相同 |
返回类型 | 可以不同 | 必须相同 |
方法体 | 不作要求 | 可以重新实现 |
调用时的选择 | 根据参数列表确定 | 根据对象类型确定 |
关系 | 同名方法之间的关系 | 父子类方法之间的关系 |
总结来说,重载是指在同一个类中可以存在多个同名方法,但参数列表必须不同;重写是子类对父类中的方法进行重新定义,方法签名必须相同。重载是静态绑定(编译时绑定),而重写是动态绑定(运行时绑定)。重载和重写在处理方法多态性和代码重用方面起到重要作用。
3.构造方法
是Java中的一种特殊方法,用于创建和初始化对象。每个类都可以有一个或多个构造方法,它们的名称必须和类名称相同,没有返回类型声明,并且不能被直接调用。
举一个例子:
public class MyClass {
// 无参构造方法
public MyClass() {
// 初始化代码
}
// 带参数的构造方法
public MyClass(int value) {
// 初始化代码
}
// 带多个参数的构造方法
public MyClass(int value1, int value2) {
// 初始化代码
}
// 复制构造方法
public MyClass(MyClass original) {
// 初始化代码
}
}
构造方法在创建对象时自动调用,并且只调用一次。它的主要作用是完成实例变量的初始化工作,为对象分配内存空间,以及执行其他必要的操作。构造方法可以有参数和重载,方便用户根据需要对对象进行不同的初始化。
如果一个类没有定义任何构造方法,则编译器会自动为其生成一个默认的无参构造方法。如果一个类定义了一个以上的构造方法,则必须用关键字 this 或 super 引用其他构造方法。同时,子类的构造方法默认调用父类的无参构造方法,如果父类没有无参构造方法,需要在子类的构造方法中显式调用父类的构造方法并传递参数。
构造方法不能被重写( override),但是可以重载 (overload),所以我们可以看到一个类中有多个构造函数的情况。