Java 核心概念补充说明
一、封装的实际意义与示例解析
封装是面向对象三大特性之一,核心是通过访问权限控制隐藏类的内部实现细节,仅暴露必要的接口供外部交互。
以Person.java为例:
- 将
name属性用private修饰,限制了直接访问(如person.name = "xiaoming"会报错) - 通过
public修饰的getName()和setName()方法提供访问入口,可在方法中添加验证逻辑(如姓名长度限制) - 优势:保护数据完整性、降低代码耦合度、便于后续维护扩展
二、接口的应用场景与特性
接口是一种行为规范,用于定义类必须实现的方法,不关注具体实现。
从Flyable.java和Bird.java看接口特性:
- 抽象方法 :如
fly(),实现类必须重写(Bird类实现了fly()方法) - 默认方法 :带
default关键字,有默认实现,实现类可选择重写(Bird重写了land()方法) - 静态方法 :带
static关键字,属于接口本身,通过接口名直接调用(Flyable.info()) - 多实现特性:类可同时实现多个接口,弥补 Java 单继承的局限性
接口降低耦合度的体现:当需要新增 "飞行" 功能的类(如Plane)时,只需实现Flyable接口,无需修改原有代码。
三、抽象类与接口的区别
从Animal抽象类和Flyable接口对比:
| 特性 | 抽象类 | 接口 |
|---|---|---|
| 关键字 | abstract class |
interface |
| 实例化 | 不能 | 不能 |
| 方法类型 | 可包含抽象方法和具体方法 | JDK8 + 可包含抽象方法、默认方法、静态方法 |
| 继承 / 实现 | 单继承(extends) |
多实现(implements) |
| 成员变量 | 可包含各种权限的变量 | 只能是public static final常量 |
| 设计意图 | 体现 "is-a" 关系(如Dog is a Animal) |
体现 "has-a" 能力(如Bird has a Flyable能力) |
四、内部类的特性与使用场景
以Outer.java中的成员内部类为例:
- 访问权限 :内部类可直接访问外部类的所有成员(包括
private修饰的outerVar) - 创建方式 :
- 外部类内部:直接
new Inner() - 外部类外部:需通过外部类实例创建(
outer.new Inner())
- 外部类内部:直接
- 应用场景 :
- 当内部类仅服务于外部类时,可隐藏实现细节
- 方便访问外部类的成员,适合编写事件监听器等场景
五、==与equals()的深层对比
结合Test01.java中的示例:
- 基本数据类型 :
==比较值(如a == c中 10 与 10.0 值相等,返回 true) - 引用数据类型 :
==比较内存地址(s1 == s2为 false,因是两个不同对象)equals()默认等同于==(Object 类实现),但可重写用于内容比较(如 String 类重写后比较字符序列)
- 注意点 :
- 比较字符串内容时应使用
equals(),而非== - 重写
equals()时需遵循对称性、传递性等规则,通常需同时重写hashCode()
- 比较字符串内容时应使用
六、静态成员的特性与生命周期
从Test01.java的Student类示例:
- 静态变量 (
static String school):- 属于类本身,所有对象共享同一份内存
- 一个对象修改后,所有对象访问到的都是修改后的值
- 静态方法 (
static void eat()):- 通过类名直接调用(
Student.eat()),无需创建对象 - 不能访问非静态成员(因静态成员加载时非静态成员可能尚未初始化)
- 通过类名直接调用(
- 静态代码块 :
- 类加载时执行,且只执行一次
- 用于初始化静态资源,执行顺序早于构造器
七、多态的实现与优势
在Test02.java中体现:
- 向上转型 :
Animal dog = new Dog("旺财")- 父类引用指向子类对象,自动完成
- 可调用父类声明的方法,实际执行子类重写的实现(如
dog.eat()执行Dog类的eat())
- 优势 :
- 提高代码灵活性:同一方法调用可表现不同行为
- 便于扩展:新增子类(如
Cat)无需修改使用父类的代码
instanceof运算符 :判断对象实际类型,避免转型错误(如animal instanceof Dog)
八、权限修饰符的实际应用
根据Test01.java中的权限表:
private:仅本类可见,用于隐藏内部状态(如Person的name)default(缺省):同一包内可见,适合包内组件间协作protected:同一包或不同包子类可见,用于继承体系中的成员共享public:全局可见,用于对外提供的接口方法(如Person的getName())
合理使用权限修饰符可降低类之间的依赖,提高代码安全性和可维护性。
整理在一起,写成word文档形式
Java 核心知识点全解析
一、数据类型与类型转换
(一)数据类型分类
Java 数据类型分为基本数据类型和引用数据类型,二者在存储方式和使用场景上有显著区别。
- 基本数据类型 (8 种):直接存储数据值,占用固定内存空间。
- 整数类型:
byte(1 字节)、short(2 字节)、int(4 字节)、long(8 字节),用于存储整数数值,根据数值范围选择对应类型。 - 浮点类型:
float(4 字节)、double(8 字节),用于存储小数,double精度高于float,日常开发中更常用。 - 字符类型:
char(2 字节),用于存储单个字符,如'a'、'中'。 - 布尔类型:
boolean,仅表示true(真)或false(假),JVM 未明确规定其占用内存大小。
- 整数类型:
- 引用数据类型:存储对象的内存地址,而非数据本身,包括类、接口、数组三类。
(二)类型转换规则
类型转换需遵循 "范围匹配" 原则,避免数据精度丢失或运行错误。
- 自动转换 :小范围类型向大范围类型转换,无需显式声明,数据不会丢失。
- 转换顺序:
byte→short→int→long→float→double - 示例:
int a = 10; long b = a;,a的int类型自动转换为long类型。
- 转换顺序:
- 强制转换 :大范围类型向小范围类型转换,需显式添加目标类型括号,可能导致数据精度丢失。
- 示例:
int c = 100; byte d = (byte)c;,若c值超过byte范围(-128~127),转换后数据会异常。
- 示例:
二、运算符
运算符是用于执行数据运算的符号,Java 提供多种运算符以满足不同计算需求。
- 算术运算符 :用于基本数学运算,包括
+(加)、-(减)、*(乘)、/(除)、%(取余)、++(自增)、--(自减)。- 自增 / 自减分为前缀和后缀两种形式:
- 前缀:
++a、--a,先执行自增 / 自减,再参与其他运算。 - 后缀:
a++、a--,先参与其他运算,再执行自增 / 自减。
- 前缀:
- 示例:
int a = 5; int b = a++;(b值为 5,a值变为 6);int c = ++a;(a值变为 7,c值为 7)。
- 自增 / 自减分为前缀和后缀两种形式:
- 赋值运算符 :用于给变量赋值,基础运算符为
=,扩展运算符包括+=、-=、*=、/=等,可简化代码并自动处理类型转换。- 示例:
int a = 3; a += 2;(等价于a = (int)(a + 2),a值变为 5)。
- 示例:
- 比较运算符 :用于比较两个值的关系,结果为
boolean类型(true或false),包括>(大于)、<(小于)、>=(大于等于)、<=(小于等于)、==(等于)、!=(不等于)。- 示例:
int a = 5, b = 3; System.out.println(a > b);(输出true)。
- 示例:
- 逻辑运算符 :用于连接布尔表达式,结果为
boolean类型,包括&&(短路与)、||(短路或)、!(非)、&(与)、|(或)、^(异或)。- "短路" 特性:
&&若左侧表达式为false,右侧不再执行;||若左侧表达式为true,右侧不再执行。 - 示例:
int a = 2; System.out.println(a > 3 && ++a > 2);(左侧为false,a值仍为 2)。
- "短路" 特性:
- 位运算符 :直接对二进制位进行运算,包括
&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移)、>>(右移),常用于底层开发或高效运算。- 示例:
int a = 3; int b = a << 1;(3二进制为11,左移 1 位后为110,b值为 6)。
- 示例:
- 三元运算符 :语法为
条件表达式 ? 表达式1 : 表达式2,根据条件表达式结果选择执行表达式 1 或表达式 2,可简化简单的分支逻辑。- 示例:
int max = (a > b) ? a : b;(若a > b,max取a值,否则取b值)。
- 示例:
三、流程控制
流程控制用于控制代码的执行顺序,包括分支结构和循环结构两类。
(一)分支结构
根据条件判断执行不同代码块,主要有if-else和switch两种形式。
-
if-else :适合范围性条件判断,可嵌套使用,逻辑清晰。
-
语法:
if (条件1) {
// 条件1为true时执行
} else if (条件2) {
// 条件1为false、条件2为true时执行
} else {
// 所有条件均为false时执行
} -
示例:
int score = 85;
if (score > 90) {
System.out.println("优秀");
} else if (score > 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}
-
-
switch :适合等值条件判断,JDK7 及以上支持
String类型,需注意 "穿透" 问题。-
语法:
switch (表达式) {
case 值1:
// 表达式等于值1时执行
break; // 终止switch,避免穿透
case 值2:
// 表达式等于值2时执行
break;
default:
// 表达式不等于任何case值时执行
} -
示例:
String day = "周一";
switch (day) {
case "周一":
System.out.println("工作日第一天");
break;
case "周日":
System.out.println("休息日");
break;
default:
System.out.println("普通日期");
} -
注意:若省略
break,会从匹配的case开始,依次执行后续所有代码,直至遇到break或switch结束,即 "switch 穿透"。
-
(二)循环结构
用于重复执行某段代码,主要有for、while、do-while三种形式。
-
for :适合已知循环次数的场景,语法简洁,控制变量作用域明确。
-
语法:
for (初始化语句; 循环条件; 更新语句) {
// 循环体:条件为true时执行
} -
示例:
for (int i = 0; i < 5; i++) {
System.out.println("循环第" + (i + 1) + "次");
}
-
-
while :适合未知循环次数的场景,先判断条件,再执行循环体。
-
语法:
while (循环条件) {
// 循环体:条件为true时执行
} -
示例:
int count = 0;
while (count < 3) {
System.out.println("count: " + count);
count++;
}
-
-
do-while :与
while类似,但先执行一次循环体,再判断条件,确保循环体至少执行一次。-
语法:
do {
// 循环体
} while (循环条件); -
示例:
int num = 5;
do {
System.out.println("num: " + num);
num--;
} while (num > 3);
-
-
循环控制关键字 :
break:立即终止当前所在的循环或switch,跳出代码块。continue:跳过当前循环的剩余代码,直接进入下一次循环判断。
四、类与对象
类与对象是面向对象编程的核心,类是对象的模板,对象是类的实例。
(一)类的结构
类包含属性(成员变量)、方法、构造器、代码块等组件,共同描述对象的特征和行为。
-
属性(成员变量) :用于存储对象的状态信息,声明在类中、方法外,有默认初始值(如
int默认 0,String默认null)。- 示例:
public class Person { String name; int age; },name和age即为Person类的属性。
- 示例:
-
方法 :用于定义对象的行为,包含方法名、参数列表、返回值类型、方法体。
-
示例:
public class Person {
public void sayHello() {
System.out.println("Hello!");
}
}
-
-
构造器 :与类名相同,无返回值类型,用于创建对象时初始化属性,若未自定义,编译器会生成默认无参构造器。
-
示例:
public class Person {
String name;
// 自定义构造器
public Person(String name) {
this.name = name;
}
}
-
-
代码块 :分为静态代码块和实例代码块,用于初始化资源。
-
静态代码块:用
static修饰,类加载时执行,仅执行一次,优先于构造器。 -
实例代码块:无
static修饰,创建对象时执行,每次创建对象都会执行。 -
示例:
public class Person {
// 静态代码块
static {
System.out.println("类加载时执行");
}
// 实例代码块
{
System.out.println("创建对象时执行");
}
}
-
(二)访问权限修饰符
访问权限修饰符用于控制类、属性、方法的访问范围,保障代码安全性和封装性,共 4 种。
| 修饰符 | 同一类中 | 同一包中 | 同包子类中 | 不同包中 |
|---|---|---|---|---|
public |
✔️ | ✔️ | ✔️ | ✔️ |
protected |
✔️ | ✔️ | ✔️ | ❌ |
| 默认(无修饰符) | ✔️ | ✔️ | ❌ | ❌ |
private |
✔️ | ❌ | ❌ | ❌ |
- 应用场景:
private:修饰属性,仅本类可访问,通过getter/setter对外暴露访问接口。public:修饰对外提供的类、方法,方便外部调用。
(三)封装
封装是面向对象三大特性之一,核心是 "隐藏内部细节,暴露安全接口",通过private修饰属性、提供public的getter/setter方法实现。
-
示例(参考
Person.java):public class Person {
// private修饰属性,隐藏内部细节
private String name;
private int age;// getter方法:获取属性值 public String getName() { return name; } // setter方法:设置属性值,可添加验证逻辑 public void setName(String name) { // 验证姓名不为空 if (name != null && !name.isEmpty()) { this.name = name; } }}
-
优势:保护数据完整性,避免非法赋值;降低代码耦合度,便于后续维护和扩展。
五、继承与多态
继承与多态是面向对象编程的重要特性,实现代码复用和灵活扩展。
(一)继承
继承通过extends关键字实现,子类继承父类的非私有属性和方法,Java 支持单继承(一个子类只能有一个直接父类)。
-
继承的核心特性 :
- 子类可直接使用父类的非私有成员,减少代码重复。
- 子类可重写父类方法,实现个性化逻辑。
- 通过
super关键字调用父类的构造器、属性、方法。
-
示例:
// 父类
public class Animal {
public void eat() {
System.out.println("动物进食");
}
}// 子类,继承Animal
public class Dog extends Animal {
// 重写父类eat方法
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
(二)抽象类
抽象类用abstract关键字修饰,是包含抽象方法的类,不能实例化,需通过子类继承并实现抽象方法使用。
-
抽象类的特性 :
- 可包含抽象方法(无方法体,用
abstract修饰)和具体方法(有方法体)。 - 非抽象子类继承抽象类后,必须实现所有抽象方法;若子类也为抽象类,可不用实现。
- 可包含抽象方法(无方法体,用
-
示例(参考
Test02.java):// 抽象父类
abstract class Animal {
String name;
// 具体方法
public void sleep() {
System.out.println(name + "在睡觉");
}
// 抽象方法
public abstract void eat();
}// 非抽象子类,实现抽象方法
class Dog extends Animal {
public Dog(String name) {
this.name = name;
}
@Override
public void eat() {
System.out.println(name + "吃骨头");
}
}
(三)多态
多态是指同一行为在不同对象上有不同表现形式,核心是 "父类引用指向子类对象"(向上转型),需满足 "继承""方法重写""向上转型" 三个条件。
-
多态的实现 :
-
向上转型:自动转换,父类引用指向子类对象,可调用父类声明的方法,实际执行子类重写的实现。
-
示例(参考
Test02.java):Animal dog = new Dog("旺财"); // 向上转型
dog.eat(); // 执行Dog类的eat(),输出"旺财吃骨头"
dog.sleep(); // 执行Animal类的sleep(),输出"旺财在睡觉"
-
-
多态的优势 :
- 提高代码灵活性:同一方法调用可根据对象实际类型执行不同逻辑。
- 便于扩展:新增子类(如
Cat)时,无需修改使用父类的代码,符合 "开闭原则"。
-
instanceof运算符 :用于判断对象的实际类型,避免转型错误,返回值为boolean类型。-
示例:
Animal animal = new Dog("旺财");
System.out.println(animal instanceof Dog); // true(animal实际是Dog对象)
System.out.println(animal instanceof Animal); // true(Dog是Animal子类)
-
六、接口
接口是一种行为规范,用interface关键字定义,用于约束类的行为,不关注具体实现,弥补 Java 单继承的局限性。
(一)接口的结构
接口包含抽象方法、默认方法(JDK8+)、静态方法(JDK8+),所有成员默认用public修饰(可省略)。
-
抽象方法:无方法体,实现类必须重写。
-
默认方法 :用
default修饰,有方法体,实现类可选择重写或直接使用。 -
静态方法 :用
static修饰,有方法体,属于接口本身,通过接口名直接调用,实现类不能重写。 -
示例(参考
Flyable.java):public interface Flyable {
// 抽象方法
void fly();
// 默认方法
default void land() {
System.out.println("默认降落");
}
// 静态方法
static void info() {
System.out.println("这是飞行接口");
}
}
(二)接口的实现
类通过implements关键字实现接口,可同时实现多个接口,需重写所有接口的抽象方法。
-
示例(参考
Bird.java和Test02.java):// 实现Flyable接口
class Bird implements Flyable {
// 重写抽象方法fly()
@Override
public void fly() {
System.out.println("鸟儿飞翔");
}
// 重写默认方法land()(可选)
@Override
public void land() {
System.out.println("鸟儿降落");
}
}// 测试
public class Test02 {
public static void main(String[] args) {
Flyable bird = new Bird();
bird.fly(); // 输出"鸟儿飞翔"
bird.land(); // 输出"鸟儿降落"
Flyable.info(); // 输出"这是飞行接口"(调用静态方法)
}
} -
接口的优势 :
- 降低耦合度:接口定义规范,实现类可独立变化,如新增
Plane类实现Flyable接口,无需修改原有代码。 - 支持多实现:一个类可实现多个接口,满足多种行为需求,如
class Plane implements Flyable, Runnable。
- 降低耦合度:接口定义规范,实现类可独立变化,如新增
七、内部类
内部类是定义在另一个类(外部类)内部的类,根据位置和修饰符分为成员内部类、静态内部类、局部内部类、匿名内部类,此处重点介绍成员内部类(参考Outer.java)。
(一)成员内部类的特性
成员内部类定义在外部类内部、方法外,无static修饰,与外部类实例关联。
-
访问权限 :可直接访问外部类的所有成员(包括
private修饰的成员),外部类需通过内部类实例访问内部类成员。 -
创建方式 :
- 外部类内部:直接
new 内部类()创建。 - 外部类外部:需先创建外部类实例,再通过
外部类实例.new 内部类()创建。
- 外部类内部:直接
-
示例(参考
Outer.java):public class Outer {
private int outerVar = 10; // 外部类私有成员// 成员内部类 class Inner { int innerVar = 20; public void innerMethod() { // 访问外部类私有成员 System.out.println("外部类变量:" + outerVar); System.out.println("内部类变量:" + innerVar); } } // 外部类方法中使用内部类 public void outerMethod() { Inner inner = new Inner(); // 外部类内部创建内部类实例 inner.innerMethod(); } public static void main(String[] args) { // 外部类外部创建内部类实例 Outer outer = new Outer(); Outer.Inner inner = outer.new Inner(); inner.innerMethod(); // 输出"外部类变量:10""内部类变量:20" }}
(二)成员内部类的应用场景
- 当内部类仅服务于外部类,且需要频繁访问外部类成员时使用,可隐藏内部实现细节,提高代码封装性,如事件监听器、迭代器等场景。
八、关键字补充
(一)final
final用于修饰类、方法、变量,表示 "不可变"。
- 修饰类 :类不能被继承,如
final class String,确保类的稳定性。 - 修饰方法 :方法不能被重写,如父类中
final修饰的方法,子类无法修改其逻辑。 - 修饰变量 :
-
基本数据类型变量:初始化后值不可改变。
-
引用数据类型变量:初始化后内存地址不可改变,但对象内容可修改。
-
示例:
final int a = 5;
// a = 6; // 报错:基本类型变量值不可变final int[] arr = {1, 2, 3};
arr[0] = 100; // 允许:修改数组内容
// arr = new int[5]; // 报错:引用地址不可变
-
(二)static
static用于修饰属性、方法、代码块,属于类本身,而非对象实例。
-
静态属性 :所有对象共享同一数据,通过
类名.属性名访问,如Student.school(参考Test01.java)。-
示例:
class Student {
static String school; // 静态属性
}
Student.school = "河金";
System.out.println(Student.school); // 输出"河金"
-
-
静态方法 :属于类,通过
类名.方法名访问,不能访问非静态成员(非静态成员依赖对象实例),如Student.eat()(参考Test01.java)。-
示例:
class Student {
public static void eat() {
System.out.println("吃饭");
}
}
Student.eat(); // 直接通过类名调用
-
-
注意 :静态成员加载时机早于非静态成员,在静态方法中不能使用
this和super关键字。
(三)this
this代表当前对象的引用,用于区分成员变量和局部变量、调用当前类的构造器、调用当前类的方法。
-
示例:
public class Person {
private String name;
public Person(String name) {
this.name = name; // 区分成员变量和局部变量
}
}
九、数组
数组是存储相同类型数据的容器,属于引用数据类型,长度固定(初始化后不可改变)。
(一)数组的声明与初始化
- 声明方式 :两种语法等价,推荐第一种,更符合 Java 风格。
数据类型[] 数组名,如int[] arr。数据类型 数组名[],如int arr[]。
- 初始化方式 :
- 静态初始化:指定数组元素,长度由元素个数决定,如
int[] arr = {1, 2, 3};。 - 动态初始化:指定数组长度,元素为默认值,如
int[] arr = new int[3];(元素默认值为 0)。
- 静态初始化:指定数组元素,长度由元素个数决定,如
(二)数组的访问与遍历
- 访问 :通过 "数组名 [索引]" 访问元素,索引从 0 开始,最大索引为 "数组长度 - 1",若索引越界会抛出
ArrayIndexOutOfBoundsException。- 示例:
int[] arr = {1, 2, 3}; System.out.println(arr[0]);(输出 1)。
- 示例:
- 遍历 :通过
for循环或增强for循环(for-each)遍历数组元素。-
示例:
int[] arr = {1, 2, 3};
// 普通for循环
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 增强for循环
for (int num : arr) {
System.out.println(num);
}
-
十、字符串比较
字符串比较是常见操作,需区分==和equals()的差异,避免逻辑错误。
(一)==的作用
- 基本数据类型:比较值是否相等,如
int a = 10, b = 10; System.out.println(a == b);(输出true)。 - 引用数据类型:比较对象的内存地址是否相同,即是否指向同一个对象,如
String s1 = new String("abc"), s2 = new String("abc"); System.out.println(s1 == s2);(输出false,因s1和s2是两个不同对象)。
(二)equals()的作用
equals()是Object类的方法,默认实现与==一致(比较内存地址),但许多类(如String、Integer)重写了该方法,用于比较对象内容是否相等。
-
String类的equals():比较字符串的字符序列是否相同,与内存地址无关。-
示例:
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.equals(s2)); // 输出true(内容相同)
-
-
自定义类重写
equals():若需比较自定义对象的内容,需手动重写equals()方法,通常需同时重写hashCode()方法(保证 "equals 相等的对象,hashCode 一定相等")。-
示例:
public class Person {
private String name;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
-