Java 基础 05. Java 面向对象

1. 初识面向对象

  • 面向过程思想
    • 步骤清晰简单,第一步做什么,第二步做什么…
    • 面对过程适合处理一些较为简单的问题。
  • 面向对象思想
    • 物以类聚,分类 的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
  • 对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理
  • 面向对象编程( Object - Oriented Programming,OOP)
  • 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
  • 三大特征:
    • 封装
    • 继承
    • 多态
  • 从认识的角度考虑,是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象。
  • 从代码运行角度考虑是先有类后有对象。类是对象的模板

2. 方法回顾和加深

  • 方法的定义

    • 修饰符
    • 返回类型
    • break:跳出 switch,结束循环。return:结束方法,返回结果
    • 方法名:注意规范,见名知意
    • 参数列表:(参数类型,参数名) …
    • 异常抛出:疑问,参考下文!
    package github.oop;
    import java.io.IOException;
    
    // 类
    public class Demo01 {
        // main方法
        public static void main(String[] args) {
        }
        /*
        修饰符 返回值类型 方法名(...){
            // 方法体
            return 返回值;
        }
         */
        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{
        }
    }
    
  • 方法的调用

    • 静态方法(和类一起加载)
    • 非静态方法(类实例化之后,才存在)
    • 形参和实参

      package com.xxx.oop.demo01;
      
      public class Demo03 {
        public static void main(String[] args) {
            // 实参  注意:实际参数和形式参数的类型要对应
            int add = new Demo03().add(3, 5);
            System.out.println(add);
        }
        // 形参
        public int add(int a, int b) {
            return a + b;
        }
      }
      
      • 值传递和引用传递
      package com.xxx.oop.demo01;
      
      // 值传递
      public class Demo04 {
          public static void main(String[] args) {
              int a = 1;
              System.out.println(a);  // 1
      
              Demo04.change(a);
              System.out.println(a);  // 1
          }
      
          // 返回值为空
          public static void change(int a) {
              a = 10;
          }
      }
      
      package com.xxx.oop.demo01;
      
      // 引用传递:对象,本质还是值传递
      public class Demo05 {
          public static void main(String[] args) {
              // 创建对象
              Person person = new Person();
              System.out.println(person.name);    // Null
      
              Demo05.change(person);
              System.out.println(person.name);    // 测试名
          }
      
          // 定义一个方法
          public static void change(Person person) {
              // person 是一个对象:指向 ---> Person person = new Person(); 这是一个具体的人,可以改变属性
              person.name = "测试名";
          }
      }
      
      // 一个类文件里可以定义多个类,但只能有一个 public 类
      // 定义一个 Person 类,有一个属性:name
      class Person {
          String name;
      }
      
    • this 关键字:this 代表当前的类

3. 类与对象的关系

  • 类(模板):是一种抽象的数据类型,它是对某一类事物整体描述/定义但是并不能代表某一个具体的事物
  • 对象(实例):是抽象概念的具体实例

4. 类与对象的创建

  • 类一般包含:属性(字段 Field)、方法
// 创建类
package com.xxx.oop.demo02;

// 学生类
public class Student {
    // 属性:字段
    String name;    // 默认 Null
    int age;    // 默认 0

    // 方法
    public void study() {
        // this 代表当前的类
        System.out.println(this.name + "在学习");
    }
}
  • 使用 new 关键字创建对象。
  • 使用 new 关键字创建的时候,除了分配内存空间之外,还会给创建好的对象 进行默认的初始化,以及 对类中构造器的调用
// 创建对象
package com.xxx.oop.demo02;

// 一个项目应该只存在一个 main 方法
public class Application {
    public static void main(String[] args) {
        // 类:抽象的,实例化
        // 类实例化后,会返回一个自己的对象!
        // student1 student2 对象,就是 Student 类的具体实例!
        Student student1 = new Student();
        Student student2 = new Student();

        // 未赋值
        System.out.println(student1.name);  // null
        System.out.println(student1.age);   // 0

        student2.name="Liu";
        student2.age=3;
        // 已赋值
        System.out.println(student2.name);  // Liu
        System.out.println(student2.age);   // 3

        student2.study();   // Liu在学习
    }
}
  • 类中的构造器也称为 构造方法是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
    • 必须和类的名字相同
    • 必须没有返回类型,也不能写 void
    • 快捷方式 Alt + Insert
  • 构造器作用:
    • 使用 new 关键字,本质在调用构造方法;
    • 用来初始化对象的值。
  • 注意:定义有参构造之后,如果想使用无参构造,必须显示的定义一个无参构造
package com.xxx.oop.demo02;

public class Person {
    // 一个类即使什么也不写,也存在一个与类同名的方法
    // 显示的定义构造器

    String name;

    // 定义无参构造器
    /*
     * 1. 使用 new 关键字,本质在调用构造方法;
     * 2. 用来初始化对象的值
     * */
    public Person() {
        this.name = "name01";
    }

    // 有参构造器
    // 定义有参构造器,如果想使用无参构造,无参就必须显示定义
    public Person(String name) {
        this.name = name;
    }
}
package com.xxx.oop.demo02;

// 一个项目应该只存在一个 main 方法
public class Application {
    public static void main(String[] args) {
        // 实例化对象,调用无参
        Person person = new Person();
        System.out.println(person.name);

        // 调用有参
        Person person1 = new Person("有参构造");
        System.out.println(person1.name);
    }
}

5. 创建对象内存分析

  • 创建类
package com.xxx.oop.demo03;

public class Pet {
    // 属性
    public String name;
    public int age;

    // 方法
    public void shout() {
        System.out.println("叫了一声!");
    }
}
  • 创建对象(实例化类)
package com.xxx.oop;

import com.xxx.oop.demo03.Pet;

public class Application {
    public static void main(String[] args) {
        // 实例化类,创建 dog 对象
        Pet dog = new Pet();
        // 赋值
        dog.name = "旺财";
        dog.age = 3;

        System.out.println(dog.name);   // 旺财
        System.out.println(dog.age);    // 3
        dog.shout();    // 叫了一声!
        System.out.println("===========");
        // 创建 cat 对象
        Pet cat = new Pet();
        // 未赋值,为默认值
        System.out.println(cat.name);   // Null
        System.out.println(cat.age);    // 0
        cat.shout();    // 叫了一声!
    }
}

小结:

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

6. 面向对象三大特性:封装、继承、多态

1、封装:属性私有,get/set

  • 程序设计要追求 高内聚,低耦合。高内聚,就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
  • 封装(数据的隐藏):通常,应禁止直接访问一个对象中数据的实际表示,而应该通过操作接口来访问,这称为信息隐藏。
package com.xxx.oop;

import com.xxx.oop.demo04.Student;

public class Application {
    public static void main(String[] args) {
        Student s1 = new Student();

        s1.setName("Liu");
        System.out.println(s1.getName());

        s1.setAge(999); // 非法值
        System.out.println(s1.getAge());
    }
}
package com.xxx.oop.demo04;

// 类    private:私有
public class Student {
    // 属性私有
    private String name;    // 姓名
    private int id;    // 学号
    private char sex;   // 性别
    private int age;    // 年龄

    // 提供一些可以操作属性的方法 public get() set()
    // 自动创建 get set 方法: 快捷键 Alt + Insert
    // get 获取数据
    public String getName() {
        return name;
    }
    // set 设置数据
    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 120 || age < 0) {
            this.age = 3;
        } else {
            this.age = age;
        }
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }
}
  • 封装的作用:
    • 提高了代码的安全性,保护数据;
    • 隐藏代码的实现细则;
    • 统一接口;
    • 系统可维护增加了。

2、继承:object 类、super、方法重写

  • 继承的本质是 对某一批类的抽象,从而实现对现实世界更好的建模。
  • extands 的意思是 扩展。子类是父类的扩展。
  • Java 中类 只有单继承,没有多继承
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类使用关键字 extends 来表示。
  • 子类和父类之间从意义上讲应该具有 is a 的关系。
  • 在 Java 中,所有的类,都默认直接或间接的继承 object 类
    • 创建父类 Person
      package com.xxx.oop.demo05;
      
      // Person 人 :父类
      // 在 Java 中,所有的类,都默认直接或间接的继承 object 类,显示当前类的层次结构 快捷键 Ctrl + H
      public class Person {
          // public   公共
          // protected    受保护的
          // default  默认
          // private  私有
          private String s1 = "父类属性";
      
          public String getS1() {
              return s1;
          }
      
          public void setS1(String s1) {
              this.s1 = s1;
          }
      
          public void say() {
              System.out.println("父类方法");
          }
      }    
      
    • 创建子类 Student
      package com.xxx.oop.demo05;
      // Student 学生 is 人:派生类,子类
      // 子类继承了父类,就会拥有父类的全部方法
      public class Student extends Person{
          // 子类中并没有创建任何属性和方法
      }
      
    • 测试类:通过子类调用父类的属性和方法
      package com.xxx.oop;
      
      import com.xxx.oop.demo05.Student;
      public class Application {
          public static void main(String[] args) {
              // 实例化学生类
              Student student = new Student();
              // 打印 Person 父类的属性值
              System.out.println(student.getS1());
              // 调用 Person 父类的方法
              student.say();
          }
      }
      
  • 显示当前类的层次结构:快捷键 Ctrl + H
  • 调用结果

Super 概述

  • 私有的(private)东西无法被继承!!!
  • 子类会默认的先调用父类的无参构造方法 (隐藏代码 super();)

super 注意点

  1. super 调用父类的构造方法,必须在构造方法的第一行!
  2. super 必须只能出现在子类的方法或者构造方法中!
  3. super 和 this 不能同时调用构造方法!

super VS this

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

重写:都是方法的重写,与属性无关

  • 静态方法测试
  • 非静态方法测试

总结:重写,需要有 继承关系,子类重写父类的方法,且必须是 非静态方法

  1. 方法名必须相同;
  2. 参数列表列表必须相同;
  3. 修饰符:范围可以扩大但不能缩小: public > Protected > Default > private
  4. 抛出的异常:范围,可以被缩小,但不能扩大;ClassNotFoundException —> Exception (大)
  • 重写:子类的方法和父类必须要一致;方法体不同!
  • 为什么需要重写:父类的功能,子类不一定需要,或者不一定满足!
  • 重写快捷键:Alt + Insert => override 或(Ctrl + O)

3、多态:

  • 即同一方法可以根据发送对象的不同,而采用多种不同的行为方式。
  • 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)。
  • 多态存在的条件:
    • 有继承关系;
    • 子类重写父类方法;
    • 父类引用指向子类对象。
  • 多态注意事项:
    1. 多态是 方法的多态属性没有多态
    2. 父类和子类,有联系,类型转换异常!ClassCastException!
    3. 存在条件:继承条件,方法需要重写!父类引用指向子类对象!Father f1 = new Son();
  • 不可重写的方法(无法多态):
    1. static 方法,(静态)属于类,它不属于实例;
    2. final 常量;
    3. private 方法;(私有)

instanceof:判断两个类型之间是否存在父子关系。左边的对象,是否是右边的类的实例,返回 boolean 的数据类型。

Object > String
Object > Person > Teacher
Object > Person > Student
  • 创建 Person 类(父类):
package com.xxx.oop.demo09;
// 父类
public class Person {
    public void go(){
        System.out.println("go");
    }
}
  • 创建子类:Teacher 类继承 Person 类:
package com.xxx.oop.demo09;
// 子类,继承 Person 类
public class Teacher extends Person{
}
  • 创建子类:Student 类继承 Person 类:
package com.xxx.oop.demo09;
// 子类,继承 Person 类
public class Student extends Person{
}
  • 主函数
public static void main(String[] args) {
        Object obj = new Student();
        System.out.println(obj instanceof Student); // true
        System.out.println(obj instanceof Person);  // true
        System.out.println(obj instanceof Object);  // true
        System.out.println(obj instanceof Teacher); // false
        System.out.println(obj instanceof String);  // false
    }
  • 运行结果
  • 主函数
Person person = new Student();
System.out.println(person instanceof Student); // true
System.out.println(person instanceof Person);  // true
System.out.println(person instanceof Object);  // true
System.out.println(person instanceof Teacher); // false
// System.out.println(person instanceof String);  // 编译报错
  • 运行结果
  • 主函数
Student student = new Student();
System.out.println(student instanceof Student); // true
System.out.println(student instanceof Person);  // true
System.out.println(student instanceof Object);  // true
// System.out.println(student instanceof Teacher); // 编译报错
// System.out.println(student instanceof String);  // 编译报错
  • 运行结果
  • 类型转换:父类型转子类型(高转低),需强制转换;子类型转父类型(低转高),可能会丢失方法。
  • 创建父类 Person
package com.xxx.oop.demo09;
// 父类
public class Person {
    public void run(){
        System.out.println("run");
    }
}
  • 创建子类 Student,继承 Person 类
package com.xxx.oop.demo09;
// 子类,继承 Person 类
public class Student extends Person{
    public void go(){
        System.out.println("go");
    }
}
  • 主函数类:
package com.xxx.oop;

import com.xxx.oop.demo09.Person;
import com.xxx.oop.demo09.Student;

// 测试类
public class Application {
    public static void main(String[] args) {
        // 类型之间转换:父类 子类
        // 高                低
        Person person = new Student();  // 低转高,自动转换
        // person.go(); 无法调用 Student 子类的独有方法

        // 将 person 强制转化成 Student 类型,就可以使用 Student 类型的方法了
        Student student = (Student) person; // 高转低,强制转换
        student.go();   // 调用 Student 子类的独有方法
        // ((Student) person).go(); 简写方式
        student.run();  // 调用 Person 父类的方法
    }
}
  • 运行结果
  • 低转高
public class Application {
    public static void main(String[] args) {
        // 类型之间转换:父类 子类
        Student student = new Student();
        student.go();
        // 子类转换为父类,可能会丢失自己的本来方法
        Person person = student;    // 低转高,自动转换
    }
}

类型转换 总结:

  1. 父类引用指向子类的对象
  2. 把子类转换为父类,向上转换
  3. 把父类转换为子类,向下转换,强制转换
  4. 方便方法的调用,减少重复的代码

static 关键字

  • 修饰属性时为静态属性:private static int age;
package com.xxx.oop.demo10;
// static
public class Student {
    private static int age; // 静态变量(类变量)
    private double score;   // 非静态变量

    public static void main(String[] args) {
        Student s1 = new Student();
        // 通过对象方式调用 静态变量
        System.out.println(s1.age); // 0
        // 通过对象方式调用 非静态变量
        System.out.println(s1.score);   // 0.0
        // 通过类方式调用 静态变量
        System.out.println(Student.age);    // 0
        // 报错:通过类方式无法调用 非静态变量
        // System.out.println(Student.score);   // 编译报错
    }
}
  • 修饰方法时为静态方法:public static void go(){...}
    • 静态方法调用:
      1. 直接调用 go();
      2. 通过类方式调用 Student.go();
      3. 通过对象实例的方式调用 new Student().go();
    • 非静态方法调用:只能通过对象实例的方式,来调用 new Student().run();
package com.xxx.oop.demo10;
// static
public class Student {
    public void run(){      // 非静态方法
        go();   // 非静态方法中可以直接调用静态方法
        System.out.println("非静态方法");
    }
    public static void go(){    // 静态方法
        System.out.println("静态方法");
    }
    public static void main(String[] args) {
        // 静态方法调用
        go();   // 1. 直接调用
        Student.go();   // 2. 通过类方式
        new Student().go(); // 3. 通过对象实例方式
        // 非静态方法调用
        // run();  报错:不能直接调用非静态方法
        new Student().run();    // 只能通过对象方式调用 非静态方法
    }
}

补充

  • 匿名代码块:{ // 代码体 }
  • 静态代码块:static { // 代码体 }
package com.xxx.oop.demo10;

public class Person {
    // 2. 匿名代码块:赋初始值
    {
        System.out.println("匿名代码块");
    }
    // 1. 静态代码块:只加载一次
    static {
        System.out.println("静态代码块");
    }
    // 3. 构造方法
    public Person() {
        System.out.println("构造方法");
    }

    public static void main(String[] args) {
        Person person = new Person();
        System.out.println("======================");
        Person person1 = new Person();
    }
}
  • 执行顺序:静态代码块 --> 匿名代码块 --> 构造方法
    静态代码块只会执行一次。
  • static 静态导入包
package com.xxx.oop.demo10;
// 静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
    public static void main(String[] args) {
        System.out.println(random());   // 导入后直接调用
        System.out.println(PI);   // 导入后直接调用
    }
}

7. 抽象类和接口

抽象类

  • abstract 修饰符可以用来修饰方法,也可以修饰类,如果修饰方法,那么该方法就是抽象方法,如果修饰类那么该类,就是抽象类。
  • 抽象类中可以没有抽象方法,但是 有抽象方法的类,一定要声明为抽象类
  • 抽象类,不能使用 new 关键字,来创建对象,它是 用来让子类继承的
  • 抽象方法只有方法的声明,没有方法的实现。它是 用来让子类实现的
  • 子类继承抽象类,就必须要实现抽象类,没有实现的抽象方法,否则该子类也要声明为抽象类。
  • 创建抽象类:
package com.xxx.oop.demo11;

// abstract 抽象类: 类继承 extends 单继承 (接口可以实现多继承)
public abstract class Action {
    // 约束,有人帮我们实现
    // abstract 抽象方法,只有方法名,没有方法的实现
    public abstract void doSomething();
    // 抽象类中可以存在普通的方法
    public void run(){
        System.out.println("抽象类中的普通方法");
    }
}
  • 抽象类的子类:必须实现父类的方法(重写),除非子类也是抽象类
package com.xxx.oop.demo11;

// 抽象类的所有方法,继承它的子类都必须实现它的方法(重写),除非子类也是抽象类
public class A extends Action{
    // 重写父类的抽象方法
    @Override
    public void doSomething() {
    }
}
  • 抽象类的特点:
    1. 不能 new 这个抽象类,只能依靠子类去实现;约束!!
    2. 抽象类中可以写普通方法;
    3. 抽象方法必须在抽象类中。

接口

  • 普通类:只有具体实现;
  • 抽象类:具体实现和规范(抽象方法)都有!
  • 接口:只有规范!无法自己写方法 (专业的约束,约束和实现分离:面向接口编程)
  • 接口就是规范,定义的是一组规则,体现了现实世界中 如果你是…则必须能… 的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。
  • 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
  • OO 的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如 c++、java、c# 等),就是因为设计模式所硏究的,实际上就是如何合理的去抽象。
  • 声明类的关键字是 class,声明接口的关键字是 interface
  • 创建 UserService 接口:interface
package com.xxx.oop.demo12;

// interface 接口定义关键字 接口都需要有实现类
public interface UserService {
    // 常量(一般不这样用):默认:public static final
    int AGE=99;

    // 接口中的定义的方法都是抽象的,默认: public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}
  • 创建 TimeService 接口
package com.xxx.oop.demo12;

public interface TimeService {
    void timer();
}
  • 创建实现 UserService,TimeService 两个接口的类(多继承)
package com.xxx.oop.demo12;
// 类实现接口 interface
// 实现了接口的类,就必须实现接口中的方法 快捷键:Ctrl + I
// 通过接口实现多继承 UserService,TimeService
public class UserServiceImpl implements UserService,TimeService{
    @Override
    public void add(String name) {
    }
    @Override
    public void delete(String name) {
    }
    @Override
    public void update(String name) {
    }
    @Override
    public void query(String name) {
    }
    @Override
    public void timer() {
    }
}

接口总结:

  • 约束,规范
  • 定义一些方法,让不同的人实现
  • 接口方法(默认):public abstract
  • 接口常量(默认):public static final
  • 接口不能被实例化,因为接口中没有构造方法
  • 类通过 implements 可以实现多个接口(多继承)
  • 实现接口的类,必须要重写接口中的方法
  • 实现接口的类名称:一般是在接口名后面加 Impl,如:接口UserService,实现类 UserServiceImpl
  • 接口方法重写:快捷键:Ctrl + I

8. 内部类及 OOP 实战

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

    1. 成员内部类
    package com.xxx.oop.demo13;
    
    // 外部类
    public class Outer {
        private int id = 10;
    
        public void out() {
            System.out.println("外部类方法");
        }
    
        // 内部类
        public class Inner {
            // 内部方法
            public void in() {
                System.out.println("内部类方法");
            }
            // 内部方法,获取外部类私有属性
            public void getId(){
                System.out.println(id);
            }
            public void getOut(){
                // 调用外部方法
                out();
            }
        }
    }
    
    package com.xxx.oop;
    
    import com.xxx.oop.demo13.Outer;
    
    // 测试类
    public class Application {
        public static void main(String[] args) {
            // 外部类实例
            Outer outer = new Outer();
            // 通过外部类实例化内部类
            Outer.Inner inner = outer.new Inner();
            inner.in();
            inner.getId();
            inner.getOut();
        }
    }
    
    1. 静态内部类:无法直接访问外部类非静态属性和方法,需要通过外部类的实例来访问

      package com.xxx.oop.demo13;
      
      // 外部类
      public class Outer {
          private int id;
      
          public void out() {
              System.out.println("外部类方法");
          }
      
          // 静态内部类
          public static class Inner {
              // 内部方法
              public void in() {
                  System.out.println("内部类方法");
              }
          }
      }
      
    2. 局部内部类:外部类方法中创建

      package com.xxx.oop.demo13;
      
      // 外部类
      public class Outer {
         public void method(){
             // 局部内部类
             class Inner{
                 public void in(){
                     System.out.println("局部内部类");
                 }
             }
         }
      }
      
    3. 匿名内部类

      package com.xxx.oop.demo13;
      
      public class Test {
          public static void main(String[] args) {
              // 匿名内部类:没有名字初始化类,不用将实例保存到变量中
              new Apple().eat();
      
              // 默认会返回 UserService userService
              new UserService() {
                  // 重写接口的方法
                  @Override
                  public void hello() {
                      System.out.println("重写接口方法");
                  }
              };
          }
      }
      
      class Apple {
          public void eat() {
              System.out.println("1");
          }
      }
      
      interface UserService{
          void hello();
      }
      

你可能感兴趣的:(Java 基础 05. Java 面向对象)