类和对象
1. 类的定义
- 类 是对象的模板,用于定义对象的属性和行为
- 类的组成
- 属性:表示对象的特征(名字/年龄/性别)
- 方法:表示对象的行为(吃饭/睡觉/跑步)
// 语法
class 类名 {
// 属性(成员变量)
数据类型 属性名;
// 方法(成员方法)
返回类型 方法名(参数列表) {
// 方法体
}
}
class Student {
// 属性(特征)
String name; // 学生的名字
int age; // 学生的年龄
// 方法(行为)
void study() {
System.out.println(name + " 正在学习。");
}
void introduce() {
System.out.println("大家好,我是 " + name + ",今年 " + age + " 岁。");
}
}
2. 对象的定义
- 对象是类的具体实例。类是抽象的,而对象是具体的
// 语法
类名 对象名 = new 类名();
// 示例
public class Main {
public static void main(String[] args) {
// 创建 Student 类的对象
Student student = new Student();
// 设置对象的属性
student.name = "小明";
student.age = 18;
// 调用对象的方法
student.study();
student.introduce();
}
}
// 输出结果
小明 正在学习。
大家好,我是 小明,今年 18 岁。
3. 类和对象的核心思想
- 类:抽象定义了一类事物的属性和行为。
- 如“学生”是类,描述了所有学生的共性(名字、年龄等属性,学习等行为)。
- 对象:类的一个具体实例。
- 如“小明”是一个学生对象,“小红”是另一个学生对象。
4. 构造方法
构造方法用于初始化对象的属性。
- 构造方法的特点
- 构造方法的名称必须和类名相同。
- 构造方法没有返回值。
- 创建对象时,构造方法会被自动调用。
// 示例
class Student {
String name;
int age;
// 构造方法
Student(String name, int age) {
this.name = name; // 使用 this 关键字引用当前对象
this.age = age;
}
void introduce() {
System.out.println("大家好,我是 " + name + ",今年 " + age + " 岁。");
}
}
public class Main {
public static void main(String[] args) {
// 创建对象时传入参数
Student student = new Student("小明", 18);
student.introduce();
}
}
大家好,我是 小明,今年 18 岁。
5. 类与对象的高级特性(封装继承多态)
- 封装
- 是将对象的属性和行为(方法)封装在一起,通过访问控制(如 private)限制外部对属性的直接访问,提供公共方法(如 get 和 set 方法)与外界交互。
- 优点:
- 提高安全性:保护对象内部数据,不允许外界随意修改。
- 提高代码维护性:通过方法控制数据的合法性。
- 隐藏实现细节:只暴露对外接口,简化使用。
// 封装
class Person {
private String name; // 私有属性,只能通过方法访问
private int age;
// 构造方法初始化对象
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 公共方法提供访问接口
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 0) { // 数据校验
this.age = age;
} else {
System.out.println("年龄不能为负数!");
}
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("小明", 25);
System.out.println("姓名:" + person.getName());
System.out.println("年龄:" + person.getAge());
person.setAge(-5); // 不合法的年龄修改
person.setAge(30); // 合法的修改
System.out.println("修改后的年龄:" + person.getAge());
}
}
姓名:小明
年龄:25
年龄不能为负数!
修改后的年龄:30
- 继承
- 一个类可以继承另一个类的属性和方法
- 优点:
- 代码复用:子类直接使用父类的功能,不需要重复定义。
- 易于扩展:子类可以在父类基础上添加新功能。
- 提高维护性:公共功能集中在父类,减少冗余代码
// 父类
class Animal {
String name;
void eat() {
System.out.println(name + " 正在吃东西。");
}
}
// 子类
class Dog extends Animal {
void bark() {
System.out.println(name + " 在汪汪叫。");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "小艾克斯"; // 继承父类的属性
dog.eat(); // 继承父类的方法
dog.bark(); // 调用子类的方法
}
}
小艾克斯 正在吃东西。
小艾克斯 在汪汪叫。
- 多态
- 多态指同一个方法在不同对象上的表现行为不同。分为:
- 编译时多态(方法重载):在同一类中定义多个同名方法,但参数不同。
- 运行时多态(方法重写):通过父类引用调用子类对象的方法。
- 优点:
- 灵活性:父类定义统一的接口,子类根据需要实现具体行为。
- 扩展性:添加新子类时无需修改现有代码。
- 多态指同一个方法在不同对象上的表现行为不同。分为:
- 编译时多态:方法重载
- 根据同名方法根据参数的类型/数量或顺序的不同,执行不同的逻辑
class Calculator {
int add(int a, int b) {
return a + b;
}
// 重载方法
double add(double a, double b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
System.out.println("两整数相加:" + calculator.add(3, 5));
System.out.println("两小数相加:" + calculator.add(3.5, 5.2));
System.out.println("三整数相加:" + calculator.add(3, 5, 7));
}
}
两整数相加:8
两小数相加:8.7
三整数相加:15
- 运行时多态:方法重写
- 方法重写是子类重写父类的方法,通过父类引用调用子类实现
class Animal {
void sound() {
System.out.println("动物发出声音。");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("艾克斯汪汪叫。");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("猫喵喵叫。");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog(); // 父类引用指向子类对象
animal1.sound(); // 调用子类的重写方法
Animal animal2 = new Cat();
animal2.sound();
}
}
艾克斯汪汪叫。
猫喵喵叫。
- 封装/继承/多态 的关系
- 封装:保护属性,隐藏实现细节。
- 继承:复用代码,将共性提取到父类。
- 多态:让同一接口在不同对象上表现出不同行为。
class Animal {
private String name; // 封装
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void sound() {
System.out.println(name + " 发出声音。");
}
}
class Dog extends Animal {
public Dog(String name) {
super(name); // 调用父类构造方法
}
@Override
public void sound() {
System.out.println(getName() + " 汪汪叫。");
}
}
class Cat extends Animal {
public Cat(String name) {
super(name);
}
@Override
public void sound() {
System.out.println(getName() + " 喵喵叫。");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog("小艾克斯"); // 多态
dog.sound();
Animal cat = new Cat("小猫");
cat.sound();
}
}
小艾克斯 汪汪叫。
小猫 喵喵叫。
6. 总结
- 类是抽象的,是一类事物的模板。
- 对象是类的实例,是一个具体存在的实体。
- 类与对象的核心特性包括:
- 封装:保护属性的安全性。
- 继承:实现代码复用。
- 多态:提高代码灵活性。
方法和封装
1. 方法
方法是封装在类中的功能块,表示对象可以执行的行为或操作
- 方法的定义
- Java 方法通常由以下部分组成:
- 访问修饰符:控制方法的访问权限(如 public、private)。
- 返回值类型:方法返回的数据类型(如 int、void)。
- 方法名:标识方法的名称,应该遵循驼峰命名规则。
- 参数列表:方法需要的输入参数,参数类型和名称需声明。
- 方法体:方法执行的代码块,包含具体的功能实现。
// 语法
访问修饰符 返回值类型 方法名(参数列表) {
// 方法体
return 返回值; // 如果返回值类型是 void,可以省略 return
}
// 示例
public class Main {
// 定义一个方法
public static int add(int a, int b) {
return a + b; // 返回两个整数的和
}
public static void main(String[] args) {
int result = add(5, 3); // 调用方法
System.out.println("5 + 3 = " + result);
}
}
2. 封装
封装是将数据(属性)和行为(方法)包装在一起,并对外隐藏实现细节,只暴露必要的接口。 它是面向对象的三大特性之一,主要用于保护对象的内部状态,防止外部不安全的访问和修改。
- 封装的核心原则
- 使用访问修饰符控制访问权限:
- public:对所有类可见。
- private:仅对当前类可见。
- protected:对同包和子类可见。
- 默认(包级私有):对同包内可见。
- 通过方法访问属性:
- 私有属性通过公共的 getter 和 setter 方法提供访问和修改。
- 隐藏实现细节:
- 类的具体实现对外部不可见,只暴露接口。
- 使用访问修饰符控制访问权限:
- 为什么需要封装?
- 提高代码安全性:防止外部直接修改对象的内部数据。
- 易维护性:可以随时修改实现细节而不影响外部代码。
- 增强可读性:通过 getter 和 setter 方法提供明确的数据访问方式。
3. 封装的实现步骤
- 将属性声明为 private,禁止外部直接访问。
- 提供 public 的 getter 和 setter 方法,用以访问和修改属性
public class Person {
// 私有属性
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getter 方法
public String getName() {
return name;
}
public int getAge() {
return age;
}
// Setter 方法
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
if (age > 0) { // 确保年龄为正数
this.age = age;
}
}
// 自定义方法
public void showInfo() {
System.out.println("姓名:" + name + ",年龄:" + age);
}
}
// 测试封装
public class Main {
public static void main(String[] args) {
// 创建对象
Person person = new Person("张三", 25);
// 通过 Getter 获取属性值
System.out.println("姓名:" + person.getName());
System.out.println("年龄:" + person.getAge());
// 使用 Setter 修改属性值
person.setName("李四");
person.setAge(30);
// 调用方法查看修改后的信息
person.showInfo(); // 输出:姓名:李四,年龄:30
}
}
4. 方法和封装的结合
封装和方法密切相关。封装是将数据和操作隐藏起来,通过方法提供访问接口,而方法是实现封装的主要工具
public class BankAccount {
private double balance; // 余额(封装为私有)
// 构造方法初始化账户余额
public BankAccount(double initialBalance) {
if (initialBalance > 0) {
this.balance = initialBalance;
}
}
// 存款方法
public void deposit(double amount) {
if (amount > 0) {
balance += amount;
System.out.println("存款成功,当前余额:" + balance);
} else {
System.out.println("存款金额无效");
}
}
// 取款方法
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
System.out.println("取款成功,当前余额:" + balance);
} else {
System.out.println("取款金额无效或余额不足");
}
}
// 查询余额方法
public double getBalance() {
return balance;
}
}
// 测试 BankAccount 类
public class Main {
public static void main(String[] args) {
BankAccount account = new BankAccount(1000); // 初始化账户
account.deposit(500); // 存款
account.withdraw(300); // 取款
System.out.println("最终余额:" + account.getBalance()); // 查询余额
}
}
5. 总结
- 方法是定义在类中、描述对象行为的功能块。
- 封装是面向对象编程的核心,用于隐藏内部实现细节,确保数据安全。
- 方法和封装相辅相成,封装数据后,需要通过方法实现数据的访问与操作。
static 关键字和继承
1. static 关键字
static 是 Java 中的一个关键字,用来修饰 变量、方法、代码块 和 嵌套类。被 static 修饰的成员属于类,而不是某个具体的对象。它在内存中的存储位置是方法区中的静态区
1.1 修饰变量
- 静态变量(类变量) 是类的所有对象共享的。无论创建多少个对象,静态变量只有一份,所有对象对它的修改都会影响其他对象
public class Counter {
public static int count = 0; // 静态变量
public Counter() {
count++;
}
}
public class Main {
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
System.out.println("创建的对象数量:" + Counter.count); // 输出:3
}
}
1.2 修饰方法
- 静态方法(类方法) 不依赖于实例,可以通过类名直接调用。
- 静态方法中 不能使用非静态成员,因为非静态成员属于对象,而静态方法不依赖对象。
public class MathUtil {
public static int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
int result = MathUtil.add(5, 3); // 通过类名调用静态方法
System.out.println("5 + 3 = " + result);
}
}
1.3 静态代码块
- 静态代码块 用于初始化类,在类加载时执行一次。
- 通常用于加载静态资源或配置文件。
public class Database {
static {
System.out.println("静态代码块执行:数据库连接已初始化");
}
public static void connect() {
System.out.println("数据库连接成功");
}
}
public class Main {
public static void main(String[] args) {
Database.connect();
}
}
1.4 修饰嵌套类
- 静态嵌套类 是可以独立于外部类实例而存在的类。
- 静态嵌套类不能直接访问外部类的非静态成员。
public class Outer {
static class Nested {
public void display() {
System.out.println("这是一个静态嵌套类");
}
}
}
public class Main {
public static void main(String[] args) {
Outer.Nested nested = new Outer.Nested(); // 直接创建静态嵌套类对象
nested.display();
}
}
2. 继承
继承是面向对象的三大特性之一,用于表示 “is-a” 的关系。子类继承父类后,可以直接复用父类的字段和方法,也可以重写父类的方法。
2.1 继承的语法
// 父类
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
// 子类
public class Dog extends Animal {
public void bark() {
System.out.println("艾克斯汪汪叫");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 调用父类的方法
dog.bark(); // 调用子类的方法
}
}
2.2 继承的特点
- 单继承:Java 不支持多继承,一个类只能继承一个父类。
- 为了避免多继承导致的 菱形继承问题,Java 使用接口来提供多继承的功能。
- 支持多层继承:一个类可以有多个层级的继承链。
- super 关键字:
- 调用父类的构造方法或成员。
- 示例:super.成员 或 super(参数)。
public class Animal {
public Animal(String name) {
System.out.println("动物的名字是:" + name);
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name); // 调用父类的构造方法
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("小黑"); // 输出:动物的名字是:小黑
}
}
2.3 方法重写
- 子类可以重写父类的方法,提供自己的实现逻辑。
- 必须保证方法签名一致:方法名、参数列表和返回类型必须与父类方法相同。
- 不能降低访问权限:比如,父类的方法是 public,子类不能重写为 protected 或 private。
public class Animal {
public void eat() {
System.out.println("动物吃东西");
}
}
public class Dog extends Animal {
@Override
public void eat() { // 重写父类方法
System.out.println("艾克斯吃骨头");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 输出:艾克斯吃骨头
}
}
2.4 使用 final 限制继承
- final 类:不能被继承。
- final 方法:不能被子类重写。
- final 属性:不能被修改
public final class Constants {
public final double PI = 3.14;
}
// 以下会报错:
public class SubClass extends Constants {}
3. 结合 static 与继承
- 静态成员不能被重写:静态方法属于类本身,而不是实例,因此子类中的静态方法只是隐藏了父类的静态方法。
- 静态代码块与继承:子类继承父类时,父类的静态代码块会优先执行。
public class Parent {
public static void display() {
System.out.println("父类的静态方法");
}
}
public class Child extends Parent {
public static void display() {
System.out.println("子类的静态方法");
}
}
public class Main {
public static void main(String[] args) {
Parent.display(); // 输出:父类的静态方法
Child.display(); // 输出:子类的静态方法
}
}
4. 总结
- static 关键字:
- 用于修饰变量、方法、代码块、嵌套类。
- 静态成员属于类,不依赖于对象。
- 继承:
- 是一种复用代码的方式,子类可扩展父类功能。
- 继承遵循单继承原则,但支持多层继承。
- 两者结合时,静态成员不参与继承,仅表现为隐藏。
特殊类
Java 中的特殊类包括 抽象类、接口、内部类、匿名类、枚举类 等,它们提供了更灵活的设计和实现能力,适用于特定的场景。以下是对这些特殊类的详细说明和示例。
1. 抽象类
- 特点:
- 不能实例化:抽象类不能直接创建对象,只能被继承。
- 抽象方法:一个类中如果有一个方法声明为 abstract,那么这个类必须是抽象类。
- 可以有普通方法和字段:抽象类不仅可以有抽象方法,还可以有具体实现的方法和成员变量。
- 应用场景:
- 需要定义某种通用的行为,而具体实现由子类完成。
- 可以部分实现功能,部分留给子类实现。
abstract class Animal {
public abstract void sound(); // 抽象方法,没有实现
public void eat() { // 普通方法,有具体实现
System.out.println("动物正在吃东西");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("艾克斯叫:汪汪");
}
}
class Cat extends Animal {
@Override
public void sound() {
System.out.println("猫叫:喵喵");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.sound();
dog.eat();
Animal cat = new Cat();
cat.sound();
}
}
艾克斯叫:汪汪
动物正在吃东西
猫叫:喵喵
2. 接口
- 特点:
- 接口是比抽象类更严格的抽象机制。
- 不能有实例字段:所有字段必须是 public static final(常量)。
- 方法默认是抽象的:所有方法默认是 public abstract。
- Java 8 开始,接口可以有默认方法和静态方法。
- 应用场景:
- 需要定义多个类的行为,但这些类可能没有继承关系。
- 实现多重继承(一个类可以实现多个接口)。
interface Flyable {
void fly(); // 抽象方法
}
interface Swimable {
void swim();
}
class Duck implements Flyable, Swimable {
@Override
public void fly() {
System.out.println("鸭子可以飞");
}
@Override
public void swim() {
System.out.println("鸭子也会游泳");
}
}
public class Main {
public static void main(String[] args) {
Duck duck = new Duck();
duck.fly();
duck.swim();
}
}
鸭子可以飞
鸭子也会游泳
接口的默认方法和静态方法
interface Printable {
default void print() {
System.out.println("默认的打印方法");
}
static void staticMethod() {
System.out.println("接口的静态方法");
}
}
public class Main {
public static void main(String[] args) {
Printable printable = new Printable() {}; // 匿名类
printable.print();
Printable.staticMethod();
}
}
默认的打印方法
接口的静态方法
3. 内部类
- 特点:
- 内部类是定义在另一个类内部的类,分为以下几种类型:
- 成员内部类:作为外部类的成员,与普通字段类似。
- 静态内部类:类似于静态字段。
- 局部内部类:定义在方法或代码块中的类。
- 匿名内部类:没有名字的类,常用于简化代码。
- 内部类是定义在另一个类内部的类,分为以下几种类型:
- 应用场景:
- 当一个类需要紧密绑定另一个类时,使用内部类可以提高封装性。
// 成员内部类
class OuterClass {
private String message = "外部类的消息";
class InnerClass {
public void display() {
System.out.println("内部类访问:" + message);
}
}
}
public class Main {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
inner.display();
}
}
内部类访问:外部类的消息
// 静态内部类
class OuterClass {
private static String message = "静态成员";
static class InnerStaticClass {
public void displayMessage() {
System.out.println("访问:" + message);
}
}
}
public class Main {
public static void main(String[] args) {
OuterClass.InnerStaticClass inner = new OuterClass.InnerStaticClass();
inner.displayMessage();
}
}
访问:静态成员
// 局部内部类
class OuterClass {
public void showMessage() {
final String localMessage = "局部变量";
class LocalInnerClass {
public void printMessage() {
System.out.println("内部类访问:" + localMessage);
}
}
LocalInnerClass localInner = new LocalInnerClass();
localInner.printMessage();
}
}
public class Main {
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.showMessage();
}
}
内部类访问:局部变量
// 匿名内部类
interface Greeting {
void sayHello();
}
public class Main {
public static void main(String[] args) {
Greeting greeting = new Greeting() {
@Override
public void sayHello() {
System.out.println("Hello, World!");
}
};
greeting.sayHello();
}
}
Hello, World!
4. 匿名类
- 特点:
- 匿名类是没有名字的类。
- 通常用于实现接口或继承抽象类的快速实现。
- 语法简洁,但只适合用于一次性的逻辑。
- 应用场景:
- 简化代码,只需要实现一次逻辑时使用。
interface Greeting {
void sayHello();
}
public class Main {
public static void main(String[] args) {
Greeting greeting = new Greeting() {
@Override
public void sayHello() {
System.out.println("Hello, World!");
}
};
greeting.sayHello();
}
}
Hello, World!
5. 枚举类
- 特点:
- 枚举类是特殊的类,用于定义一组固定的常量。
- 每个枚举值本质上是该枚举类的实例。
- 可以定义构造方法、字段和方法。
- 应用场景:
- 定义一组不可变的常量,例如星期、季节、颜色等。
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
public boolean isWeekend() {
return this == SATURDAY || this == SUNDAY;
}
}
public class Main {
public static void main(String[] args) {
Day today = Day.FRIDAY;
System.out.println("今天是:" + today);
System.out.println("今天是周末吗?" + today.isWeekend());
}
}
今天是:FRIDAY
今天是周末吗?false
带构造方法的枚举
enum Color {
RED("红色"), GREEN("绿色"), BLUE("蓝色");
private String description;
Color(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public class Main {
public static void main(String[] args) {
for (Color color : Color.values()) {
System.out.println(color + " - " + color.getDescription());
}
}
}
RED - 红色
GREEN - 绿色
BLUE - 蓝色
6. 总结
| 特殊类 | 特点 | 应用场景 |
|---|---|---|
| 抽象类 | 不能实例化;可以包含抽象和具体方法 | 定义通用行为,由子类实现细节 |
| 接口 | 方法默认为 public abstract;支持多实现 | 定义多个类的统一行为 |
| 内部类 | 嵌套在外部类中;封装性强 | 逻辑紧密相关的类 |
| 匿名类 | 没有名字;用于快速实现接口或继承类 | 一次性实现简单逻辑 |
| 枚举类 | 定义固定的常量;不可变 | 定义一组常量,例如状态或类型 |