Java SE 语法基础总结

Java SE 语法基础总结

Java语言概述

1. Java语言概述

Java是一种面向对象的编程语言,强调代码的可移植性和安全性。它通过“一次编写,到处运行”的理念,允许程序在不同操作系统上运行,这得益于Java虚拟机(JVM)的抽象层。Java语言设计简洁,支持多线程、网络编程和内存管理自动化(垃圾回收)。

2. Java的历史

前身:Java语言的前身是Oak语言,最初由Sun Microsystems(后被Oracle公司收购)的团队开发,用于智能家居设备。发明人:Java的主要发明人是James Gosling(詹姆斯·高斯林),他在1990年代主导了Java的开发。1995年,Java正式发布,并迅速成为主流编程语言。发展:Oracle公司在2010年收购了Sun Microsystems,现在负责Java的维护和更新(如Java SE、Java EE等版本)。

3. Java程序的组成

一个Java程序由多个层次结构组成,确保代码的模块化和可维护性:

源文件(.java文件):Java程序的基本单位是源文件,通常以.java为后缀。每个源文件包含一个或多个类。

规则:一个源文件中最多只能有一个被public修饰的类,且该类名必须与文件名相同(例如,文件HelloWorld.java中只能有一个public class HelloWorld)。其他非public类可以共存。 类(Class):类定义对象的蓝图,包含属性(变量)和方法。类必须声明在源文件内部。方法(Method):方法代表可执行的行为,必须声明在类内部。每个方法包含Java语句。语句(Statement):Java语句是具体的执行指令,位于方法内部。总结:源文件包含类,类包含方法,方法包含语句。这是一个层次结构:文件 → 类 → 方法 → 语句。

例如,一个简单Java程序的结构:

// HelloWorld.java 源文件

public class HelloWorld { // public类,类名与文件名相同

public static void main(String[] args) { // 主方法

System.out.println("Hello, World!"); // Java语句

}

}

class AnotherClass { // 非public类

void display() { // 方法

// 语句

}

}

4. Java程序的运行过程

Java是一种半编译型半解释型语言,运行需要两个步骤:编译和解释执行。以下是详细过程:

编译步骤:使用JDK中的javac编译器将源文件(.java)编译为字节码文件(.class)。字节码是面向JVM的中间代码。

命令行示例:javac HelloWorld.java(生成HelloWorld.class文件)。 执行步骤:使用JDK中的java命令将字节码文件加载到JVM中运行。JVM解释字节码并执行。

命令行示例:java HelloWorld(注意:运行时不加.class后缀)。 为什么需要JVM:字节码文件不依赖特定操作系统,JVM负责在不同平台上解释执行,实现跨平台性。

5. JDK、JRE和JVM的关系

Java开发环境的核心组件相互关联:

JVM(Java虚拟机):执行字节码的运行时引擎,提供内存管理和安全机制。JRE(Java Runtime Environment):Java程序运行环境,包含JVM和Java基础类库(如java.lang包)。用户只需JRE来运行Java程序。JDK(Java Development Kit):Java开发工具包,包含JRE、编译器(javac)、调试工具(如jdb)和开发库。开发者必须安装JDK来编写和编译Java程序。关系总结:JDK = JRE + 开发工具;JRE = JVM + Java基础类库。简单说,JDK用于开发,JRE用于运行。

6. Java中的注释

注释用于解释代码,提高可读性,Java支持三种类型:

单行注释:以//开头,适用于单行说明。例如:int x = 10; // 初始化变量。多行注释:以/*开头,以*/结尾,可跨多行。例如: /* 这是一个多行注释

用于描述复杂逻辑 */

文档注释:以/**开头,以*/结尾,用于生成API文档(通过javadoc工具)。例如: /**

* 计算两数之和

* @param a 第一个数

* @param b 第二个数

* @return 和

*/

public int add(int a, int b) {

return a + b;

}

7. 标识符命名规范

标识符是类、方法、变量等的名称,Java有严格规则:

组成规则:只能由字母、数字、下划线(_)和美元符号($)组成,不能以数字开头,且不能是Java关键字(如class、public)。命名惯例(遵循行业标准):

类名:大驼峰式(Upper Camel Case),每个单词首字母大写。例如:HelloWorld、EmployeeDetails。方法名和变量名:小驼峰式(Lower Camel Case),首单词小写,后续单词首字母大写。例如:calculateSum()、userName。包名:全小写字母,通常使用公司域名的倒写(防止命名冲突)。

8. 环境变量配置

环境变量允许命令行在任何目录下找到JDK工具(如javac和java),配置步骤如下:

为什么需要:命令行默认在当前目录查找程序,未找到时搜索系统路径。配置环境变量添加JDK路径,使命令全局可用。配置方法(以Windows为例):

安装JDK后,记下安装路径(例如:C:\Program Files\Java\jdk-21\bin)。打开系统设置 → 高级系统设置 → 环境变量。在“系统变量”中编辑Path变量,添加JDK的bin目录路径。保存后,重启命令行生效。 验证:在命令行输入javac -version,如果显示版本号(如javac 21.0.1),则配置成功。

9. 检查JDK安装

在运行Java程序前,需确认JDK已正确安装:

命令行检查:打开命令行(如CMD或Terminal),输入java -version。如果输出JDK版本信息(例如:java version "21.0.1"),表示安装成功;否则,需重新安装或配置环境变量。推荐做法:开发时使用IDE(如Eclipse或IntelliJ IDEA),它们自动管理JDK路径,简化开发。

Java SE 语法基础:数据类型与变量

一、常量和变量

Java中的数据分为常量和变量:

常量(字面常量):直接在代码中写出的固定值,如整数2、浮点数3.4、字符'a'、字符串"name"。这些值在程序运行期间不可修改。变量:通过声明来存储可变数据,语法为数据类型 变量名。例如: int age = 25; // 声明并初始化一个整型变量

String name = "Alice"; // 声明并初始化一个字符串变量

变量必须在使用前初始化,否则会导致编译错误。例如,未初始化的变量会报错: int count; // 未初始化

System.out.println(count); // 编译错误:变量未初始化

二、基本数据类型

Java的基本数据类型分为4类8种,大小固定(不随系统变化),且整形和字符型默认有符号。以下是详细分类:

整形(整数类型):

byte:1个字节,范围-128到127。short:2个字节,范围-32768到32767。int:4个字节,默认整数类型,范围-2147483648到2147483647。long:8个字节,范围-9223372036854775808到9223372036854775807。 示例代码: byte smallNumber = 10;

long bigNumber = 1000000000L; // 必须加L后缀

浮点型(小数类型):

float:4个字节,单精度浮点数。double:8个字节,默认小数类型,双精度浮点数。 示例代码: float price = 19.99F; // 必须加F后缀

double pi = 3.1415926535;

字符型:

char:2个字节,使用Unicode编码(支持ASCII和中文)。 示例代码: char letter = 'A';

char chineseChar = '中';

布尔型:

boolean:大小未严格定义(通常为1字节),值只能是true或false。Java中不能使用0或1替代布尔值。 示例代码: boolean isActive = true;

// boolean flag = 1; // 错误:不能赋值0或1

三、变量定义与初始化

变量必须初始化:Java要求所有变量(基本类型或引用类型)在声明时或使用前赋值,否则编译失败。推荐定义时赋初始值(如0或null)。 int score = 0; // 正确:初始化

// int count; // 错误:未初始化

long和float的特殊处理:

整数默认类型为int,定义long时需加L后缀(如10L)。小数默认类型为double,定义float时需加F后缀(如10.5F)。 示例: long population = 7800000000L; // 不加L会警告

float height = 1.75F; // 不加F会编译错误

四、包装类

Java为基本数据类型提供了包装类(如Integer、Double),用于对象操作和查看范围:

常用包装类:Byte, Short, Integer, Long, Character, Float, Double, Boolean。查看取值范围:使用MIN_VALUE和MAX_VALUE方法。 示例代码: System.out.println("int范围: " + Integer.MIN_VALUE + " 到 " + Integer.MAX_VALUE);

// 输出:int范围: -2147483648 到 2147483647

五、类型转换

不同类型赋值时需遵循规则:

自动类型转换:范围小的类型自动转为范围大的类型(如int到long)。 int num1 = 100;

long num2 = num1; // 自动转换

强制类型转换:范围大的类型强制转为范围小的类型,需使用(类型)语法,可能丢失精度。 double value = 9.87;

int intValue = (int) value; // 强制转换,结果为9

不兼容类型:布尔型与整形/浮点型不兼容,不能强制转换。 // boolean flag = (boolean) 1; // 错误:编译失败

六、类型提升

计算时,小范围类型自动提升为大范围类型:

整形提升:byte, short, char 先提升为int。整体提升规则:

有long时,提升为long。有float时,提升为float。有double时,提升为double。 示例代码: byte a = 10;

short b = 20;

int result = a + b; // 提升为int计算

double c = 5.5;

double sum = a + c; // 提升为double计算

Java SE 语法基础:Java运算符详解

一、算数运算符

算数运算符用于基本数学计算,包括双目运算符:+(加法)、-(减法)、*(乘法)、/(除法)和%(取余)。

除法运算符/:

分为整数除法和小数除法:

如果操作数均为整数(如int),则执行整数除法,结果截断小数部分。如果任一操作数为浮点数(如double),则执行小数除法,结果保留小数。 修正:结果的符号由两个操作数的符号共同决定,而非仅第一个操作数。例如:

5 / 2 = 2(整数除法,同号结果正)-5 / 2 = -2(整数除法,异号结果负)5.0 / 2 = 2.5(小数除法) 除数不能为0,否则抛出ArithmeticException。 取余运算符%:

一般用于整数取余,小数取余意义不大。扩展:结果的符号由第一个操作数决定,例如 5 % 3 = 2, -5 % 3 = -2。除数不能为0,否则抛出异常。

Java代码示例:

public class ArithmeticDemo {

public static void main(String[] args) {

int a = 5;

int b = 2;

System.out.println(a / b); // 输出2(整数除法)

System.out.println((double)a / b); // 输出2.5(小数除法)

System.out.println(a % b); // 输出1

}

}

二、关系运算符

关系运算符用于比较值,返回布尔值(true或false),包括:>(大于)、>=(大于等于)、<(小于)、<=(小于等于)、==(等于)、!=(不等于)。

扩展:==比较基本类型值是否相等;对象比较需用equals()方法,否则比较引用地址。示例:x > y 若 x = 5, y = 3,则结果为 true。

Java代码示例:

public class RelationalDemo {

public static void main(String[] args) {

int x = 5;

int y = 3;

System.out.println(x > y); // 输出true

System.out.println(x == y); // 输出false

}

}

三、逻辑运算符

逻辑运算符用于布尔表达式,包括:&&(逻辑与)、||(逻辑或)、!(逻辑非)。

&&和||是短路运算符:

&&:若左操作数为false,则跳过右操作数计算。||:若左操作数为true,则跳过右操作数计算。 扩展:避免在右操作数中放置有副作用的表达式(如方法调用),以防短路导致逻辑错误。

Java代码示例:

public class LogicalDemo {

public static void main(String[] args) {

boolean a = true;

boolean b = false;

System.out.println(a && b); // 输出false(短路示例)

System.out.println(!a); // 输出false

}

}

四、复合赋值运算符

复合赋值运算符结合赋值和运算,包括:+=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=、>>>=。

等价形式:a += b 等同于 a = a + b。扩展:可能涉及隐式类型转换,例如 int a = 5; a += 2.5; 后,a 为 7(截断小数)。

Java代码示例:

public class CompoundAssignmentDemo {

public static void main(String[] args) {

int x = 10;

x += 5; // 等价于 x = x + 5

System.out.println(x); // 输出15

}

}

五、自增自减运算符

自增++和自减--用于变量值增减。

前缀形式(如++a):先增减后使用值。后缀形式(如a++):先使用值后增减。扩展:避免在复杂表达式中混用,以防未定义行为。

Java代码示例:

public class IncrementDemo {

public static void main(String[] args) {

int a = 5;

System.out.println(a++); // 输出5(后缀)

System.out.println(++a); // 输出7(前缀)

}

}

六、位运算符

位运算符直接操作二进制位,包括:&(按位与)、|(按位或)、^(按位异或)、~(按位取反)。

示例:5 & 3 计算为 1(二进制 101 & 011 = 001)。~ 是单目运算符:例如 ~5 在8位系统中为 -6(二进制取反)。

Java代码示例:

public class BitwiseDemo {

public static void main(String[] args) {

int a = 5; // 二进制 0101

int b = 3; // 二进制 0011

System.out.println(a & b); // 输出1(0101 & 0011 = 0001)

System.out.println(~a); // 输出-6

}

}

七、移位运算符

移位运算符移动二进制位,包括:<<(左移)、>>(带符号右移)、>>>(无符号右移)。

<< n:左移 n 位,等价于乘以 2^n。>> n:右移 n 位,等价于除以 2^n(保留符号)。>>> n:右移 n 位,高位补0(忽略符号)。数学表示:a << n = a \times 2^n(整数范围)。

Java代码示例:

public class ShiftDemo {

public static void main(String[] args) {

int num = 8; // 二进制 1000

System.out.println(num << 1); // 输出16(左移1位)

System.out.println(num >> 1); // 输出4(右移1位)

}

}

八、三目运算符(条件运算符)

三目运算符格式:condition ? expr1 : expr2。

若 condition 为 true,返回 expr1;否则返回 expr2。修正:结果必须被使用(如赋值或打印),不能单独存在。扩展:常用于简化if-else语句,但嵌套时需注意可读性。

Java SE 语法基础:程序控制语句与方法详解

一、程序控制语句

程序控制语句用于控制代码的执行流程,主要包括选择语句和循环语句。

1. 选择语句 选择语句根据条件决定执行哪部分代码。

if-else语句:

语法:if(布尔表达式) { ... } else if(布尔表达式) { ... } else { ... }注意:Java中if()内的表达式必须是布尔类型(如true或false),不能使用整数值(如1或0)代替布尔值。示例代码: int score = 85;

if (score >= 90) {

System.out.println("优秀");

} else if (score >= 60) {

System.out.println("及格");

} else {

System.out.println("不及格");

}

switch语句:

语法:switch(表达式) { case 值: ... break; default: ... }表达式结果类型限制:只能是byte、short、int、char、String或枚举类型。关键字:break用于跳出switch块,case匹配值,default处理未匹配情况。示例代码: char grade = 'B';

switch (grade) {

case 'A':

System.out.println("优秀");

break;

case 'B':

System.out.println("良好");

break;

default:

System.out.println("未知等级");

}

2. 循环语句 循环语句用于重复执行代码块,直到条件不满足。

for循环:

语法:for(初始化; 布尔表达式; 更新) { ... }示例代码: for (int i = 0; i < 5; i++) {

System.out.println("循环次数: " + i);

}

while循环:

语法:while(布尔表达式) { ... }示例代码: int count = 0;

while (count < 3) {

System.out.println("计数: " + count);

count++;

}

do-while循环:

语法:do { ... } while(布尔表达式);(先执行一次,再检查条件)示例代码: int num = 5;

do {

System.out.println("数值: " + num);

num--;

} while (num > 0);

3. break和continue关键字

break:跳出当前循环体或switch块。continue:结束本次循环,直接进入下一次循环的条件判断。示例代码: for (int i = 0; i < 10; i++) {

if (i == 3) continue; // 跳过i=3的循环

if (i == 7) break; // 当i=7时跳出循环

System.out.println(i);

}

4. 键盘输入(使用Scanner) Java中通过Scanner类实现键盘输入,需导入java.util.Scanner。

基本用法:

Scanner scanner = new Scanner(System.in); 创建Scanner对象。int a = scanner.nextInt(); 读取整数。String str = scanner.nextLine(); 读取字符串。scanner.close(); 关闭Scanner。 循环输入示例: import java.util.Scanner;

public class InputExample {

public static void main(String[] args) {

Scanner scanner = new Scanner(System.in);

while (scanner.hasNextInt()) {

int num = scanner.nextInt();

System.out.println("输入值: " + num);

}

scanner.close();

}

}

二、Java方法

方法是代码的模块化单元,提高代码复用性。在Java中,方法必须定义在类内。

1. 方法定义

语法:public static 返回值类型 方法名(参数列表) { 方法体 }

public static 表示访问修饰符和静态方法(可根据需求调整)。返回值类型:如void(无返回值)、int等。 示例代码: public class MethodDemo {

public static void main(String[] args) {

greet("张三"); // 调用方法

}

public static void greet(String name) { // 方法定义

System.out.println("你好, " + name + "!");

}

}

2. 形式参数与实际参数

形式参数:方法定义中的参数,是实际参数的拷贝。实际参数:方法调用时传入的值。参数传递规则:

基本数据类型(如int、double):传值调用(修改形式参数不影响实际参数)。引用数据类型(如数组、对象):传地址调用(修改形式参数会影响实际参数)。 示例代码: public class ParamPassing {

public static void main(String[] args) {

int a = 10;

changeValue(a); // 传值调用,a不变

System.out.println("a after: " + a); // 输出10

}

public static void changeValue(int num) {

num = 20; // 修改形式参数

}

}

3. 方法重载 方法重载允许同一类中有多个同名方法,但参数列表不同。

条件:

方法名相同。参数列表不同(参数数量、类型或顺序)。与返回值类型无关。 示例代码: public class OverloadDemo {

public static void main(String[] args) {

printInfo(10); // 调用printInfo(int)

printInfo("JavaSE"); // 调用printInfo(String)

}

public static void printInfo(int num) {

System.out.println("整数: " + num);

}

public static void printInfo(String text) {

System.out.println("字符串: " + text);

}

}

4. 方法签名 方法签名是编译器区分重载方法的依据,包含方法名和参数列表(不包括返回值类型)。

为什么需要:Java不允许在类中定义同名同参数的方法,但通过签名支持重载。组成:方法名 + 参数类型序列(如printInfo(int)和printInfo(String))。

5. 递归方法 递归方法是方法体内部调用自身的方法,常用于解决分治问题(如阶乘、斐波那契数列)。

示例代码(计算阶乘): public class RecursionDemo {

public static void main(String[] args) {

int result = factorial(5); // 调用递归方法

System.out.println("5的阶乘: " + result); // 输出120

}

public static int factorial(int n) {

if (n == 0 || n == 1) { // 基线条件

return 1;

}

return n * factorial(n - 1); // 递归调用

}

}

Java SE 语法基础:数组的定义与使用

在Java编程中,数组是一种基础且强大的数据结构,用于存储相同类型元素的集合。数组在内存中是连续的空间,这使得元素访问高效。本部分作为JavaSE语法系列的第五篇,将系统总结数组的核心概念、使用方法、常见操作及注意事项。内容基于Java标准语法,确保真实可靠。如果您错过了前几部分,建议回顾以构建完整知识体系。

1. 什么是数组?

数组是一组相同类型元素的集合,在内存中分配为一块连续的空间。数组变量属于引用数据类型,它存储的是数组对象在堆内存中的地址。通过这个引用,我们可以访问数组中的元素。例如:

数组元素下标范围是$[0, \text{length})$(包左不包右),其中$\text{length}$表示数组长度。如果下标超出范围(如访问$\text{index} \geq \text{length}$或$\text{index} < 0$),Java会抛出ArrayIndexOutOfBoundsException异常,确保程序安全。

2. 数组的创建与初始化

数组的初始化分为动态初始化和静态初始化两种方式。动态初始化指定数组长度,元素使用默认值(如int数组默认0,boolean数组默认false);静态初始化直接赋值元素值,无需指定长度。

动态初始化:

int[] array = new int[10]; // 创建长度为10的int数组,元素默认0

可以分步操作:

int[] array3;

array3 = new int[10]; // 先声明,后初始化

静态初始化:

int[] array1 = new int[]{1, 2, 3, 4}; // 直接赋值

int[] array2 = {1, 2, 3, 4}; // 简化形式,省略new int[]

分步操作时,不能省略new int[]:

int[] array4;

array4 = new int[]{1, 2, 3, 4}; // 正确

// array4 = {1, 2, 3, 4}; // 错误!分步时不能省略new int[]

注意:静态初始化时,末尾的逗号(如{1, 2, 3, 4,})在Java中是合法的,但易引起混淆,建议避免使用以提高代码可读性。

3. 访问数组元素与长度

获取数组长度:通过数组引用.length属性,这是一个只读属性,不能修改。 int length = array.length; // 例如,array.length 返回10

访问元素:使用下标操作符[],下标从0开始: int element = array[0]; // 访问第一个元素

// 如果 array.length = 5, array[5] 会抛出 ArrayIndexOutOfBoundsException

4. 遍历数组

遍历数组是常见操作,推荐使用for-each循环(增强for循环),简洁且安全:

int[] array4 = {1, 2, 3, 4};

for (int x : array4) {

System.out.print(x + " "); // 输出:1 2 3 4

}

传统for循环也可用: for (int i = 0; i < array4.length; i++) {

System.out.print(array4[i] + " ");

}

for-each循环更简洁,但无法修改元素值;传统for循环更灵活。

5. 打印数组内容

直接打印数组引用(如System.out.println(array4))会输出哈希码(如[I@1a2b3c4d),而非元素值。正确方法是使用Arrays.toString()方法:

import java.util.Arrays; // 需导入Arrays类

System.out.println(Arrays.toString(array4)); // 输出:[1, 2, 3, 4]

为什么字符串不同?:字符串引用(如String string = "hello")在打印时自动调用String类重写的toString()方法,输出内容而非地址。数组没有默认重写,所以需要手动调用Arrays.toString()。

6. 补充:常见数组操作与注意事项

默认值:动态初始化时,元素有默认值:

int: 0, double: 0.0, boolean: false, 引用类型: null。 数组复制:避免直接赋值(会共享引用),使用System.arraycopy()或Arrays.copyOf(): int[] copy = Arrays.copyOf(array4, array4.length); // 安全复制

排序与搜索:使用Arrays.sort()排序,Arrays.binarySearch()搜索(需先排序): Arrays.sort(array4); // 排序数组

int index = Arrays.binarySearch(array4, 3); // 搜索元素3的位置

多维数组:Java支持多维数组(如二维数组),可视为数组的数组: int[][] matrix = {{1, 2}, {3, 4}}; // 静态初始化二维数组

System.out.println(Arrays.deepToString(matrix)); // 使用deepToString打印

优点与缺点:

优点:内存连续,访问高效;适合固定大小数据。缺点:长度固定,无法动态扩展;插入/删除元素效率低(需移动元素)。 错误处理:总是检查下标范围,避免ArrayIndexOutOfBoundsException。使用try-catch处理异常: try {

int value = array[10]; // 可能越界

} catch (ArrayIndexOutOfBoundsException e) {

System.out.println("下标越界错误!");

}

7. 完整代码示例

整合并优化用户代码,添加更多操作:

import java.util.Arrays;

public class ArrayDemo {

public static void main(String[] args) {

// 动态初始化

int[] array = new int[5]; // 默认值: 0,0,0,0,0

System.out.println("动态数组长度: " + array.length);

// 静态初始化

int[] array1 = {1, 2, 3, 4}; // 推荐省略末尾逗号

int[] array2 = new int[]{5, 6, 7};

// 遍历与打印

System.out.print("For-each遍历: ");

for (int num : array1) {

System.out.print(num + " "); // 输出: 1 2 3 4

}

System.out.println("\nArrays.toString: " + Arrays.toString(array1)); // 输出: [1, 2, 3, 4]

// 常见操作

int[] copy = Arrays.copyOf(array1, array1.length); // 复制数组

Arrays.sort(copy); // 排序

System.out.println("排序后: " + Arrays.toString(copy));

// 多维数组

int[][] matrix = {{1, 2}, {3, 4}};

System.out.println("二维数组: " + Arrays.deepToString(matrix)); // 输出: [[1, 2], [3, 4]]

}

}

8. 结论

数组是JavaSE中的核心概念,适用于存储固定大小数据集合。关键点包括:

数组是引用类型,内存连续。初始化分动态和静态,注意下标范围[0, \text{length})。使用数组引用.length获取长度,Arrays.toString()打印内容。for-each循环简化遍历,Arrays类提供排序、复制等工具。避免下标越界,善用异常处理。

Java SE 语法基础:面向对象编程核心概念优化总结

1. 面向对象基础

面向对象是一种编程范式,通过对象(实体)之间的交互完成任务。对象是类的实例,类则是描述一类事物的蓝图。例如,定义一个Student类,用于创建学生对象:

public class Student {

private String name; // 私有属性

public void study() { // 公有方法

System.out.println("Studying...");

}

}

2. 类的定义与实例化

类是引用数据类型,用于创建对象。定义时需注意:

使用class关键字创建类。一个Java文件通常只包含一个类;若类包含main方法,则必须用public修饰,且类名与文件名一致。成员变量(属性)常用private修饰以实现封装,成员方法(行为)常用public修饰以提供外部访问。实例化对象使用new关键字: Student stu = new Student(); // 创建对象并获取引用

stu.study(); // 通过引用调用方法

3. this引用

当多个对象共享相同方法时,this引用用于区分当前对象:

在成员方法内部,this指向调用该方法的对象。编译器自动将this作为方法的第一个隐藏参数,例如: public class Student {

private String name;

public void setName(String name) {

this.name = name; // this 区分参数与成员变量

}

}

this只能在成员方法中使用,不能用于静态方法。

4. 对象初始化

对象属性初始化分三步:

默认初始化:new创建对象时,堆内存分配并赋予默认值(如int为0)。就地初始化:声明属性时直接赋值: private int age = 18; // 就地初始化

构造方法:特殊方法,用于自定义初始化:

语法:public 类名(参数列表) {...},无返回值。支持重载(不同参数组合),例如: public Student() { // 无参构造

this("Unknown"); // 调用其他构造方法

}

public Student(String name) {

this.name = name; // 带参构造

}

注意:未定义构造方法时,编译器生成默认无参构造;使用this()调用其他构造方法时,必须置于第一行。

5. 封装与访问限定

封装隐藏实现细节,通过访问限定符控制可见性:

private:仅同类内成员方法可访问。default(默认):同包下类可访问。protected:不同包子类可访问。public:任何地方可访问。 例如:

public class Student {

private String name; // 封装属性

public String getName() { // 提供公有访问接口

return name;

}

}

6. 包与导入

包用于组织类和避免命名冲突:

导入其他包类:import 包名.类名; 或 import 包名.*;(推荐前者)。类查找顺序:当前包 → import导入类 → java.lang包。使用示例: import java.util.ArrayList; // 导入ArrayList类

ArrayList list = new ArrayList<>();

7. static关键字

static修饰的成员属于类而非对象:

静态成员变量:类共享属性,存储在方法区,生命周期与类相同。静态成员方法:类共享行为,无法访问非静态成员或使用this。访问方式:通过类名直接调用,例如: public class Student {

public static int count = 0; // 静态变量

public static void printCount() { // 静态方法

System.out.println(count);

}

}

// 调用:Student.printCount();

静态方法中不能有this引用,因此main方法必须为static。

8. 代码块

代码块用于初始化成员:

静态代码块:初始化静态成员变量,类加载时执行一次: static {

count = 0; // 初始化静态变量

}

实例代码块:初始化实例成员变量,每次创建对象时执行: {

name = "Default"; // 初始化实例变量

}

9. 对象创建顺序

创建对象(如Student stu = new Student();)的执行顺序:

加载类:方法区分配静态变量空间,默认初始化。执行静态代码块:初始化静态变量。堆内存分配实例变量空间,默认初始化。执行就地初始化代码和实例代码块(按代码顺序)。执行构造方法:完成实例变量初始化。 例如:

public class Student {

private int age = 10; // 就地初始化

{ age = 20; } // 实例代码块

public Student() {

age = 30; // 构造方法

}

}

// 最终 age = 30

10. 面向对象特性

Java OOP 三大特性:

封装:通过类和访问控制隐藏细节。继承:子类复用父类特性(后续博客详述)。多态:同一接口不同实现(后续博客详述)。

Java SE 语法基础 :深入理解多态与抽象类

一、多态的本质与实现条件

定义:同一行为被不同对象执行时产生不同状态。例如:动物进食行为,猫执行时吃鱼,狗执行时啃骨头。 实现条件:

继承体系:需存在父子类关系方法重写:子类必须重写父类方法父类引用调用:通过父类类型引用调用重写方法

class Animal {

void eat() { System.out.println("动物进食"); }

}

class Cat extends Animal {

@Override

void eat() { System.out.println("猫吃鱼"); } // 重写父类方法

}

public class Main {

public static void main(String[] args) {

Animal animal = new Cat(); // 父类引用指向子类对象

animal.eat(); // 输出"猫吃鱼" → 多态

}

}

二、方法重写(Override)规范

核心规则:

要素要求反例方法签名方法名、参数列表、返回值完全相同返回值类型不同 → 编译错误访问权限不低于父类方法权限父类public → 子类不能为protected不可重写方法static/final/private修饰或构造方法重写final方法 → 编译错误

重写 vs 重载:

重写:父子类间,方法签名严格一致重载:同一类中,方法名相同但参数列表不同

三、转型机制:向上转型与向下转型

向上转型:父类引用指向子类对象(自动转换)

Animal animal = new Dog(); // 直接赋值 → 向上转型

应用场景:

直接赋值方法参数传递子类对象方法返回子类对象

局限:无法调用子类特有方法(如Dog.bark())

向下转型:将向上转型后的对象强制转回子类类型

if (animal instanceof Dog) {

Dog dog = (Dog) animal; // 安全向下转型

dog.bark(); // 调用子类特有方法

}

关键:转型前必须用instanceof校验对象类型,避免ClassCastException

四、抽象类与抽象方法

抽象类:用abstract修饰,描述不具体对象的类(如Shape、Animal)

abstract class Shape {

abstract void draw(); // 抽象方法

}

抽象方法:

只有声明,无具体实现所在类必须是抽象类子类必须重写(除非子类也是抽象类)

抽象类特性:

能力抽象类普通类包含抽象方法✓✗包含构造方法✓✓包含普通成员方法✓✓实例化对象✗✓

设计价值:

强制重写校验:确保子类实现关键方法模板方法模式:在抽象类中定义算法骨架

abstract class Database {

abstract void connect(); // 子类必须实现

void execute() {

connect();

System.out.println("执行查询");

}

}

Java SE 语法基础:继承从基础到实践

一、继承的意义与基本概念

继承的本质是“共性的抽取”,通过创建父类(基类)来封装通用属性和方法,子类(派生类)继承这些成员,实现代码复用。例如,在描述动物体系时,可以抽取共性如“名称”和“进食方法”,创建父类Animal,子类如Dog继承后直接复用代码,无需重复定义。

// 父类定义共性

class Animal {

protected String name; // protected修饰,允许子类访问

public void eat() {

System.out.println(name + " is eating.");

}

}

// 子类继承并扩展

class Dog extends Animal {

public void bark() {

System.out.println(name + " is barking."); // 复用父类name属性

}

}

二、子类成员访问规则

子类继承父类的成员变量和方法,但访问时需注意优先级:

无同名变量:使用this.变量名访问父类继承的成员。有同名变量:this.变量名优先访问子类自身成员;如需访问父类同名成员,必须使用super.变量名。最佳实践:在子类方法中,访问父类成员时显式添加super关键字,避免歧义。例如:

class Parent {

int value = 10;

}

class Child extends Parent {

int value = 20; // 同名变量

void display() {

System.out.println("子类value: " + this.value); // 输出20(访问自身)

System.out.println("父类value: " + super.value); // 输出10(访问父类)

}

}

三、构造方法的关键细节

子类对象初始化时,必须先完成父类属性的初始化,再处理子类自身属性:

默认行为:子类构造方法首行隐式调用super()(父类无参构造方法)。父类有参构造:若父类定义了有参构造,子类必须显式调用super(参数),且必须是构造方法的第一条语句。规则限制:super()和this()不能在构造方法中同时出现(二者均需首行),且this()用于调用本类其他构造方法。

class Parent {

int id;

Parent(int id) { // 有参构造

this.id = id;

}

}

class Child extends Parent {

String name;

Child(int id, String name) {

super(id); // 必须显式调用,传递参数

this.name = name; // 初始化子类属性

}

}

四、super与this的对比分析

super和this都用于非静态方法中,访问非静态成员,但作用域和用途不同:

特性thissuper引用指向当前对象(包括继承成员)当前对象的父类部分成员访问访问本类成员变量和方法访问父类成员变量和方法构造方法使用this()调用本类其他构造方法super()调用父类构造方法位置要求构造方法首行,且只能调用一次构造方法首行,且只能调用一次

关键区别:

this强调“当前对象”,super强调“父类部分”。在子类中,this.method()调用本类方法(包括重写方法),super.method()调用父类原方法。

五、对象初始化过程详解

创建子类对象时,初始化顺序严格遵循以下步骤(以Student stu = new Student();为例):

类加载阶段:

加载父类和子类,在方法区分配类变量空间并初始化为默认值(如int为0)。执行父类静态代码块,再执行子类静态代码块。 对象创建阶段:

堆中分配内存,包含父类和子类所有实例变量,初始化为默认值。执行父类就地初始化代码和实例代码块,再调用父类构造方法。执行子类就地初始化代码和实例代码块,再调用子类构造方法。 引用赋值:对象地址赋给引用变量(如stu)。

此过程确保父类属性优先初始化,避免未定义行为。

六、protected修饰符的作用

protected提供跨包继承访问控制:

父类在包A中,子类在包B时,子类需导入父类包。protected成员(变量或方法)允许子类直接访问,实现封装与灵活性的平衡。

// 包A中的父类

package com.example;

public class Parent {

protected int count; // protected修饰

}

// 包B中的子类

package com.test;

import com.example.Parent;

public class Child extends Parent {

void increment() {

count++; // 直接访问父类protected成员

}

}

七、final关键字的三大应用

final用于限制修改、继承或重写:

修饰变量:变量值不可变(常量),如final int MAX = 100;。修饰类:类不可被继承,如final class UtilityClass { ... }。修饰方法:方法不可被子类重写,确保行为一致。

class Base {

final void display() { // final方法,不可重写

System.out.println("Base display");

}

}

class Derived extends Base {

// 错误:尝试重写final方法会导致编译错误

// void display() { ... }

}

八、组合:继承的替代方案

组合(Composition)通过包含其他类的实例实现代码复用,避免继承的深度耦合:

实现方式:在类中定义其他类的成员变量(如public A a;或数组public A[] arr = new A[10];)。优势:更灵活,支持运行时动态替换;适用于“has-a”关系(如汽车“有”引擎)。示例:

class Engine { // 独立类

void start() {

System.out.println("Engine started");

}

}

class Car {

private Engine engine; // 组合关系

Car() {

engine = new Engine(); // 包含Engine实例

}

void drive() {

engine.start(); // 复用Engine功能

}

}

九、结论:选择继承还是组合?

继承适合“is-a”关系(如狗是动物),提供直接代码复用,但需注意初始化顺序和成员访问规则。组合更适合“has-a”关系,降低类间依赖。最佳实践:

优先使用组合避免多重继承问题。在需要多态时选择继承,并合理使用super和final。始终遵循构造方法规则,确保对象初始化安全。

Java SE 语法基础:接口详解

一、接口的基本概念

接口(Interface)是一种引用数据类型,用于定义“能做什么”的行为规范。它不关注对象“是什么”(如继承关系)或“有什么”(如组合关系),而是强调类应实现的功能。

继承(Inheritance):表示“is-a”关系,例如狗是动物(Dog extends Animal)。组合(Composition):表示“has-a”关系,例如车有轮胎(Car has Tire)。接口(Interface):表示“can-do”关系,例如类能排序(implements Sortable)。

接口的核心价值在于:

统一行为规范:不同类共享相同功能(如排序、比较)。解耦设计:调用方只需关注接口定义,不依赖具体实现类。多态支持:通过接口引用调用方法,实现动态行为。

二、何时使用接口

接口适用于以下场景:

定义行为而非身份:当需要指定“类能做什么”(如可序列化、可比较),而非“类是什么”。共享行为:多个类需实现相同功能,但实现细节不同(如不同数据库连接类都实现Connectable接口)。未来扩展:代码不关心具体类,只要求实现接口(如使用List接口,可兼容ArrayList或LinkedList)。

例如,定义一个Drawable接口,任何可绘制对象(圆形、矩形)都能实现它:

// 定义接口

interface Drawable {

void draw(); // 抽象方法,默认public abstract

}

// 实现类

class Circle implements Drawable {

public void draw() {

System.out.println("绘制圆形");

}

}

class Rectangle implements Drawable {

public void draw() {

System.out.println("绘制矩形");

}

}

三、接口的定义与成员特点

接口使用interface关键字定义,成员遵循严格规范:

定义方式: public interface 接口名 {

// 成员变量和方法

}

成员变量:默认由public static final修饰,即常量(不可修改)。例如:int MAX_SIZE = 100; 等价于 public static final int MAX_SIZE = 100;。成员方法:

默认是抽象方法,由public abstract修饰(不需显式写出)。实现类必须重写这些方法,且访问权限必须是public(不能是默认或更低)。接口无构造方法、静态代码块或实例代码块,不能实例化对象。

示例:

interface Calculable {

double PI = 3.14; // 等价于 public static final double PI = 3.14;

double calculateArea(); // 抽象方法

}

四、接口的实现与类关系

接口由类通过implements关键字实现,称为实现类:

实现要求:类必须重写接口所有抽象方法,否则需声明为abstract类。多接口实现:一个类可实现多个接口(Java支持多接口继承)。接口继承:接口间用extends继承,相当于合并多个接口;实现类需重写所有父接口方法。

示例:

interface A {

void methodA();

}

interface B extends A { // 接口继承

void methodB();

}

class MyClass implements B { // 实现类

public void methodA() {

System.out.println("实现methodA");

}

public void methodB() {

System.out.println("实现methodB");

}

}

五、接口与抽象类的区别

接口和抽象类都用于定义规范,但核心区别在于功能限制:

接口(Interface):

只能包含抽象方法和常量。无构造方法,不能实例化。强调“行为契约”,适合多态和松散耦合。 抽象类(Abstract Class):

可包含普通方法、成员变量和构造方法。子类可直接复用父类方法。强调“部分实现”,适合代码复用和层次结构。

对比总结:

特性接口抽象类成员方法仅抽象方法可抽象方法或普通方法成员变量仅常量(final)可变量或常量构造方法无有实例化不能不能多继承支持是(多接口实现)否(单继承)适用场景定义行为规范提供部分实现

六、总结

接口是Java多态和设计模式的基础,它通过定义“能做什么”来解耦代码,提升灵活性和可扩展性。关键点包括:

使用场景:定义共享行为、不依赖具体类。定义规范:interface关键字,成员默认public abstract(方法)和public static final(变量)。实现机制:类通过implements重写方法,支持多接口。与抽象类区别:接口无状态实现,抽象类可包含具体逻辑。

Java SE 语法基础:内部类详解

1. 什么是内部类?

内部类允许在一个类的内部定义另一个类,从而增强代码的模块化。例如,一个购物车类可能包含一个订单内部类来处理订单逻辑。内部类的主要优势包括:

封装性:将相关逻辑封装在外部类中,减少代码耦合。访问权限:内部类可以直接访问外部类的成员(包括私有成员)。灵活性:适用于事件处理、回调机制等场景。

在Java中,内部类分为三类:

成员内部类:定义在外部类的成员位置,包括静态成员内部类和实例成员内部类。局部内部类:定义在方法或作用域内部。

接下来,我们详细探讨每种类型。

2. 静态成员内部类

静态成员内部类使用static关键字修饰,它类似于外部类的一个静态成员。静态内部类不依赖于外部类对象,因此可以直接通过外部类名访问。

使用注意事项:

在静态内部类的方法中,只能访问外部类的静态成员(如静态变量或静态方法)。创建静态内部类对象时,不需要先创建外部类对象,直接通过外部类名即可访问。

代码示例:

class OuterClass {

private int a; // 实例变量

static int b; // 静态变量

public void methodA() {

a = 10;

System.out.println(a);

}

public static void methodB() {

System.out.println(b);

}

// 静态成员内部类

static class InnerStaticClass {

public void methodInner() {

b = 200; // 只能访问外部类的静态成员

methodB(); // 调用外部类的静态方法

}

}

}

public class Test {

public static void main(String[] args) {

// 创建静态内部类对象:直接通过外部类名访问

OuterClass.InnerStaticClass inner = new OuterClass.InnerStaticClass();

inner.methodInner(); // 输出结果:200

}

}

关键点:

静态内部类无法访问外部类的实例变量(如a),因为它不绑定外部类对象。适合工具类或辅助功能,无需外部类实例。

3. 实例成员内部类

实例成员内部类未使用static修饰,它依赖于外部类对象。实例内部类可以访问外部类的所有成员(包括私有成员),但创建对象时必须基于外部类实例。

使用注意事项:

实例内部类可以访问外部类的任意成员(实例变量、静态变量、方法等)。如果内部类和外部类有同名成员,访问外部类成员需使用外部类名.this.成员名。创建实例内部类对象前,必须先创建外部类对象。外部类不能直接访问实例内部类的成员,需先创建内部类对象。

代码示例:

class OuterClass2 {

private int a; // 实例变量

static int b; // 静态变量

int c; // 实例变量

public void methodA() {

a = 10;

System.out.println(a);

}

public void methodB() {

System.out.println(b);

}

// 实例成员内部类

class InnerInstanceClass {

int c; // 与外部类同名变量

public void methodInner() {

a = 100; // 访问外部类私有成员

b = 200; // 访问外部类静态成员

methodA(); // 调用外部类方法

methodB(); // 调用外部类方法

c = 300; // 访问内部类自身成员

System.out.println(c); // 输出300(内部类c)

// 访问外部类同名成员:使用外部类名.this.成员名

OuterClass2.this.c = 400;

System.out.println(OutClass2.this.c); // 输出400(外部类c)

}

}

}

public class Test {

public static void main(String[] args) {

// 创建外部类对象

OuterClass2 outer = new OuterClass2();

// 访问外部类成员

System.out.println(OuterClass2.b); // 输出静态变量

System.out.println(outer.c); // 输出实例变量

// 创建实例内部类对象:通过外部类对象引用

OuterClass2.InnerInstanceClass inner = outer.new InnerInstanceClass();

inner.methodInner(); // 执行内部类方法

}

}

关键点:

实例内部类适合需要紧密耦合的场景,如事件监听。使用外部类名.this.成员名避免命名冲突。

4. 局部内部类

局部内部类定义在方法或代码块内部,作用域仅限于其所在方法。它不能使用public、static等访问修饰符,且使用频率较低。

使用注意事项:

局部内部类只能在定义它的方法体内使用。不能添加访问修饰符(如public),因为其作用域受限。可以访问外部类的成员,以及所在方法的局部变量(但变量需为final或有效final)。

代码示例:

class OuterClass {

int a = 10; // 外部类实例变量

public void method() {

int b = 10; // 方法局部变量(需为final或有效final)

// 局部内部类定义在方法内

class InnerLocalClass {

public void methodInner() {

System.out.println(a); // 访问外部类成员

System.out.println(b); // 访问方法局部变量

}

}

// 在方法内创建并使用局部内部类对象

InnerLocalClass inner = new InnerLocalClass();

inner.methodInner(); // 输出:10 10

}

}

public class Test {

public static void main(String[] args) {

OuterClass outer = new OuterClass();

outer.method(); // 调用方法,触发局部内部类

}

}

关键点:

局部内部类适用于一次性任务,如临时计算。在Java 8+中,访问的局部变量需为final或有效final(即值不变)。

总结

静态成员内部类:独立于外部类对象,访问静态成员。实例成员内部类:绑定外部类对象,可访问所有成员。局部内部类:定义在方法内,作用域受限。

最佳实践建议:

优先使用静态内部类,减少内存开销。在需要访问外部类实例成员时,选择实例内部类。局部内部类应谨慎使用,避免代码冗余。

Java SE 语法基础:Object类及其常用方法

一、Object类:Java类的根基

Object类位于java.lang包中,是Java所有类的默认父类。如果一个类没有显式继承其他类(如class Student),它将自动继承Object类。如果类显式继承了一个父类(如class Child extends Parent),则继承链为:Child → Parent → Object。这体现了Java的单继承原则:一个类只能直接继承一个父类,但最终所有类都追溯到Object类。这种设计确保了所有对象都具备统一的基础方法,便于通用操作。

二、toString方法:提升对象可读性

toString方法用于返回对象的字符串表示,默认实现(继承自Object)输出类似类名@哈希码的格式(如Student@1a2b3c),可读性较差。实际开发中,我们需要重写toString方法,以输出对象内部内容。例如,String类已重写此方法,直接打印字符串引用(如System.out.println(str))会输出字符串内容。

重写要点:

在子类中,使用@Override注解声明重写。返回一个描述对象状态的字符串(如属性值)。示例:在Student类中,重写toString以输出学生姓名和年龄。

三、equals方法:实现内容比较

equals方法默认比较两个对象的引用地址(即是否指向同一内存地址),而非内容。这在实际应用中不实用,因此需要重写以比较对象内容是否相等。例如,String类已重写equals,使得str1.equals(str2)比较字符串内容而非地址。

重写要点:

步骤1:检查传入对象是否为null(null引用不与任何对象相等)。步骤2:检查是否与当前对象相同(obj == this,则直接返回true)。步骤3:检查传入对象类型是否匹配(使用instanceof运算符,避免类型不匹配错误)。步骤4:类型转换后,比较属性值(如字符串用equals,基本类型用==)。示例:在Student类中,重写equals以比较姓名和年龄是否相同。

四、hashCode方法:确保对象一致性

hashCode方法返回对象的哈希码,用于数据结构(如HashMap)。重写equals时,通常需同时重写hashCode,以保证相等对象具有相同哈希码。推荐使用Objects.hash()工具方法生成哈希码,避免手动计算错误。

重写要点:

使用java.util.Objects类的hash方法,传入所有参与比较的属性。示例:在Student类中,重写hashCode基于姓名和年龄生成哈希码。

五、完整示例:Student类实现

以下是一个优化后的Student类代码,演示了toString、equals和hashCode方法的重写。代码中加入了详细注释,帮助理解每个步骤。

import java.util.Objects;

class Student {

public String name;

public int age;

public Student(String name, int age) {

this.name = name;

this.age = age;

}

@Override

public String toString() {

// 重写toString:输出可读的学生信息

return name + " " + age; // 格式:姓名+空格+年龄

}

@Override

public boolean equals(Object obj) {

// 步骤1: 检查null

if (obj == null) {

return false;

}

// 步骤2: 检查自引用

if (obj == this) {

return true;

}

// 步骤3: 检查类型匹配

if (!(obj instanceof Student)) {

return false;

}

// 步骤4: 类型转换并比较内容

Student other = (Student) obj;

return name.equals(other.name) && age == other.age; // 使用String的equals比较姓名

}

@Override

public int hashCode() {

// 使用Objects.hash生成哈希码,确保equals和hashCode一致

return Objects.hash(name, age);

}

}

public class Test {

public static void main(String[] args) {

// 测试toString:直接打印对象,输出重写后的内容

System.out.println(new Student("郭怡滔", 18)); // 输出: 郭怡滔 18

// 测试equals:比较两个内容相同但地址不同的对象

Student stu1 = new Student("zhangsan", 18);

Student stu2 = new Student("zhangsan", 18);

System.out.println(stu1.equals(stu2)); // 输出: true

}

}

六、测试与最佳实践

在Test类的main方法中:

toString测试:System.out.println(new Student("张三", 18))会自动调用重写的toString,输出张三 18。equals测试:stu1.equals(stu2)比较两个Student对象的内容,返回true(因为姓名和年龄相同)。最佳实践:

重写equals时,务必进行null检查、类型检查和属性比较。使用@Override注解确保正确重写。重写equals后,必须重写hashCode,以维护对象在集合中的行为一致性。

七、总结

Object类是Java面向对象编程的基石,其核心方法(toString、equals、hashCode)通过重写可定制对象行为。关键点包括:

toString提升对象输出的可读性。equals实现内容比较,需注意类型安全和null处理。hashCode应与equals保持一致。

Java SE 语法基础 :字符串类详解

相关博客链接:Java字符串处理:从基础到高级详解-CSDN博客

Java SE 语法基础 :Java异常详解

相关博客链接:Java异常处理深度解析-CSDN博客

相关科技文章

【重磅】腾讯80页PPT告诉你: 哪些行业将被颠覆!(完整版)
365bet官方网站是多少

【重磅】腾讯80页PPT告诉你: 哪些行业将被颠覆!(完整版)

⌚ 08-22 👁️ 8178
《dnf》武炼值怎么算 《dnf》武炼需要多少战斗力
365bet官方网站是多少

《dnf》武炼值怎么算 《dnf》武炼需要多少战斗力

⌚ 09-02 👁️ 3341
视频应用调试入门指南及其它
365体育平台怎么不取缔

视频应用调试入门指南及其它

⌚ 06-29 👁️ 8671
东海县离哪个城市最近?
365bet官方网站是多少

东海县离哪个城市最近?

⌚ 07-30 👁️ 1337

合作伙伴