Java 基本语法详解(四)
十、面向对象核心特性(封装、继承、多态)
面向对象有三大核心特性:封装、继承、多态,它们是 Java 代码设计的核心思想,能提升代码的安全性、复用性和灵活性。
1. 封装(隐藏细节,暴露接口)
封装指将类的成员变量(属性)隐藏在类内部,通过私有访问修饰符(private) 限制外部直接访问,再提供公共的 “getter/setter 方法” 供外部间接操作,实现对属性的控制(如合法性校验),避免数据被随意修改。
(1)封装的实现步骤
-
用private修饰成员变量,禁止外部直接访问;
-
提供public的getXxx()方法(获取属性值)和setXxx()方法(设置属性值);
-
在setXxx()方法中添加逻辑校验(如年龄不能为负数)。
示例:封装 Student 类
public class Student {
// 1. 用private修饰成员变量(隐藏细节)
private String name; // 姓名
private int age; // 年龄(需校验:不能为负数)
private String studentId; // 学号
// 2. 无参数构造方法
public Student() {}
// 3. 有参数构造方法(调用setter方法,复用校验逻辑)
public Student(String name, int age, String studentId) {
this.setName(name);
this.setAge(age);
this.setStudentId(studentId);
}
// 4. getter方法(获取name值)
public String getName() {
return name;
}
// 5. setter方法(设置name值,可添加校验)
public void setName(String name) {
// 校验:姓名不能为null或空字符串
if (name == null || "".equals(name)) {
System.out.println("姓名不能为空!");
this.name = "未知姓名"; // 赋予默认值
} else {
this.name = name;
}
}
// getter方法(获取age值)
public int getAge() {
return age;
}
// setter方法(设置age值,校验年龄合法性)
public void setAge(int age) {
if (age < 0 || age > 150) { // 年龄范围:0-150
System.out.println("年龄不合法!赋予默认值18");
this.age = 18;
} else {
this.age = age;
}
}
// getter/setter方法(studentId)
public String getStudentId() {
return studentId;
}
public void setStudentId(String studentId) {
this.studentId = studentId;
}
// 成员方法:自我介绍
public String introduce() {
return "大家好!我是" + getName() + ",今年" + getAge() + "岁,学号是" + getStudentId();
}
}
示例:使用封装后的 Student 类
public class EncapsulationDemo {
public static void main(String[] args) {
// 1. 通过无参数构造+setter方法创建对象
Student student1 = new Student();
student1.setName(""); // 触发姓名校验:姓名不能为空!
student1.setAge(-5); // 触发年龄校验:年龄不合法!赋予默认值18
student1.setStudentId("2023001");
System.out.println(student1.introduce()); // 输出:大家好!我是未知姓名,今年18岁,学号是2023001
// 2. 通过有参数构造方法创建对象(复用setter校验)
Student student2 = new Student("李四", 200, "2023002"); // 年龄200不合法
System.out.println(student2.introduce()); // 输出:大家好!我是李四,今年18岁,学号是2023002
}
}
2. 继承(复用代码,建立类层级)
继承指一个类(子类)继承另一个类(父类)的属性和方法,子类可直接使用父类的非私有成员,还可扩展新的属性和方法,实现代码复用。Java 中用extends关键字实现继承,且单继承(一个子类只能有一个直接父类)。
(1)继承的核心概念
-
父类(超类 / 基类):被继承的类(如 “Person” 类);
-
子类(派生类):继承父类的类(如 “Student” 类,Student extends Person);
-
继承内容:子类继承父类的public、protected成员(属性 / 方法),private成员无法直接继承(需通过父类的 getter/setter 访问);
-
super关键字:子类中用于访问父类的成员(如super.name访问父类属性,super()调用父类构造方法)。
示例:继承的实现(Person 父类 → Student 子类)
// 父类:Person(抽取共性属性和方法)
public class Person {
protected String name; // 受保护的属性(子类可直接访问)
private int age; // 私有属性(子类需通过getter/setter访问)
// 父类构造方法
public Person(String name, int age) {
this.name = name;
this.setAge(age); // 调用自身setter校验年龄
}
// 父类成员方法:吃饭
public void eat() {
System.out.println(name + "正在吃饭");
}
// getter/setter方法(age)
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0 || age > 150) {
this.age = 18;
} else {
this.age = age;
}
}
}
// 子类:Student(继承Person,扩展特有属性和方法)
public class Student extends Person {
// 子类特有属性:学号
private String studentId;
// 子类构造方法:必须先调用父类构造方法(super())
public Student(String name, int age, String studentId) {
super(name, age); // 调用父类的有参数构造方法(必须在子类构造方法第一行)
this.studentId = studentId;
}
// 子类特有方法:学习(扩展父类功能)
public void study() {
// 子类可直接访问父类的protected属性name,或通过getter访问private属性age
System.out.println(name + "(" + getAge() + "岁)正在学习,学号:" + studentId);
}
// 重写父类方法(Override):修改父类方法的实现逻辑
@Override // 注解:标识该方法是重写父类的方法(语法校验)
public void eat() {
System.out.println(name + "正在学校食堂吃饭");
}
}
示例:使用子类 Student
public class InheritanceDemo {
public static void main(String[] args) {
// 创建子类对象
Student student = new Student("张三", 20, "2023001");
// 1. 调用子类特有方法
student.study(); // 输出:张三(20岁)正在学习,学号:2023001
// 2. 调用重写后的父类方法(多态的体现)
student.eat(); // 输出:张三正在学校食堂吃饭(而非父类的“正在吃饭”)
// 3. 调用父类的getter方法(子类继承)
System.out.println(student.getAge()); // 输出:20
}
}
3. 多态(一种行为,多种实现)
多态指 “父类引用指向子类对象”,调用方法时会根据对象的实际类型执行对应的实现(即 “动态绑定”),核心是 “方法重写(Override)” 和 “父类引用指向子类对象”,能降低代码耦合度。
(1)多态的实现条件
-
存在继承关系(子类继承父类);
-
子类重写父类的方法;
-
父类引用指向子类对象(如Person p = new Student();)。
示例:多态的应用
// 父类:Animal
public class Animal {
// 父类方法(被子类重写)
public void makeSound() {
System.out.println("动物发出声音");
}
}
// 子类1:Dog(重写makeSound)
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("小狗汪汪叫");
}
}
// 子类2:Cat(重写makeSound)
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("小猫喵喵叫");
}
}
// 多态测试类
public class PolymorphismDemo {
public static void main(String[] args) {
// 1. 父类引用指向子类对象(多态的核心格式)
Animal animal1 = new Dog(); // animal1实际是Dog对象
Animal animal2 = new Cat(); // animal2实际是Cat对象
// 2. 调用方法:根据对象实际类型执行对应实现
animal1.makeSound(); // 输出:小狗汪汪叫(执行Dog的方法)
animal2.makeSound(); // 输出:小猫喵喵叫(执行Cat的方法)
// 3. 多态的优势:统一调用接口(如遍历不同子类对象)
Animal[] animals = {new Dog(), new Cat()};
for (Animal animal : animals) {
animal.makeSound(); // 自动匹配对应子类的方法
}
}
}
输出结果:
小狗汪汪叫
小猫喵喵叫
小狗汪汪叫
小猫喵喵叫
十一、访问修饰符(控制访问权限)
Java 提供 4 种访问修饰符,用于控制类、成员变量、成员方法的访问范围,从严格到宽松依次为:private → default(无修饰符) → protected → public。
1. 访问修饰符的作用范围
| 修饰符 | 同一类中 | 同一包中(非子类) | 不同包中的子类 | 不同包中的非子类 |
|---|---|---|---|---|
| private | ✅ | ❌ | ❌ | ❌ |
| default | ✅ | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
2. 访问修饰符的使用场景
-
private:用于类的成员变量(封装时隐藏细节),仅类内部可访问;
-
default:默认修饰符(不写),用于同一包内的类之间共享成员;
-
protected:用于父类的成员,供子类(无论是否同包)访问,非子类不可访问;
-
public:用于对外暴露的接口(如类、getter/setter 方法),所有类均可访问。
示例:访问修饰符的应用
// 包1:com.example.demo1
package com.example.demo1;
public class Person {
private String privateField = "私有属性"; // 仅Person类内部可访问
String defaultField = "默认属性"; // 同包可访问
protected String protectedField = "受保护属性"; // 同包或子类可访问
public String publicField = "公共属性"; // 所有类可访问
// 测试访问权限(同一类中均可访问)
public void testAccess() {
System.out.println(privateField); // ✅
System.out.println(defaultField); // ✅
System.out.println(protectedField); // ✅
System.out.println(publicField); // ✅
}
}
// 包1中的非子类(同包,可访问default、protected、public)
package com.example.demo1;
public class NonSubClassInSamePackage {
public void accessPerson() {
Person person = new Person();
// System.out.println(person.privateField); // ❌ private不可访问
System.out.println(person.defaultField); // ✅
System.out.println(person.protectedField); // ✅
System.out.println(person.publicField); // ✅
}
}
// 包2中的子类(不同包,可访问protected、public)
package com.example.demo2;
import com.example.demo1.Person;
public class SubClassInDifferentPackage extends Person {
public void accessParent() {
// System.out.println(privateField); // ❌ private不可访问
// System.out.println(defaultField); // ❌ default不可访问(不同包)
System.out.println(protectedField); // ✅ 子类可访问protected
System.out.println(publicField); // ✅
}
}
十二、常用 API 基础(以 String 类为例)
API(Application Programming Interface)是 Java 提供的预定义类库,包含大量实用方法,无需手动实现。java.lang.String是最常用的 API 类之一,用于处理字符串(不可变字符序列)。
1. String 类的核心特性
-
不可变性:String 对象创建后,其内容不可修改(若修改会创建新的 String 对象);
-
常用构造方法:
-
String():创建空字符串;
-
String(String original):根据传入的字符串创建对象;
-
String(char[] value):将字符数组转为字符串。
2. String 类的常用方法
| 方法名 | 功能描述 | 示例 | 结果 |
|---|---|---|---|
| length() | 获取字符串长度 | “Java”.length() | 4 |
| charAt(int index) | 获取指定索引的字符(索引从 0 开始) | “Java”.charAt(1) | ‘a’ |
| equals(Object obj) | 比较字符串内容是否相等(区分大小写) | “Java”.equals(“java”) | false |
| equalsIgnoreCase(String str) | 比较字符串内容(不区分大小写) | “Java”.equalsIgnoreCase(“java”) | true |
| contains(CharSequence s) | 判断字符串是否包含指定子串 | “Hello Java”.contains(“Java”) | true |
| indexOf(String str) | 查找子串首次出现的索引(未找到返回 - 1) | “Hello Java”.indexOf(“Java”) | 6 |
| substring(int beginIndex) | 从指定索引开始截取子串(到末尾) | “Hello Java”.substring(6) | “Java” |
| replace(CharSequence old, CharSequence new) | 替换字符串中的子串 | “Hello Java”.replace(“Java”, “World”) | “Hello World” |
| split(String regex) | 按指定正则表达式分割字符串,返回字符串数组 | “a,b,c”.split(“,”) | [“a”, “b”, “c”] |
| toUpperCase() | 将字符串转为大写 | “Java”.toUpperCase() | “JAVA” |
| toLowerCase() | 将字符串转为小写 | “Java”.toLowerCase() | “java” |
示例:String 类常用方法的使用
public class StringApiDemo {
public static void main(String[] args) {
String str = "Hello Java!";
// 1. 获取长度
System.out.println("字符串长度:" + str.length()); // 输出:7
// 2. 获取指定索引字符
System.out.println("索引3的字符:" + str.charAt(3)); // 输出:'l'
// 3. 比较内容
String str2 = "hello java!";
System.out.println("equals比较:" + str.equals(str2)); // 输出:false
System.out.println("忽略大小写比较:" + str.equalsIgnoreCase(str2)); // 输出:true
// 4. 包含子串
System.out.println("是否包含'Java':" + str.contains("Java")); // 输出:true
// 5. 截取子串
System.out.println("从索引6截取:" + str.substring(6)); // 输出:"Java!"
// 6. 替换子串
String newStr = str.replace("Java", "World");
System.out.println("替换后:" + newStr); // 输出:"Hello World!"

7080

被折叠的 条评论
为什么被折叠?



