随堂笔记之Java面向对象OOP
此内容源自
B站狂神说Java基础
的课后笔记与总结,用于复习和查看,因此写得比较简陋,不太适合萌新学习
面向对象
Java是面向对象编程(OOP, Object-Oriented Programming)的语言,它的核心思想是一切皆对象,程序是由对象组成的,每个对象都有自己的属性(数据)和行为(方法)
本质:以类的方式组织代码,以对象的方式封装数据
三大核心特性:
- 封装
把对象的属性和行为封装在类里,只暴露必要的方法,防止外部直接修改对象数据。
好处:提高安全性,隐藏内部细节,让代码更好维护。
class Person {
private String name; // 私有变量,外部不能直接访问
public void setName(String name) { // 公开方法,提供访问方式
this.name = name;
}
public String getName() {
return name;
}
}
//这里 name 变量是私有的(private),不能被外部直接修改,而是用 setName() 和 getName() 访问
- 继承
子类可以继承父类的属性和方法,避免重复代码,提高代码复用性。
好处:让代码更简洁,增强代码的扩展性。
// 父类
class Animal {
void eat() {
System.out.println("动物在吃东西");
}
}
// 子类继承 Animal
class Dog extends Animal {
void bark() {
System.out.println("狗在汪汪叫");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat(); // 继承了父类的方法
dog.bark(); // 子类自己的方法
}
}
//这里 Dog 继承 Animal,所以 Dog 也可以用 eat() 方法
- 多态
同一个方法,在不同情况下可以有不同的表现,提高代码灵活性。
好处:可以用 父类的引用 指向 子类对象,让代码更加通用。
class Animal {
void makeSound() {
System.out.println("动物发出声音");
}
}
class Dog extends Animal {
void makeSound() {
System.out.println("狗汪汪叫");
}
}
class Cat extends Animal {
void makeSound() {
System.out.println("猫喵喵叫");
}
}
public class Test {
public static void main(String[] args) {
Animal myAnimal = new Dog(); // 父类引用指向子类对象
myAnimal.makeSound(); // 调用的是 Dog 的方法
}
}
//这里 Animal 是父类,Dog 和 Cat 继承它,但它们重写了 makeSound() 方法,让不同的动物发出不同的叫声
方法调用
对象名.方法名(参数); // 调用实例方法
类名.方法名(参数); // 调用静态方法
方法调用分为两种情况:
- 调用静态方法(不需要创建对象)
静态方法(static 方法) 属于类本身,可以直接调用,不需要创建对象
class MathUtils {
// 静态方法
static int add(int a, int b) {
return a + b;
}
}
public class Test {
public static void main(String[] args) {
int result = MathUtils.add(5, 3); // 直接用类名调用
System.out.println("结果: " + result);
}
}
//不能使用 this 关键字(因为 this 代表对象,而静态方法属于类)
- 调用实例方法(需要创建对象)
实例方法属于对象,必须先创建对象才能调用
class Person {
// 实例方法
void sayHello() {
System.out.println("你好,我是一个人!");
}
}
public class Test {
public static void main(String[] args) {
Person p = new Person(); // 先创建对象
p.sayHello(); // 用对象调用方法
}
}
值传递和引用传递
在Java中,方法参数的传递方式可以分为值传递(Pass by Value)和引用传递(Pass by Reference)。但Java只有值传递,没有真正的引用传递
- 值传递
值传递指的是方法调用时,参数的“值”会被复制一份传递给方法,方法内部的修改不会影响原始变量
class Test {
static void changeValue(int num) {
num = 10; // 修改的是 num 的副本
}
public static void main(String[] args) {
int a = 5;
changeValue(a);
System.out.println(a); // 输出:5(a 没有被修改)
}
}
- 引用传递
引用传递一般指方法接收到的是对象的引用(地址),方法内部的修改会影响原始对象。
Java本质上仍是值传递,只是当对象作为参数时,传递的是对象引用的值(地址),而不是对象本身
class Person {
String name;
}
class Test {
static void changePerson(Person p) {
p.name = "李四"; // 修改对象的属性
}
public static void main(String[] args) {
Person person = new Person();
person.name = "张三";
changePerson(person);
System.out.println(person.name); // 输出:李四
}
}
构造方法
使用快捷键alt+insert插入
Java 中的一种特殊方法,它的作用是在创建对象时初始化对象,赋予对象初始值
构造方法的名字必须与类名相同,并且没有返回值(连void也不能写)
特点:
- 与类名相同,否则编译报错。
- 没有返回值,不能写void,否则它就变成了普通方法。
- 在创建对象时自动调用,不能手动调用,如s.Student()。
- 可以有参数,也可以没有参数,支持方法重载。
- 如果不写构造方法,Java会提供默认无参构造方法
构造方法的分类:
- 无参构造:如果一个类没有手动定义构造方法,Java会自动提供一个无参构造方法
- 有参构造:用于在创建对象时直接给成员变量赋值
- 构造方法重载:方法重载允许一个类有多个构造方法,只要参数不同
this关键字在构造方法中的作用:
- this.成员变量 解决参数名冲突
class Person {
String name;
public Person(String name) {
this.name = name; // 使用 this 区分成员变量和参数
}
}
- this()调用另一个构造方法
class Person {
String name;
int age;
// 调用其他构造方法
public Person() {
this("默认名", 18); // 调用带参数的构造
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
构造代码块:
构造代码块是{}包裹的代码块,每次创建对象都会执行,比构造方法更早执行。
class Person {
// 构造代码块
{
System.out.println("构造代码块执行!");
}
public Person() {
System.out.println("构造方法执行!");
}
}
public class Main {
public static void main(String[] args) {
new Person();
new Person();
}
}
构造代码块执行!
构造方法执行!
构造代码块执行!
构造方法执行!
注意:如果手动定义了有参构造方法,Java不会再自动提供默认的无参构造方法,因此如果需要无参构造,必须手动写出来。(无参构造显式化)
class Person {
String name;
// 只有有参构造
public Person(String name) {
this.name = name;
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person("张三"); // ✅ 正常
Person p2 = new Person(); // ❌ 报错:找不到无参构造方法
}
}
内存分析

封装
(一般来说类中的属性会更多用到封装思想,而方法不怎么涉及封装思想)
核心思想是隐藏对象的内部细节,仅暴露必要的接口,从而提高安全性和代码可维护性
一句话:属性私有,get/set(将属性私有化,通过get/set函数访问)
好处/作用:
- 保护数据安全:防止外部直接访问对象的内部数据,避免误操作。
- 隐藏实现细节:外部不需要关心类的内部实现,只需通过提供的方法进行交互。
- 提高代码的可维护性:封装后,内部实现可以修改,而不会影响外部调用者。
- 控制访问权限:可以通过 private、public、protected 控制类成员的访问权限
封装思想展示:
class Student {
// 1. 将属性私有化,禁止外部直接访问
private String name;
private int age;
// 2. 提供 `getter` 和 `setter` 方法,控制访问
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("年龄不能为负数!");
}
}
// 3. 提供对外公开的方法
public void showInfo() {
System.out.println("学生姓名:" + name + ",年龄:" + age);
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student();
s.setName("张三");
s.setAge(20);
s.showInfo();
s.setAge(-5); // 触发数据保护
}
}
*访问修饰符与封装:

封装的核心做法:
- 用private修饰属性,禁止外部直接访问。
- 用public修饰getter和setter方法,提供受控的访问方式。
- 用访问修饰符(private、protected、public)控制访问权限
继承
使用ctrl+H查看继承结构
继承是允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码复用和扩展
本质:对一批类的抽象
语法:
在Java中,使用extends关键字来表示继承:
// 定义父类(超类 / 基类)
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 = "小狗"; // 继承了 name 变量
dog.eat(); // 继承了 eat() 方法
dog.bark(); // 调用子类自己的方法
}
}
继承的特点:
- 子类继承父类的public和protected成员,但不能直接访问private成员和默认不写的(参考封装的程度图片)。
- Java只支持单继承(一个类只能继承一个父类)。
- 子类可以扩展父类的方法,也可以重写父类的方法。
- 构造方法不会被继承,但子类会调用父类的构造方法
Object类
Object类是Java中所有类的祖先(超类),也就是说,所有的Java类都直接或间接继承自Object类。它位于java.lang包中,默认不需要导入
一些常用方法(待补充完善):
*super关键字
在Java中,super关键字主要用于子类访问父类的内容,它有以下几种常见的用途
- 调用父类的构造方法(super())
- 在子类的构造方法中,默认会先调用父类的无参构造方法,如果父类没有无参构造,就必须手动调用super(参数)。
- super(参数) 语句必须写在子类构造方法的第一行
class Parent {
Parent() {
System.out.println("父类无参构造方法");
}
Parent(String msg) {
System.out.println("父类有参构造方法:" + msg);
}
}
class Child extends Parent {
Child() {
super("Hello from Child"); // 调用父类有参构造
System.out.println("子类构造方法");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
}
}
//output
父类有参构造方法:Hello from Child
子类构造方法
//如果去掉 super("Hello from Child"),就会默认调用 Parent()
- 调用父类的成员变量(super.变量名)
当子类和父类有相同的成员变量时,super.变量名 可以访问父类的变量,避免和子类的变量混淆
class Parent {
int num = 10;
}
class Child extends Parent {
int num = 20;
void show() {
System.out.println("子类 num:" + num); // 访问子类变量
System.out.println("父类 num:" + super.num); // 访问父类变量
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.show();
}
}
//output
子类 num:20
父类 num:10
- 调用父类的方法(super.方法名())
当子类重写了父类的方法,但仍然想调用父类的版本时,可以用super.方法名()
class Parent {
void show() {
System.out.println("父类的方法");
}
}
class Child extends Parent {
@Override
void show() {
super.show(); // 先调用父类的方法
System.out.println("子类的方法");
}
}
public class Main {
public static void main(String[] args) {
Child c = new Child();
c.show();
}
}
//output
父类的方法
子类的方法
注意事项:
- super() 必须是子类构造方法的第一行,否则会报错。
- 不能在静态方法中使用super,因为super依赖对象,而静态方法属于类本身。
- super不能访问子类的成员,只能用于父类的内容
- super必须只能出现在子类的方法或构造方法中
- super和this不能同时调用构造方法,会报错。因为都必须在第一行
多态
在Java里,多态就是指 “同一个方法,在不同对象上可以有不同的实现”
多态是方法的多态,属性没有多态
方法重写
快捷键:alt+insert
方法重写(Override)是指子类对父类继承而来的方法进行重新定义,以提供新的实现方式
(都是方法的重写,和属性无关,属性不涉及重写)
方法重写规则:
- 方法名相同,参数列表相同
- 返回值类型
JDK 1.5 之前:必须与父类方法完全一致
JDK 1.5 及以后:返回类型可以是父类方法返回类型的子类 - 访问权限不能比父类更严格(可以放宽,但不能缩小)
public → 必须是 public
protected → protected 或 public
默认(default) → default、protected 或 public
private 不能被重写 - static 方法不能被重写,但可以被子类重新定义(隐藏)(重写之和非静态方法有关)
- final 方法不能被重写
- 必须是继承关系(即方法必须是从父类继承来的)
- 子类方法不能抛出比父类更多或更大的异常
注意事项:
如果方法是static方法、私有方法(private)、或者是final方法(final),那么它的调用只取决于左侧引用类型,而不会受到右侧实例类型的影响
//静态方法、私有方法、final 方法 → 编译时绑定,只看左边类型(引用类型)
class Parent {
static void staticMethod() {
System.out.println("父类 static 方法");
}
}
class Child extends Parent {
static void staticMethod() {
System.out.println("子类 static 方法");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child();
p.staticMethod(); // 输出:父类 static 方法
}
}
//实例方法 → 运行时绑定,看右边实例的真实类型(多态)
class Parent {
void show() {
System.out.println("父类实例方法");
}
}
class Child extends Parent {
@Override
void show() {
System.out.println("子类实例方法");
}
}
public class Main {
public static void main(String[] args) {
Parent p = new Child(); // 父类引用指向子类对象
p.show(); // 输出:子类实例方法
}
}
@Override:
@Override是Java 中的一个注解,用于标识子类正在重写父类的某个方法。它是可选的,但建议使用,主要用于编译时检查,防止拼写错误或方法签名不匹配的问题
instanceof
instanceof是Java中的一个关键字,用于判断对象是否是某个类的实例,或者是否是其子类的实例
//基本语法
对象 instanceof 类名
class Animal {}
class Dog extends Animal {}
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
Dog dog = new Dog();
Animal animalDog = new Dog(); // 向上转型
System.out.println(animal instanceof Animal); // true
System.out.println(dog instanceof Dog); // true
System.out.println(dog instanceof Animal); // true (子类对象也是父类的实例)
System.out.println(animalDog instanceof Dog); // true (多态对象仍然是 Dog)
System.out.println(animal instanceof Dog); // false (父类对象不是子类的实例)
}
}
注意事项:
在进行向下转型(把父类引用转换为子类类型)时,必须使用 instanceof进行检查,以防止运行时ClassCastException异常
向下转型:
class Animal {
public void makeSound() {
System.out.println("动物在叫...");
}
}
class Dog extends Animal {
public void bark() {
System.out.println("狗在汪汪叫!");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型,多态
animal.makeSound(); // 只能调用父类的方法(输出
//animal 是 Animal 类型的引用,虽然它指向的是 Dog 类型的对象,但它只能访问 Animal 类中定义的方法,不能直接调用 Dog 类中特有的方法
//因此需要向下转型:
if (animal instanceof Dog) {
Dog dog = (Dog) animal; // 向下转型
dog.bark(); // 现在可以调用 Dog 类的 bark() 方法了
}
子类转化为父类可能丢失一些自己的方法(同上一个例子):
当你将一个子类对象赋给一个父类的引用时(即向上转型),父类的引用只能访问父类中定义的方法,而不能直接访问子类中特有的方法或属性
class Animal {
public void makeSound() {
System.out.println("动物叫...");
}
}
class Dog extends Animal {
public void bark() {
System.out.println("狗汪汪叫!");
}
}
public class Main {
public static void main(String[] args) {
// 创建 Dog 对象
Dog dog = new Dog();
// 使用 Dog 对象调用 Dog 和 Animal 的方法
dog.makeSound(); // 输出:动物叫...
dog.bark(); // 输出:狗汪汪叫!
// 向上转型
Animal animal = dog; // 父类引用指向子类对象
animal.makeSound(); // 输出:动物叫...
// 下面这一行编译时会报错,因为 animal 引用类型是 Animal,无法访问 Dog 中的 bark 方法
// animal.bark(); // 编译错误:无法从 Animal 类型访问 bark 方法
}
}
static关键字
- static 修饰变量(静态变量)
特点:静态变量属于类,而不是某个实例,每个对象共享同一个静态变量
class Counter {
static int count = 0; // 静态变量(类变量)
public Counter() {
count++; // 每次创建对象时增加 count
}
public void showCount() {
System.out.println("当前 count 值:" + count);
}
}
public class Main {
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
Counter c3 = new Counter();
c1.showCount(); // 输出:当前 count 值:3
c2.showCount(); // 输出:当前 count 值:3
c3.showCount(); // 输出:当前 count 值:3
}
}
- static 修饰方法(静态方法)
特点:静态方法属于类,不依赖于对象,可以通过类名直接调用
静态方法的限制:- 不能访问非静态变量(实例变量),因为静态方法属于类,而实例变量属于对象。
- 不能调用非静态方法,除非先创建对象
class Test {
int x = 10;
public static void staticMethod() {
// System.out.println(x); // ❌ 报错:无法访问实例变量 x
}
}
- static 修饰代码块(静态代码块)
特点:- 静态代码块在类加载时执行,且只执行一次。
- 通常用于初始化静态变量或执行一些只需运行一次的操作(如数据库连接)
class Test {
static int a;
// 静态代码块
static {
System.out.println("静态代码块执行!");
a = 100; // 初始化静态变量
}
public static void show() {
System.out.println("a = " + a);
}
}
public class Main {
public static void main(String[] args) {
Test.show();
Test.show();
}
}
//output
静态代码块执行!
a = 100
a = 100
补充:匿名代码块
匿名代码块(也称实例代码块)是 Java 类中没有 static 关键字,且没有方法名的代码块。
它在每次创建对象时都会执行一次,用于初始化实例变量或执行某些操作
class Example {
// 匿名代码块(实例代码块)
{
System.out.println("匿名代码块执行!");
}
public Example() {
System.out.println("构造方法执行!");
}
}
public class Main {
public static void main(String[] args) {
Example e1 = new Example();
Example e2 = new Example();
}
}
//output
匿名代码块执行!
构造方法执行!
匿名代码块执行!
构造方法执行!
//匿名代码块每次创建对象时都会执行,而构造方法只针对某个构造器执行

- static 修饰内部类(静态内部类)
特点:- 静态内部类不依赖外部类的实例,可以直接创建对象。
- 只能访问外部类的静态变量和静态方法。
class Outer {
static String msg = "Hello";
// 静态内部类
static class Inner {
void show() {
System.out.println("外部类的 msg: " + msg);
}
}
}
public class Main {
public static void main(String[] args) {
Outer.Inner obj = new Outer.Inner(); // 直接创建静态内部类对象
obj.show(); // 输出:外部类的 msg: Hello
}
}
- static 在继承中的作用
static 方法不能被重写(override),但可以被隐藏(hide)
子类可以定义与父类相同的静态方法,但它们是两个独立的方法
抽象类
在 Java 中,抽象类是不能直接实例化的类,它通常用于作为其他类的父类,提供一些通用的行为,并且可以包含抽象方法(即没有方法体的方法)
关键点:
- 抽象类用 abstract 关键字声明。
- 抽象类不能被直接实例化(被new),只能靠子类去实现它,但可以被子类继承。
- 抽象类可以包含普通方法和抽象方法(抽象方法没有方法体)。
- 子类必须重写抽象方法,或者自身也是抽象类。
- 抽象方法(规范)只能写在抽象类中。
// 定义抽象类
abstract class Animal {
// 抽象方法(没有方法体,子类必须实现)
public abstract void makeSound();
// 普通方法(子类可以直接使用)
public void eat() {
System.out.println("动物在吃东西...");
}
}
// 具体子类继承抽象类
class Dog extends Animal {
// 必须重写抽象方法
@Override
public void makeSound() {
System.out.println("狗在汪汪叫!");
}
}
public class Main {
public static void main(String[] args) {
// Animal a = new Animal(); // ❌ 错误,抽象类不能实例化
Dog d = new Dog(); // ✅ 具体子类可以实例化
d.makeSound(); // 调用重写的方法
d.eat(); // 继承父类的普通方法
}
}
//output
狗在汪汪叫!
动物在吃东西...
抽象类的作用:
- 代码复用:抽象类可以提供公共的代码,减少代码重复。
- 规范约束:规定子类必须实现某些方法,保证子类的行为一致。
- 增强可维护性:提高代码的可扩展性和可读性。
//多个子类继承抽象类
abstract class Animal {
public abstract void makeSound(); // 规范:子类必须实现这个方法
}
// 具体子类1
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("狗在汪汪叫!");
}
}
// 具体子类2
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("猫在喵喵叫!");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.makeSound(); // 狗在汪汪叫!
Animal cat = new Cat();
cat.makeSound(); // 猫在喵喵叫!
}
}
//Dog 和 Cat 继承 Animal,必须实现 makeSound() 方法。
//使用抽象类可以保证所有子类都有 makeSound() 方法。
抽象的抽象:
"抽象的抽象" 通常指的是抽象类的进一步抽象,即一个抽象类继承另一个抽象类,而且可以不完全实现父类的抽象方法,而是继续将部分方法保持为抽象状态,交由更具体的子类去实现。
注意:
- 抽象类虽然不能被直接实例化,但是也拥有构造器,它的构造器可以被子类调用,用于初始化父类的成员变量或执行必要的操作。
- 如果一个类有抽象方法则必是抽象类,但是抽象类不一定有抽象方法。
约束和实现
抽象类和接口中的两个重要概念
什么是约束?
约束指的是 对类行为的规定,也就是定义“应该有哪些方法”,但不关心“如何实现”。
- 约束通常由接口(interface)或抽象类(abstract class)提供,它们定义了方法的名称、参数和返回类型,但不提供具体的实现。
- 约束的作用:确保不同的类可以遵循相同的规则,使得代码更加规范和可扩展。
//接口(纯约束)
interface Animal {
void makeSound(); // 约束:所有动物必须实现这个方法
}
//抽象类(约束和实现都有)
abstract class Animal {
abstract void makeSound(); // 约束:子类必须实现
void eat() { // 具体实现
System.out.println("吃东西...");
}
}
什么是实现?
实现指的是如何完成某个功能,也就是具体代码的编写
//子类接口的实现
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("狗在汪汪叫!");
}
}
//子类继承抽象类
class Cat extends Animal {
@Override
void makeSound() {
System.out.println("猫在喵喵叫!");
}
}
接口
接口是Java中用于定义行为规范的机制,它规定了一组方法,但不提供具体实现。实现接口的类必须提供接口中定义的所有方法,从而保证一定的行为一致性
interface Animal {
void makeSound(); // 接口中的方法默认是 public abstract
//接口中变量默认为public static final(但一般不在接口里定义变量)
}
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("狗在汪汪叫!");
}
}
public class Main {
public static void main(String[] args) {
//接口不能被实例化,接口中没有构造方法
Animal myDog = new Dog();
myDog.makeSound(); // 输出:狗在汪汪叫!
}
}
接口里所有方法都是public abstract的,因为:
- 接口方法默认 public,是为了保证所有实现类都能访问到这些方法。
- 接口方法默认 abstract,是因为它不需要具体实现,交给子类实现。
接口的特点:
- 接口中的方法默认是 public abstract(即使不写)。
- 接口中的变量默认是 public static final(即常量)。
- 类使用 implements 关键字实现接口,并必须实现接口的所有方法。
- 一个类可以实现多个接口,从而实现多重继承的效果(伪多继承)。
- Java 8 之后,接口可以包含 default 方法(有实现)和 static 方法(有实现)。
- 接口不能创建对象,但可以作为引用类型使用。

Java8后接口的增强:
interface Animal {
void makeSound(); // 仍然是 public abstract
default void sleep() { // default 方法可以有实现
System.out.println("动物在睡觉...");
}
static void info() { // static 方法也可以有实现
System.out.println("这是一个动物接口");
}
}
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("狗在汪汪叫!");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
dog.makeSound(); // 狗在汪汪叫!
dog.sleep(); // 动物在睡觉...
Animal.info(); // 这是一个动物接口
}
}
约束和实现分离:
- 用抽象类或接口定义“应该做什么”(约束)。
- 在具体的子类中定义“怎么做”(实现)
可以抽空去看R3设计模式
内部类
一个java文件中可以有多个class,但是只能有一个public class
内部类是在一个类的内部定义的类,它可以访问外部类的成员,包括 private修饰的成员。内部类可以帮助封装逻辑、增强可读性,并用于特殊的场景,如回调和事件监听。
分类:
- 成员内部类(非静态内部类)
在类的成员位置定义的非static类,类似实例变量,需要外部类的实例才能创建对象
class Outer {
private String message = "Hello from Outer";
class Inner {
void showMessage() {
System.out.println(message); // 访问外部类的 private 成员
}
}
}
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // 先创建外部类对象,再创建内部类对象
inner.showMessage(); // 输出:Hello from Outer
}
}
//内部类可以直接访问外部类的私有成员
//需要通过外部类的实例来创建内部类对象,语法
外部类.内部类 变量 = 外部类实例.new 内部类();
- 静态内部类
使用static修饰的内部类,可以独立于外部类创建对象,只能访问外部类的静态成员(因为加了static就是随着类加载而加载的,但是实例变量是创建对象的时候才加载的,因此不能提前访问)
class Outer {
private static String message = "Hello from Outer";
static class StaticInner {
void showMessage() {
System.out.println(message); // 访问外部类的静态成员
}
}
}
public class Main {
public static void main(String[] args) {
Outer.StaticInner inner = new Outer.StaticInner(); // 直接创建,不需要外部类实例
inner.showMessage(); // 输出:Hello from Outer
}
}
//不依赖外部类实例,可以直接创建
//外部类.内部类 变量 = new 外部类.内部类();
//只能访问外部类的静态成员,不能访问非静态成员
- 局部内部类
定义在方法或代码块内部的类,作用范围仅限于该方法或代码块
class Outer {
void display() {
class LocalInner {
void show() {
System.out.println("局部内部类");
}
}
LocalInner inner = new LocalInner();
inner.show(); // 输出:局部内部类
}
}
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
outer.display();
}
}
//只能在定义它的方法内使用。
//不能使用 public, private, protected 修饰。
//可以访问方法中的局部变量,但该变量必须是 final(JDK 8 之后可以省略 final)
- 匿名内部类
没有名字的内部类,通常用于简化代码,一般在需要实现接口或继承类的地方使用
//匿名内部类实现接口
interface Animal {
void makeSound();
}
public class Main {
public static void main(String[] args) {
Animal dog = new Animal() { // 匿名内部类
@Override
public void makeSound() {
System.out.println("狗在汪汪叫!");
}
};
dog.makeSound(); // 输出:狗在汪汪叫!
}
}
//实现继承
class Person {
void speak() {
System.out.println("说话...");
}
}
public class Main {
public static void main(String[] args) {
Person p = new Person() { // 继承 Person
@Override
void speak() {
System.out.println("匿名内部类重写方法");
}
};
p.speak(); // 输出:匿名内部类重写方法
}
}
//没有类名,使用 new 类名/接口() { 重写方法 } 的方式创建。
//不能有构造方法,但可以初始化代码块。
//只创建一次,不能重复使用。
//常用于简化代码,如事件监听、回调等场景
总结:

浙公网安备 33010602011771号