我在B站上大学😃
学习至:狂神说Java
1. 什么是面向对象
1.1 面向过程与面向对象
-
面向过程思想
- 步骤简单清晰,第一步做啥,第二步做啥......
- 面向过程适合处理一些较为简单的问题
-
面向对象思想
- 物以类聚。分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路取处理。
1.2 什么是面向对象
-
面向对象编程(Object-Oriented Programming, OOP)
-
面向对象的本质:以类的方式组织代码,以对象的方式组织(封装)数据
-
三大特性:
-
封装
-
继承
-
多态
-
-
从认识论的角度来看,是先有对象后有类。对象,是具体的事物。类,是抽象的,是对事物的抽象。
-
从代码运行的角度来看,是先有类后有对象。类是对象的模板。
注意:程序员从来不缺对象,因为new一个就好了(手动狗头)
1.3 回顾
1.方法的定义
-
修饰符
-
返回类型
-
break: 结束循环
-
return:结束方法
-
-
方法名:注意规范,见名知意
-
参数列表:(参数类型,参数名)eg:(int x), (int x, double b), (int...x)
-
异常抛出:
eg:
import java.io.IOException;
//Demo01类
public class Demo01 {
//main方法
public static void main(String[] args) {
}
public String sayHello(){
return "hello, world";
}
public int max(int a,int b){
return a > b ? a : b;//三元运算符
}
//数组下标越界异常:Arrayindexoutofbounds
public void readFile(String file) throws IOException{
//读取文件 //抛出 //异常
}
}
2.方法的跨类调用
静态方法(含修饰符static):类名.方法名();
public class Student {
//静态方法
public static void say() {
System.out.println("Hello World!");
}
}
public class Demo02 {
public static void main(String[] args) {
Student.say();
}
}
Hello World!
进程已结束,退出代码0
非静态方法:实例化后调用
public class Student {
//非静态方法
public void say() {
System.out.println("Hello World!");
}
}
public class Demo02 {
public static void main(String[] args) {
//实例化方法所在类(创建对象)
Student student = new Student();
//调用实例方法
student.say();
/*
这样也可以
new Student().say();
*/
}
}
Hello World!
进程已结束,退出代码0
3.方法在类的内部调用
public class Demo02 {
public static void main(String[] args) {
Student student = new Student();
student.say();
// new Student().say();
}
public void a(){
b();//一个类的内部的普通方法(非静态)可以互相调用
}
public void b(){}
}
public class Demo02 {
public static void main(String[] args) {
Student student = new Student();
student.say();
// new Student().say();
}
public static void a(){
b();//一个类的内部的静态方法可以互相调用
}
public static void b(){}
}
public class Demo02 {
public static void main(String[] args) {
Student student = new Student();
student.say();
// new Student().say();
}
public static void a(){
b();//此处会报错,类的内部静态方法不能调用非静态方法
}
public void b(){
a();//一个类的内部非静态方法可以调用静态方法
}
}
public class Demo03 {
public static void main(String[] args) {
add(2,3);//主函数调用同类下定义的静态方法的两种方式
Demo03.add(3,5);
}
public static int add(int a, int b){
return a + b;
}
}
public class Demo03 {
public static void main(String[] args) {
new Demo03().add(3,5);//主函数调用同类下定义的非静态方法前需要先创建对象
}
public int add(int a, int b){
return a + b;
}
}
注:内部的静态方法不能直接调用非静态方法,因为static和类一起加载,有类就可用,非静态方法是在实例化后才存在。
4.值传递与引用传递
public class Demo04 {
public static void main(String[] args) {
int a = 1;
System.out.println(a);//输出 1
change(a);//方法执行后,未改变主函数内a 的值
System.out.println(a);//输出 1
}
//返回值为空
public static void change(int a) {
a = 10;
}
}
//引用传递: 对象, 本质还是值传递
public class Demo05 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);//null
change(person);
System.out.println(person.name);//小红
}
public static void change(Person person) {
person.name = "小红";
}
}
//定义了一个Person类,有一个属性: name
//相当于自定义了一个数据类型
class Person{
String name;//默认为null
}
2. 对象与类
2.1 对象与类的关系
-
类是一种抽象的数据类型,它是对某一类事物整体的描述/定义,但不能代表某一具体的事物
-
对象是抽象概念的具体实例
-
张三就是人的一个具体实例;他家的狗狗旺财是狗的一个具体实例
-
能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念
-
2.2 创建和初始化对象
- 使用
new
关键字创建对象
使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化,以及对类中构造器的调用
//一个项目应该只有一个main方法
public class Application {
public static void main(String[] args) {
//类:抽象的,要实例化
//类实例化后会返回一个自己的对象
Student xiaoming = new Student();
Student xiaohong = new Student();
xiaohong.name = "小红";
xiaohong.age = 13;
System.out.println(xiaohong.name);//小红
System.out.println(xiaohong.age);//13
System.out.println(xiaoming.name);//null
System.out.println(xiaoming.age);//0
}
}
public class Student {
//属性:字段
String name;
int age;
//方法
public void study(){
System.out.println(this.name+"在学习");
}
}
- 类中的构造器也称为构造方法,是在进行创建对象时必须要调用的。并且构造器有以下两个特点:
-
必须和类的名字相同
-
必须没有返回类型,也不能写
void
-
public class Person {
}
public class Application {
public static void main(String[] args) {
Person person = new Person();//Person类是空的,但仍然可以new一个对象出来,说明空的类中有一个默认的方法,即构造器
}
}
运行后反编译生成的class文件可发现,Person类下有个默认的方法,即:
public class Person {
public Person(){//构造方法,可以自己写,没有的话会自动生成
}
}
构造器可以用来实例化初始值
public class Person {
String name;
//使用new关键字,本质是在调用构造器
public Person(){
//实例化初始值
this.name="xiaohong";
}
}
public class Application {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);//xiaohong
}
}
注:有参构造(相当于方法的重载),一旦定义了有参构造,无参就必须显式定义,除非你不用,实例化对象时可根据参数自动匹配构造器。
IDEA快捷键:alt + insert
自动生成构造器
2.3 创建对象内存分析
在Java中,创建对象时会涉及到内存的分配和管理。下面是Java创建对象时的内存分析的过程:
- 堆内存分配:对象在Java中存储在堆(Heap)内存区域中。当使用关键字 new 创建对象时,JVM会在堆内存中为对象分配内存空间。内存的大小取决于对象的类型和实例变量。
- 对象的实例变量:创建对象时,会根据类的定义在内存中分配实例变量的存储空间。每个对象都有自己的实例变量的副本。
- 构造函数的执行:在创建对象后,会调用对象的构造函数来初始化对象。构造函数是一个特殊的方法,用于对对象进行初始化操作。它可以在对象创建时设置对象的成员变量的初始值。
- 引用变量:在创建对象时,通常会使用引用变量来引用这个对象。引用变量存储在栈(Stack)内存中,它们指向实际存储在堆内存中的对象。
- 垃圾回收:当对象不再被引用时,Java的垃圾回收机制会自动回收这些对象所占用的内存空间。垃圾回收器会定期扫描堆内存,对不再被引用的对象进行清理,并释放它们所占据的内存空间。
需要注意以下几点:
-
堆内存是所有线程共享的,用于存储对象实例。
-
栈内存是线程私有的,在方法调用过程中会使用栈来保存方法的局部变量、方法参数和返回地址。
-
引用变量存储在栈内存中,指向堆内存中的对象。
-
对象的大小取决于其实例变量和对齐要求。
-
Java提供了自动内存管理,开发人员不需要手动释放对象所占用的内存空间。垃圾回收器会自动回收不再使用的对象。
内存分配和管理是Java的一项关键功能,它确保对象的动态创建和销毁,并有效地管理系统的内存资源。
3. 封装
程序设计要追求 “ 高内聚,低耦合 ”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
封装(Encapsulation)用于隐藏对象的内部实现细节,并通过公共接口提供对对象的访问和操作。
在封装中,一个对象的数据和方法被组合在一起,并通过访问修饰符(如public、private、protected
等)进行限制访问。这样可以确保对象的内部状态只能通过定义的公共接口进行访问,而不允许外部直接访问或修改对象的数据。
封装的主要目的是增强代码的可维护性和可复用性,它提供了以下几个主要好处:
-
数据隐藏: 封装将对象的内部数据隐藏起来,只暴露必要的接口给外部使用。这样可以防止外部代码直接修改对象的数据,从而保护数据的完整性和一致性。
-
实现信息隐藏:通过封装,可以隐藏对象的具体实现细节。这样,外部代码只需要知道如何使用对象的接口,而不需要关心对象是如何实现的。这提供了更好的抽象和模块化,减少了代码的耦合性,使得代码更易于理解和修改。
-
接口统一性:通过封装,可以定义一致的公共接口来访问对象。这样,不同的实现类可以提供相同的接口,使得外部代码可以以统一的方式操作不同的实现类对象,提高了代码的可扩展性和灵活性。
-
访问控制:通过使用访问修饰符,封装可以对对象的访问进行控制。私有(
private
)修饰符可以限制对象的访问范围,只允许在对象的内部进行访问和修改。公共(public
)修饰符可以提供对外界的开放访问接口。
封装是面向对象编程的重要特性之一,它有助于提高代码的可维护性、安全性和重用性。通过将对象的数据和方法封装在一起,并通过定义的接口进行访问,可以有效地管理和保护对象的内部状态 。
public class Student {
//属性私有
private String name;//姓名
private int id;//学号
private char sex;//性别
//提供可以操作这些属性的方法
//get 获得这个数据
public String getName() {
return name;
}
//给这个数据赋值
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
}
//一个项目应该只有一个main方法
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setId(2023111111);
s1.setSex('女');
s1.setName("小红");
System.out.println(s1.getName());
System.out.println(s1.getSex());
System.out.println(s1.getId());
}
}
小红
女
2023111111
进程已结束,退出代码0
注:Java中可以通过Alt+Insert
快捷键快速生成set/get方法;
可以在set函数中设置安全性检查
public void setSex(char sex) {
if (sex == '男' || sex == '女'){
this.sex = sex;
}
}
4. 继承
继承的主要目的是实现代码的重用和扩展。通过继承,子类可以继承父类的属性和方法,而无需重新编写相同的代码。子类可以使用继承的属性和方法,还可以在其自身中添加新的属性和方法,或者修改继承的属性和方法,以满足自己的需求。
继承具有以下几个关键概念:
- 父类和子类:父类是被继承的类,子类是继承父类的类。父类通常具有通用的属性和方法,而子类可以继承这些属性和方法并添加自己的特定内容。
- 继承关系:子类通过
extends
关键字指定其继承的父类。这建立了一个继承关系,使子类能够访问父类中的非私有(protected
、public
及默认属性default
)属性和方法。 - 重写(Override):子类可以重写父类中的方法,以便根据自身的需求提供新的实现。子类重写父类方法时,方法名、参数列表和返回类型必须与父类中的方法一致。
- 访问修饰符:继承也受到访问修饰符的影响。如果父类中的属性或方法被声明为private,则子类无法直接访问它们。受保护修饰符允许子类访问父类的属性和方法,并且public修饰符允许所有类都可以访问。
继承使得代码更具有结构性和可扩展性。它促进了代码的复用,减少了重复编写代码的工作量,并使代码更易于维护。此外,继承还提供了多态性(Polymorphism)的基础,允许以统一的方式处理不同的子类对象。然而,应该谨慎使用继承,以避免过度复杂化的继承层次结构。
class Parent {
int age; // 默认属性
public void display() {
System.out.println("Age: " + age);
}
}
class Child extends Parent {
// 子类继承了父类的默认属性 age
public void setAge(int age) {
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.setAge(10);
child.display(); // 输出: Age: 10
}
}
注:
Java中所有类默认继承Object类;
Java中类只有单继承,没有多继承;
IDEA快捷键:Ctrl + H
,查看父类子类
4.1 super 关键字
super
关键字用于引用父类的成员,包括实例变量、方法和构造函数。它可以在子类中使用,用于调用父类的成员或访问父类的构造函数。
-
调用父类的构造函数:在子类的构造函数中,通过 方法可以调用父类的构造函数。这通常用于初始化从父类继承的实例变量或执行父类的一些初始化逻辑。
super()
public class Child extends Parent { public Child() { super(); // 调用父类的无参构造函数,默认添加,显式定义必须放在子类构造器的第一个 } }
-
调用父类的方法:在子类中,可以使用 关键字来调用父类中被重写的方法。这在需要在子类中扩展父类方法的功能时非常有用。
super
.public class Child extends Parent { @Override public void someMethod() { super.someMethod(); // 调用父类的 someMethod() 方法 // 执行其他子类的逻辑 } }
-
引用父类的实例变量:子类可以使用 关键字来引用父类的实例变量。这在子类需要访问隐藏或覆盖的父类成员时很有用。
super
.public class Child extends Parent { public void displayParentVariable() { System.out.println(super.age); // 访问父类的实例变量 age } }
注:
super:
1.调用父类方法,必须放在构造器第一个;
2.只能出现在子类的方法或构造方法中;
3.super
和this
不能同时调用构造方法。
super与this不同点:
-
代表对象不同:
- this:本身调用者这个对象
- super:代表父类对象的应用
-
前提不同:
- this没有继承类也可以使用
- super只能在继承条件下使用
-
构造方法不同:
- this():本类的构造
- super():父类的构造
4.2 方法的重写
方法的重写(Method Overrideing)是指子类重新定义了从父类继承的方法,以便根据子类的特定需求提供新的实现。方法重写是实现多态性的一种方式,它允许在父类引用中调用子类对象的方法。
方法重写遵循以下规则:
-
子类方法的名称、参数列表和返回类型必须与父类方法完全相同。这被称为方法签名。
-
子类方法不能缩小或丢失父类方法的访问级别。也就是说,如果父类方法是 public,则子类方法必须也是 public 或更为宽松的访问级别。
-
子类方法不能抛出比父类方法更多的异常,但可以抛出比父类方法更少的异常,或者不抛出异常。
-
在方法重写中,子类方法使用 注解来表明它是对父类方法的重写。这样有助于编译器检查是否满足了方法重写的条件。
@Override
class Vehicle {
public void start() {
System.out.println("Vehicle starts");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("Car starts");
}
}
public class Main {
public static void main(String[] args) {
Vehicle vehicle = new Car(); // 使用父类引用指向子类对象
vehicle.start(); // Output: Car starts
}
}
注:
方法重写只发生在继承关系中,并且只能从子类对父类的方法进行重写。
5. 多态
多态(Polymorphism)允许使用父类的引用来引用子类的对象,以实现不同对象之间的统一处理。
多态性的实现依赖于以下两个关键概念:继承和方法重写。
- 继承:子类可以继承父类的属性和方法。通过继承,子类可以拥有父类的一些通用行为和特征。
- 方法重写:子类可以重写(override)从父类继承的方法,提供自己的实现。通过方法重写,子类可以改变父类方法的行为。
多态性的实现方式如下:
-
父类引用指向子类对象:通过将父类的引用指向子类的对象,可以实现多态性。这意味着可以使用父类的引用来调用子类的方法。
-
方法重写:当子类重写父类的方法时,可以根据子类的特定需求提供新的实现。当通过父类引用调用方法时,实际上会根据子类对象的类型决定调用的方法。
class Animal {
public void makeSound() {
System.out.println("Animal makes sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal animal1 = new Dog();
Animal animal2 = new Cat();
animal1.makeSound(); // Output: Dog barks
animal2.makeSound(); // Output: Cat meows
}
}
注:以下不能重写
1.static 方法,属于类,不属于实例
2.final 常量
3.private 方法
6. instanceof 和类型转换
6.1 instanceof
在Java中, instanceof
是一个运算符,用于检查一个对象是否是某个类的实例或者是否是其子类的实例。它的语法如下:
object instanceof ClassName
其中, object
是要检查的对象, ClassName
是要检查的类名。
instanceof
运算符的返回结果是一个布尔值,如果该对象是指定类的实例或者其子类的实例,则返回true
,否则返回false
。
class Animal {
}
class Dog extends Animal {
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog();
System.out.println(animal instanceof Dog);//true
System.out.println(animal instanceof Animal);//true
}
}
6.2 类型转换
Java提供了两种类型转换方式:向上转型(Upcasting)和向下转型(Downcasting)。
1.向上转型(Upcasting):
向上转型是指将子类类型转换为父类类型。这种类型转换是隐式的,也就是说,不需要显式地进行转换操作。编译器会自动进行类型转换。这种转型是安全的,因为子类对象具有父类的所有属性和方法。
class Animal { }
class Dog extends Animal { }
Dog dog = new Dog();
Animal animal = dog; // 向上转型
注:子转父,可能丢失自己本来的方法
2.向下转型(Downcasting):
向下转型是指将父类类型转换为子类类型。这种类型转换是显式的,需要使用强制类型转换操作符进行转换。
class Animal { }
class Dog extends Animal { }
Animal animal = new Dog(); // 向上转型
Dog dog = (Dog) animal; // 向下转型
注:向下转型时要确保原始对象的实际类型是目标类型的子类,否则会在运行时抛出 异常。
7. static 关键字
static
是一个关键字,用于声明静态成员。静态成员属于类而不是类的实例,可以在没有创建对象的情况下直接访问。以下是静态成员可以应用于的内容:
1.静态变量(静态字段):
静态变量是与类相关联的变量,而不是与类的实例相关联。它们在类加载时被初始化,并且在整个类的所有实例之间共享。静态变量使用 关键字static
进行声明,可以直接通过类名访问。
class Example {
static int count;
}
Example.count = 10; // 直接访问静态变量
2.静态方法:
静态方法是不依赖于类的实例的方法。它们使用static
关键字进行声明,并可以直接通过类名调用,无需创建类的实例。静态方法不能直接访问实例变量,因为它们不属于任何特定的实例。
class Example {
static void sayHello() {
System.out.println("Hello!");
}
}
Example.sayHello(); // 调用静态方法
3.静态代码块:
静态代码块在类加载时执行,用于初始化静态变量或执行其他静态操作。它们使用 static
关键字声明,并使用花括号{}
包围代码。
class Example {
static {
System.out.println("Static block");
}
}
// 类加载时会输出 "Static block"
注:
- 静态成员可以通过类名直接访问,不需要创建类的实例。
- 静态成员属于整个类,而不是类的实例。如果一个实例修改了静态变量的值,那么这个值对其他实例也是可见的。
- 静态方法只能直接调用其他静态方法或访问其他静态成员(包括静态变量)。它们不能直接调用非静态方法或访问非静态成员,因为这些成员是与类的实例相关联的。
- 静态代码块在类加载时执行,只执行一次。
- 静态成员适用于在整个类中共享的变量或方法。
静态成员在特定情况下非常有用,例如全局常量、工具类方法、单例模式等。然而,它们的使用也应谨慎,因为它们存在一些限制,如无法访问非静态成员和无法由子类覆盖等。
eg:
public class Application {
public Application() {
System.out.println("构造器");
}
{
System.out.println("匿名代码块"); //匿名代码块
}
static {
System.out.println("静态匿名代码块"); //静态匿名代码块
}
public static void main(String[] args) {
new Application();
}
}
/*
输出结果:
静态匿名代码块
匿名代码块
构造器
*/
//通过上面的代码可以看出,虽然构造器是写在最前面的,但是却是最后运行的。
8. 抽象类
抽象类是用 abstract
关键字声明的类。抽象类是一种特殊的类,不能直接实例化,而是作为其他类的基类或者被继承使用。
抽象类的特点和用途如下:
- 抽象类不能被实例化:抽象类不能直接创建对象,只能被用作其他类的基类。这是因为抽象类本身是不完整的,其中可能包含了抽象方法或者实例方法的具体实现。
- 抽象方法:抽象方法必须在抽象类中,抽象类可以包含普通方法和抽象方法,后者是一种没有实现体的方法声明。抽象方法使用
abstract
关键字声明,没有方法体。子类必须实现抽象类中的所有抽象方法,除非子类也是抽象类。 - 子类继承抽象类:其他类可以通过继承抽象类来使用抽象类的特性。继承抽象类的子类必须实现抽象类中的所有抽象方法,除非子类也是抽象类。具体的实现细节由子类来完成。
以下是一个简单的抽象类的示例:
abstract class Animal {
abstract void sound(); // 抽象方法
void sleep() {
System.out.println("Animal is sleeping"); // 实例方法
}
}
class Dog extends Animal {
void sound() {
System.out.println("Dog is barking"); // 实现抽象方法
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.sound(); // 输出: Dog is barking
dog.sleep(); // 输出: Animal is sleeping
}
}
9. 接口
接口(Interface)是一种特殊的引用类型,接口定义了一组抽象方法和常量(默认为静态和常量)的集合,但不提供实现。
接口的特点和用途如下:
- 定义:接口使用
interface
关键字来声明。它可以包含方法签名(没有实现体),默认方法(具有默认实现),静态方法(在接口级别上调用),和常量。 - 抽象方法:接口中的方法都是抽象方法,没有方法体。它们只包含方法声明,而不包含具体的实现。在实现接口的类中,必须提供这些方法的具体实现。
- 多继承:一个类可以实现多个接口。这种多继承的方式允许类使用多个不同接口提供的行为。
- 强制实现:实现接口的类必须提供接口中定义的所有方法的实现。这种强制实现确保了类具备了接口所定义的行为。
以下是一个简单的接口的示例:
interface Animal {
void sound(); // 抽象方法,接口中定义的方法都是抽象的,前边省略了 public abstract
default void sleep() {
System.out.println("Animal is sleeping"); // 默认方法
}
static void breathe() {
System.out.println("Animal is breathing"); // 静态方法
}
int legs = 4; // 常量,前边省略了 public static final
}
class Dog implements Animal {
public void sound() {
System.out.println("Dog is barking"); // 实现抽象方法
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.sound(); // 输出: Dog is barking
dog.sleep(); // 输出: Animal is sleeping
Animal.breathe(); // 输出: Animal is breathing
System.out.println(Animal.legs); // 输出: 4
}
}
10. 内部类
内部类(Inner Class)指的是定义在另一个类内部的类。内部类可以访问包含它的外部类的成员,并且可以提供更好的封装和组织代码的能力。Java中的内部类有以下几种类型:
1.成员内部类(Member Inner Class):成员内部类是定义在类的内部,并且与类的成员变量具有相同的级别。成员内部类可以直接访问外部类的成员,包括私有成员。可以使用以下语法创建成员内部类的实例:
class OuterClass {
// 外部类成员变量和方法
class InnerClass {
// 内部类定义
}
}
// 创建内部类的实例
OuterClass outerObj = new OuterClass();
OuterClass.InnerClass innerObj = outerObj.new InnerClass();
2.静态内部类(Static Inner Class):静态内部类是定义在类内部,但被声明为静态的。它与外部类没有直接的关联,可以通过外部类的名称直接访问。静态内部类不能访问外部类的非静态成员,只能访问静态成员。可以使用以下语法创建静态内部类的实例:
class OuterClass {
// 外部类成员变量和方法
static class InnerClass {
// 内部类定义
}
}
// 创建静态内部类的实例
OuterClass.InnerClass innerObj = new OuterClass.InnerClass();
3.方法局部内部类(Method Local Inner Class):方法局部内部类是定义在方法内部的类。这个类只在方法内可见,不能被其他方法或类访问。方法局部内部类可以访问方法的局部变量,但这些局部变量必须是 final
或 effectively final
(Java 8+)。
class OuterClass {
// 外部类成员方法
void method() {
class LocalInnerClass {
// 内部类定义
}
// 创建方法局部内部类的实例
LocalInnerClass innerObj = new LocalInnerClass();
}
}
4.匿名内部类(Anonymous Inner Class):匿名内部类没有显式的类名,它是在创建实例的同时定义和实现的。匿名内部类通常用于在接口或抽象类上创建实例。可以使用以下语法创建匿名内部类的实例:
interface MyInterface {
void method();
}
// 创建匿名内部类的实例
MyInterface innerObj = new MyInterface() {
public void method() {
// 实现方法
}
}