当前位置: 首页 > news >正文

java的面向对象思想

文章目录

    • 初识面向对象
      • 面向过程&面向对象
      • 什么是面向对象
    • 方法回顾和加深
      • 方法的定义
      • 方法的调用
    • 类与对象的关系
    • 对象的创建分析
      • 类与对象小结
    • 面向对象三大特性
      • 封装
        • 封装的好处
      • 继承
        • super
          • super注意点
        • 方法重写
          • 方法重写注意点
      • 多态
        • 多态注意点
      • instanceof
        • instanceof注意点
    • 抽象类和接口
      • 抽象类
        • 抽象类的注意点
      • 接口
        • 接口的注意点
    • 四种内部类详解
      • 内部类
        • 成员内部类
        • 静态内部类
        • 局部内部类
        • 匿名内部类
          • 匿名内部类关键点总结
          • 等效的传统写法
          • 等效的传统写法

初识面向对象

面向过程&面向对象

面向过程思想

  • 步骤清晰简单,第一步做什么,第二步做什么…
  • 面向过程适合处理一些较为简单的问题

面相对象思想

  • 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索
  • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题

对于描述复杂的事物,为了从宏观上把握,从整体上合理分析,我们需要使用面向对象来分析整个系统,但是,具体到微观操作,仍然需要面向过程的思路去处理

什么是面向对象

面向对象编程(Object-Oriented Programming,OOP)

面向对象编程的本质就是:以类的方式组织代码,以对象的形式组织(封装)数据

三大特性

  • 封装
  • 继承
  • 多态

从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象

从代码运行角度考虑是先有类后有对象。类是对象的模板

方法回顾和加深

方法的定义

修饰符:一个方法可以使用多个修饰符,如public,static,private,void

返回类型:与定义方法的类型修饰符一致

break:跳出switch。结束循环

return:结束方法,返回一个值,不返回,默认返回空

方法名:注意规范,见名知意

参数列表:可以有多个参数类型和参数名,还可以使用…定义可变长参数

异常抛出:使用throws抛出异常,使用try…catch代码块捕获异常后,抛给上级

方法的调用

静态方法( 和类一起加载):在方法前加上static修饰符,在静态方法内不能调用非静态方法

非静态方法(类实例化后才存在):在方法不加static修饰符,

静态方法和非静态方法的创建时机不同

package com.oop.demo01;public class Demo02 {public static void main(String[] args) {//    实例化这个类 使用new关键字//    对象类型  对象名 = 对象值Student student = new Student();student.say();}//    和类一起加载的public static void a() {
//        b(); // 调用时,b()方法还不存在,会报错}//    类实例化后才存在public void b() {}
}

形参和实参:形参的类型和实参的类型要一致

值传递和引用传递

package com.oop.demo01;// 值传递
public class Demo03 {public static void main(String[] args) {int a = 1;System.out.println(a); // 1Demo03.change(a);System.out.println(a); // 1}
//    返回值为空public static void change(int a) {a = 10;}
}
package com.oop.demo01;
// 引用传递(对象):本质还是值传递
public class Demo04 {public static void main(String[] args) {Person person = new Person();System.out.println(person.name); // nullDemo04.change(person);System.out.println(person.name); // baoli}public static void change(Person person) {person.name = "baoli";}
}// 定义一个Persion类,有一个属性 name
class Person {String name; // null
}

this关键字:代表当前类或对象

类与对象的关系

类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物

  • 动物、植物、手机、电脑…
  • Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为

对象是抽象概念的具体实例

  • 张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例
  • 能够体现出特点,展现出功能的是具体的实例,而不是抽象的概念

对象的创建分析

使用new关键字创建对象

使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用

类中的构造器也称为构造方法,是在进行创建对象的时候必须调用的,并且构造器有以下两个特点

  1. 必须和类的名字相同
  2. 必须没有返回类型,也不能写void
package com.oop.demo02;public class Application {public static void main(String[] args) {
//        类:抽象的
//        类实例化后会返回一个自己的对象!
//        student对象就是一个Student类的具体实例!Student kobe = new Student();Student james = new Student();kobe.name = "kobe";kobe.age = 35;System.out.println(kobe.name);System.out.println(kobe.age);james.name = "james";james.age = 39;System.out.println(james.name);System.out.println(james.age);}
}
package com.oop.demo02;// 学生类
public class Student {
//    属性:字段String name; // nullint age; // 0//    方法public void study() {System.out.println(this.name + "在学习");}
}

创建一个类,默认会有一个无参的构造方法

在这里插入图片描述

使用idea生成对应的.class文件

在这里插入图片描述

重载构造器

package com.oop.demo02;public class Person {
//    一个类即使什么都不写,也会存在一个构造方法
//    显示的定义构造器String name;//    无参构造器(默认构造器)
//    1、使用new关键字,本质是在调用构造器
//    2、构造器用来初始化值public Person() {}//    有参构造器(重载构造器):一旦定义了有参的构造器,那么必须显示的定义无参的构造器public Person(String name) {this.name = name;}
}

Person类生成的.class文件

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.oop.demo02;public class Person {String name;public Person() {}public Person(String name) {this.name = name;}
}

main方法(程序主入口)

package com.oop.demo02;public class Application {public static void main(String[] args) {
//        使用new关键字,实例化了一个对象Person person = new Person("baoli");System.out.println(person.name); // baoli}
}

构造器注意点:

  • 构造器:
    • 名称与类名相同
    • 没有返回值,不能写void
  • 作用:
    • new关键字本质在调用类的构造方法
    • 用于初始化对象的值
  • 注意点:
    • 定义有参构造器后,必须显示的定义一个无参的构造器
  • 创建构造器的快捷键:
    • ALT+insert

类与对象小结

1、类与对象类是一个模板:抽象,对象是一个具体的实例
2、方法定义和调用
3、对象的引用基本类型(8)引用类型:对象是通过引用来操作数据的:栈 --->4、属性:字段Field -> 成员变量默认初始化:数字:0 0.0cahr:u0000booleanfalse引用:null修饰符 属性类型 属性 = 属性值
5、对象的创建和使用(1)必须使用new关键字创建对象,至少有一个构造器 Person baoli = new Person()2)调用对象的属性:baoli.name(3)调用对象的方法:baoli.sleep()
6、类:静态的属性——>属性动态的行为——>方法

面向对象三大特性

封装

该露的露,该藏的藏

  • 程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用

封装(数据的隐藏)

  • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏

属性私有:get/set

package com.oop.demo02;// 类 private:私有
public class Student {
//    属性私有private String name; // 姓名private int id; // 学号private char sex; // 性别private int age; // 年龄//    提供一些可以操作这个属性的方法(get、set)
//    get获取这个数据public String getName() {return this.name;}
//    get给设个数据设置值public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {if (age > 120 || age < 0) {this.age = 3;} else {this.age = age;}}
}

main程序入口

package com.oop.demo02;public class Application {public static void main(String[] args) {Student student = new Student();student.setName("baoli");System.out.println(student.getName());student.setAge(999); // 不合法的System.out.println(student.getAge()); // 3}
}
封装的好处
  1. 提高程序的安全性,保护数据
  2. 隐藏了代码的时间细节,高内聚,低耦合
  3. 统一接口
  4. 提高系统可维护性

继承

继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模

extend的意思是“扩展”,子类是父类的扩展

java中类只有单继承,没有多继承

继承是类和类之间的一种关系,除此之外,类和类之间的关系还有依赖、组合、聚合等

继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示

子类和父类之间,从意义上讲应该具有“is a”的关系

Object类

super

父类Person

package com.oop.demo02;// 在java中,所有的类,都默认直接或者间接继承Object
// Person 人:父类
public class Person {protected String name = "james";//    如果是private,则子类也无法继承使用public void print() {System.out.println("Person");}public Person() {System.out.println("Person无参构造器执行了");}
}

子类Student

package com.oop.demo02;// 学生 is 人: 派生类,子类
// 子类继承了父类,就会拥有父类的全部方法
public class Student extends Person {private String name = "kobe";public void print() {System.out.println("Student");}public Student() {
//        隐藏代码:默认调用了父类的无参构造器super(); // 调用父类的构造器,必须放在子类构造器的第一行System.out.println("Student无参构造器执行了");}public void test(String name){System.out.println(name); // baoliSystem.out.println(this.name); // kobeSystem.out.println(super.name); // james}public void test(){print(); // Studentthis.print(); // Studentsuper.print(); // Person}
}

main方法程序主入口

package com.oop.demo02;public class Application {public static void main(String[] args) {Student student = new Student();student.test("baoli"); // baoli kobe jamesstudent.test(); // Student Student Person}
}
super注意点
  1. super调用父类的构造方法,必须在构造方法的第一个
  2. super必须只能出现在子类的方法或者构造方法中
  3. super()和this()这两个构造方法不能同时调用

super对比this:

  • 代表对象不同
    • this:本身调用者这个对象
    • super:代表父类对象
  • 前提:
    • this:没继承也可以使用
    • supper:只能在继承条件下才可以使用
  • 构造方法:
    • this():当前类的构造方法
    • super ():父类的构造方法
方法重写

A类(派生类,子类)

package com.oop.demo02;// 继承B类
public class A extends B{public static void test() {System.out.println("A=>test()");}
}

B类(基类,父类)

package com.oop.demo02;// 重写都是方法的重写,和属性无关
public class B {public static void test() {System.out.println("B=>test()");}
}

main()方法主入口

package com.oop.demo02;public class Application {public static void main(String[] args) {
//        方法的调用只和左边定义的数据类型有关A a = new A();a.test(); // A
//        父类的引用指向了子类B b = new A();b.test(); // B}
}

方法重写对象方法

在这里插入图片描述

A类(派生类,子类)

package com.oop.demo02;// 继承B类
public class A extends B{
//    @Override 重写@Override // 注解:有功能的注释public void test() {
//        super.test(); 默认生成System.out.println("A=>test()");}
}

B类(基类,父类)

package com.oop.demo02;// 重写都是方法的重写,和属性无关
public class B {public void test() {System.out.println("B=>test()");}
}

main()方法主入口

package com.oop.demo02;public class Application {public static void main(String[] args) {
//        方法的调用只和左边,定义的数据类型有关
//       非静态的方法可以重写A a = new A();a.test(); // A
//        父类的引用指向了子类B b = new A();b.test(); // A}
}
方法重写注意点
  1. 方法没有static修饰时,b调用的是对象的方法,而b是用A类new的

  2. 方法有static修饰时,b调用了B类的方法,因为b是用B类定义的

  3. 重写需要有继承关系,子类重写父类的方法

  4. 方法名必须相同,参数列表必须相同,方法体不同

  5. 修饰符:范围可以扩大但不能缩小: public >protected>default>private

  6. 抛出的异常:范围可以被缩小,但不能扩大:ClassNotFount -> Exception

多态

  • 即同一方法可以根据发送对象的不同而采用多种不同的行为方式
  • 一个对象的实际类型是确定的,但可以指向对象的引用的类型很多
  • 多态存在的条件
    • 有继承关系
    • 子类重写父类的方法
    • 父类引用指向子类对象
  • 注意:多态是方法的多态,属性没有多态性
  • instanceof
  • 引用类型转换

Student子类

package com.oop.demo03;public class Student extends Person {@Override // 重写了父类的run方法public void run() {System.out.println("Student run");}public void eat() {System.out.println("Student eat");}
}

Person父类

package com.oop.demo03;public class Person {public void run() {System.out.println("Person run");}
}

main方法主入口

package com.oop;
import com.oop.demo03.Person;
import com.oop.demo03.Student;public class Application {public static void main(String[] args) {
//         一个对象的实际类型是确定的
//        new Student();
//        new Person();
//        但可以指向的引用类型就不确定了,父类的引用指向子类//        Student 能调用的方法都是自己的或者继承父类的方法Student s1 = new Student();
//        Person 父类,可以指向子类,但是不能调用子类独有的方法(子类有,父类没有)Person s2 = new Student();Object s3 = new Student();//        对象能执行哪些方法,主要看对象左边的类型s1.run(); // Student run// 子类重写了父亲的方法,执行子类的方法s2.run(); // Student runs1.eat(); // Student eat}
}
多态注意点
  • 子类重写了方法的前提下,只要new的是子类实例,无论实例前声明的是超类还是子类的引用,都会调用子类自己重写过的方法
  1. 多态是方法的多态,属性没有多态
  2. 父类和子类,类型转换异常!ClassCastException
  3. 存在多态的必要条件:有继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son()
  4. 不能重写的方法
    1. static方法,属于类方法,不属于实例方法,不能重写
    2. final修饰符 修饰的方法
    3. private修饰符 修饰的方法

instanceof

package com.oop;
import com.oop.demo04.Person;
import com.oop.demo04.Student;public class Application {public static void main(String[] args) {
//        Object > String
//        Object > Person > Teacher
//        Object > Person > Student
//        编译看左边,运行看右边,左边是右边的实例或本身,返回true否则返回falseObject object = new Student();System.out.println(object instanceof Student); // trueSystem.out.println(object instanceof Person); // trueSystem.out.println(object instanceof Object); // trueSystem.out.println(object instanceof Tearcher); // falseSystem.out.println(object instanceof String); // falseSystem.out.println("================================");Person person = new Student();System.out.println(person instanceof Student); // trueSystem.out.println(person instanceof Person); // trueSystem.out.println(person instanceof Object); // trueSystem.out.println(person instanceof Tearcher); // false
//        System.out.println(person instanceof String); // 编译报错System.out.println("================================");Student student = new Student();System.out.println(student instanceof Student); // trueSystem.out.println(student instanceof Person); // trueSystem.out.println(student instanceof Object); // true
//        System.out.println(student instanceof Tearcher); // 编译报错
//        System.out.println(student instanceof String); // 编译报错}
}

Student子类

package com.oop.demo04;public class Student extends Person {public void go() {System.out.println("Student go");}
}

Person父类

package com.oop.demo04;public class Person {public void run() {System.out.println("Person run");}
}

main()主入口

package com.oop;
import com.oop.demo04.Person;
import com.oop.demo04.Student;public class Application {public static void main(String[] args) {
//        类型之间的转化:父 ---> 子
//        高                 低Person person = new Student();
//      将这个对象转换为Student类型,我们就可以使用Student类型的方法了Student student = (Student) person; // 父类转子类,高转低->强制转换// 调用子类的go方法student.go(); // Student go// 调用父类的run方法student.run(); // Person runSystem.out.println("===========================");
//        子类转父类,可能丢失自己本来独有的一些方法!Student student1 = new Student();student1.go(); // 转换前可以调用子类独有的go方法Person person1 = student1; // 子类转父类,低转高->自动转换// 转换后不能调用转换前的子类独有的go方法,只能调用父类独有的run方法person1.run();}
}

如果子类中重写了父类的方法

Student子类重写父类的run方法

package com.oop.demo04;public class Student extends Person {public void go() {System.out.println("Student go");}@Overridepublic void run() {System.out.println("Student run");}
}

main()主入口

package com.oop;
import com.oop.demo04.Person;
import com.oop.demo04.Student;public class Application {public static void main(String[] args) {
//        类型之间的转化:父 ---> 子
//        高                 低Person person = new Student();
//      将这个对象转换为Student类型,我们就可以使用Student类型的方法了Student student = (Student) person; // 父类转子类,高转低->强制转换// 调用子类的go方法student.go(); // Student go// 调用被子类重写的run方法student.run(); // Student runSystem.out.println("===========================");
//        子类转父类,可能丢失自己本来的一些特有方法!Student student1 = new Student();student1.go(); // 转换前可以调用go方法Person person1 = student1; // 子类转父类,低转高->自动转换// 转换后,不能调用转换之前子类独有的go方法person1.run(); // 可以调用被子类重写的run方法}
}
instanceof注意点
  • 子转父: 向上转型, 直接转, 丢失子类中原本可直接调用的特有方法; 父转子: 向下转型, 强制转, 丢失父类被子类所重写掉的方法。

抽象类和接口

抽象类

abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法,如果修饰类,那么该类就是抽象类

抽象类,不能使用new关键字来创建对象,他是用来让子类继承的

抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的

子类继承抽象类,那么就必须要实现抽象类,没有实现的抽象方法,否则该子类也要声明为抽象类

子类A

package com.oop.demo05;// 继承了抽象类,就必须实现抽象类中的所有抽象方法,除非自己也是抽象类
public class A extends Action{@Overridepublic void doSomething() {}
}

抽象类:父类Action

package com.oop.demo05;// abstract修饰类,代表这个类是抽象类
public abstract class Action {
//    abstract修饰方法,代表这个方法是抽象方法
//    抽象方法:只有方法名字,没有方法实现
//    abstract可以作为一个约束,自己不用实现,有自己的后代帮我们实现public abstract void doSomething();public void hello() {System.out.println("hello abstract");}
}
抽象类的注意点
  1. 有抽象方法的类一定是抽象类,抽象类里不一定有抽象方法
  2. 不能new这个抽象类,只能靠子类去实现它
  3. 抽象类中可以写普通方法
  4. 抽象方法必须在抽象类中
  5. 抽象类不能被实例化,抽象类中没有构造方法

接口

普通类:只有具体实现

抽象类:具体实现和规范(抽象方法)都有

接口:只有规范!自己无法写方法,约束和实现分离,面向接口编程

  • 接口就是规范,定义的是一组规则
  • 接口本质是契约,就想我们人间的法律一样,制定好后大家都遵守
  • 面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口

UserService接口

package com.oop.demo06;// interface 定义的关键字, 接口都需要有实现类
public interface UserService {
//    接口中定义的属性,默认都是静态常量,默认加了 public static finalint AGE = 99;//    接口中的所有定义的方法,其实都是抽象的,定义的方法默认加了 public abstract修饰符void add(String name);void delete(String name);void update(String name);void query(String name);
}

TimeService接口

package com.oop.demo06;public interface TimeService {void timer();
}

UserServiceImpl.java

package com.oop.demo06;// 抽象类只能使用extends实现方法,所以是单继承
// 类 可以实现接口 使用 implements关键字实现接口
// 实现了接口的类,就需要实现接口中的方法
// 利用接口实现多继承
public class UserServiceImpl implements UserService,TimeService{@Overridepublic void add(String name) {}@Overridepublic void delete(String name) {}@Overridepublic void update(String name) {}@Overridepublic void query(String name) {}@Overridepublic void timer() {}
}
接口的注意点
  1. 接口都是约束
  2. 定义的方法默认都是抽象方法,让不同的人实现 -> public abstract
  3. 定义的属性默认都是静态常量 -> public static final
  4. 接口不能被实例化,接口中没有构造方法
  5. implements可以实现多个接口,必须要重新多个接口中的所有方法

四种内部类详解

内部类

内部类就是在一个类的内部再定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类

  1. 成员内部类
  2. 静态内部类
  3. 局部内部类
  4. 匿名内部类
成员内部类
package com.oop.demo07;// 外部类
public class Outer {private int id = 10;public void out() {System.out.println("这是外部类的out方法");}// 成员内部类public class Inner {public void in() {System.out.println("这是成员内部类的in方法");}//        获得外部类的私有属性或私有方法public void getId() {System.out.println(id);}}
}

main()程序主入口

package com.oop;
import com.oop.demo07.Outer;public class Application {public static void main(String[] args) {// 成员内部类是外部类的实例,因此需要先创建外部类的对象即可实例化        
//        通过这个外部类来实例化内部类Outer outer = new Outer();Outer.Inner inner = outer.new Inner();inner.in(); // 这是成员内部类的in方法inner.getId(); // 10}
}

成员内部类注意点

  1. 内部类可以直接访问外部类方法和属性,不需创建外部类的对象
  2. **成员内部类是外部类的实例,因此需要先创建外部类的对象即可实例化 **
静态内部类

如果内部类是用static修饰的,要访问外部类的属性,那么外部类的属性也需要加上static修饰

外部类Outer

package com.oop.demo07;public class Outer {// 加上static,静态内部类就可以访问这个属性private static int id = 10;public void out() {System.out.println("这是外部类的out方法");}// 静态内部类(嵌套类)public static class Inner {public void in() {System.out.println("这是静态内部类的in方法");}//        获得外部类的私有属性或私有方法public void getId() {System.out.println(id);}}
}

main()程序主入口

package com.oop;
import com.oop.demo07.Outer;public class Application {public static void main(String[] args) {Outer outer = new Outer();// 静态内部类属于外部类本身,而不是外部类的实例,因此不需要先创建外部类的对象即可实例化。// 直接实例化静态内部类,无需创建 Outer 的实例Outer.Inner inner = new Outer.Inner();inner.in(); // 这是静态内部类的in方法new Outer().out(); // 这是外部类的out方法}
}

静态内部类的注意点

  • **静态内部类(也称为嵌套类)可以被实例化,但实例化方式与非静态内部类(成员内部类)不同。 **
  • **静态内部类属于外部类本身,而不是外部类的实例,因此不需要先创建外部类的对象即可实例化。 **
  • **直接实例化静态内部类,无需创建 Outer 的实例 **
局部内部类

Outer.java

package com.oop.demo07;public class Outer {
//    局部内部类public void method() {class Inner {public void in() {System.out.println("这是局部内部类的in方法");}}// 只能在 method() 方法内部实例化 Inner 类Inner inner = new Inner();inner.in(); // 调用内部类的方法}
}

main()程序主入口

package com.oop;
import com.oop.demo07.Outer;public class Application {public static void main(String[] args) {Outer outer = new Outer();// 调用 method() 时才会执行 Inner 类的实例化和方法调用outer.method(); // 这是局部内部类的in方法}
}

局部内部类的注意点

  • 局部内部类的作用域Inner类只能在 method()方法内部被访问,外部无法直接引用。
  • **必须在 method()方法的内部创建 Inner 的实例,因为该类的定义只在方法的作用域内有效。 **
匿名内部类

匿名内部类的第一种形式(new 类名() {})

package com.oop.demo07;public class Test {public static void main(String[] args) {// 使用了匿名内部类的语法来创建 Apple 类的实例new Apple().eat(); // 普通的顶级类的eat方法Apple apple = new Apple() {@Overridepublic void eat() {
//                super.eat(); // 重写eat方法默认生成System.out.println("这才是匿名内部类中重写的eat方法");}};apple.eat(); // 这才是匿名内部类中重写的eat方法new Apple() {@Overridepublic void eat() {
//                super.eat(); // 重写eat方法默认生成System.out.println("这才是匿名内部类中重写的eat方法");}}.eat(); // 这才是匿名内部类中重写的eat方法}
}// Apple 是一个普通的顶级类(非内部类)
class Apple {public void eat() {System.out.println("普通的顶级类的eat方法");}
}
  1. 匿名内部类的本质
    这行代码创建了一个继承自 Apple 的匿名子类,并立即实例化该子类的对象。这个子类重写了 eat() 方法,因此调用 eat() 时会执行重写后的逻辑

  2. 对象的类型
    虽然对象的引用类型是 Apple,但实际类型是匿名子类。例如:

Apple apple = new Apple() {@Overridepublic void eat() {System.out.println("匿名内部类");}
};System.out.println(apple.getClass()); // 输出: class com.oop.demo07.Test$1

Test$1 表示这是 Test 类的第一个匿名内部类。

  1. 多态的体现
    通过父类 Apple 的引用调用 eat() 方法时,实际执行的是匿名子类中重写的方法(动态绑定)。
匿名内部类关键点总结
  • new Apple(){...} 返回对象:它是匿名子类的实例,也是 Apple 类的子类对象。
  • new Apple(){...} 返回的是一个对象实例,属于匿名内部类类型。这个匿名内部类继承自 Apple 类,并在创建时重写了 eat() 方法。
  • 匿名内部类的特点
    • 没有显式的类名,直接在 new 语句中定义。
    • 必须继承某个类或实现某个接口。
    • 适合创建一次性使用、需要自定义行为的子类。
  • 与普通子类的区别
    匿名内部类无需单独定义类文件,语法更简洁,但只能使用一次。
等效的传统写法

这段代码等效于先定义一个具名子类,再实例化它:

// 定义具名子类
class SpecialApple extends Apple {@Overridepublic void eat() {System.out.println("具名子类的eat方法");}
}// 实例化具名子类
new SpecialApple().eat();

匿名内部类的第二种形式(new 接口名(){})

package com.oop.demo07;public class Test {public static void main(String[] args) {UserService userService = new UserService() {@Overridepublic void hello() {System.out.println("我是接口实现的匿名内部类");}};userService.hello(); // 我是接口实现的匿名内部类new UserService() {@Overridepublic void hello() {System.out.println("我是接口实现的匿名内部类");}}.hello(); // 我是接口实现的匿名内部类}
}interface UserService {void hello();
}

userService 是一个对象实例,属于匿名内部类类型,在创建对象的同时实现了 UserService 接口

UserService userService = new UserService() {@Overridepublic void hello() {System.out.println("我是接口实现的匿名内部类");}
};
userService.hello(); // 我是接口实现的匿名内部类

匿名内部类的本质

  1. 这行代码实际上创建了一个没有显式类名的类,该类实现了 UserService 接口

  2. 对象的类型
    userServiceUserService 接口的实例,但具体类型是匿名内部类,匿名内部类会隐式实现该接口。

  3. 对象的行为
    userService 对象的 hello() 方法会执行匿名内部类中重写的逻辑:

    userService.hello(); // 输出:我是接口实现的匿名内部类
    
等效的传统写法

这段代码等效于先定义一个具名类,再实例化它:

// 定义一个实现 UserService 接口的具体类
class MyUserService implements UserService {@Overridepublic void hello() {System.out.println("我是接口实现的匿名内部类");}
}// 实例化具名类
UserService userService = new MyUserService();

匿名内部类注意点

  • 匿名内部类:需要在 new 关键字后紧跟类名(或接口名),并通过 {…}定义类的内容(如方法重写)
  • 匿名内部类的核心特点是没有显式的类名,并且在创建时直接实现或继承某个类 / 接口
  • 匿名内部类的优势在于无需显式定义类名,适合简化一次性使用的子类实现,也适合一次性使用的场景(如事件监听器、回调函数)

相关文章:

  • 小蜗牛拨号助手用户使用手册
  • 2.1.3
  • 【基于栈的 Vue3 路由历史管理:优雅处理多系统间的导航】
  • 使用python进行船舶轨迹跟踪
  • 符合Python风格的对象(对象表示形式)
  • 使用HtmlAgilityPack采集墨迹天气中的天气数据
  • 简单神经网络(ANN)实现:从零开始构建第一个模型
  • python项目参考文献
  • 用Python玩转人工智能——数字识别技术 之二
  • QT软件安装
  • 高效完成任务:制定标准与限时完成的双重法宝
  • 三层固定实体架构:高效实现图上的检索增强生成(RAG)
  • 2024 山东省ccpc省赛
  • 【持续更新中】架构面试知识学习总结
  • 回溯法理论基础 LeetCode 77. 组合 LeetCode 216.组合总和III LeetCode 17.电话号码的字母组合
  • 在RK3588上使用NCNN和Vulkan加速ResNet50推理全流程
  • 一阶线性方程 线性方程
  • 设计模式Java
  • C语言指针深入详解(一):内存和地址、指针变量和地址、指针变量类型的意义、指针运算
  • Makefile变量冲突与包含关系解析
  • 气急败坏!20多名台湾艺人被台当局列为“重点核查对象”
  • 六省会共建交通枢纽集群,中部离经济“第五极”有多远?
  • 小雨伞保险经纪母公司手回集团通过港交所聆讯
  • 农行再回应客户办理业务期间离世:亲属连续三次输错密码,理解亲属悲痛,将协助做好善后
  • 严打金融黑灰产,今年来上海警方破获各类经济犯罪案件690余起
  • 订婚不等于性同意!山西订婚强奸案入选最高法案例