面向对象进阶
本章主要学习内容:
- static
- 继承
- 包,final,权限修饰符,代码块
- 抽象类
- 接口
- 多态
- 内部类
1. static
- static翻译过来就是静态的意思
- static表示静态,是java中的一个修饰符,可以修饰成员方法,成员变量
- 被static修饰的成员变量,叫做静态变量 
  - 特点: 
    - 被该类所有对象共享
- 不属于对象,属于类
- 随着类的加载而加载,优先于对象存在
 
 
- 特点: 
    
- 被static修饰的成员方法,叫做静态方法 
  - 特点: 
    - 多在测试类和工具类中
- javabean类中很少会用
 
 
- 特点: 
    
- 调用方式: 
  - 类名调用(推荐)
- 对象名调用
 
需求:写一个javaBean类来描述班级的学生
- 属性:姓名,年龄,性别
- 行为:学习逆向
public class Test {
    public static void main(String[] args) {
        // 创建两个学生对象
        Student.teacherName = "刘老师";
        Student s1 = new Student();
        s1.setName("小明");
        s1.setAge(10);
        s1.setGender("男");
        s1.show();
        s1.study();
        System.out.println("==========================");
        Student s2 = new Student();
        s2.setGender("女");
        s2.setAge(12);
        s2.setName("小红");
        s2.show();
        s2.study();
    }
}
// 学生类
class Student{
    // 属性: 姓名,年龄,性别
    // 新增属性: 老师的姓名
    private String name;
    private int age;
    private String gender;
    // 使用static修饰后,Student类中所有对象都共享teacherName
    public static String teacherName;
    public Student() {
    }
    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    /**
     * 获取
     * @return gender
     */
    public String getGender() {
        return gender;
    }
    /**
     * 设置
     * @param gender
     */
    public void setGender(String gender) {
        this.gender = gender;
    }
    // 重写toString方法
    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
    }
    // 行为: 学习方法
    public void study(){
        System.out.println(name + "正在学习");
    }
    // 输出学生信息
    public void show(){
        System.out.println(name + ", " + age + ", " + gender + ", " + teacherName);
    }
}
工具类
类的分类

工具类的定义规范:
- 类名见名知意
- 私有化构造方法
- 方法都定义为静态的,方便调用
示例代码:
需求:在时机开发中,经常会遇到一些数组使用的工具类,按照以下要求编写一个数组的工具类: ArrayUtil
- 提供一个工具类方法printArr,用于返回整数数组的内容 
  - 返回的字符串格式如:[10,20,30,40]
 
- 提供一个工具方法 getAerage,用于返回平均分
- 定义一个测试类TestDemo,调用工具类的工具方法
public class Test {
    public static void main(String[] args) {
        int[] arr1 = {1,2,3,4,5,6};
        String s = ArrayUtil.printArr(arr1);
        System.out.println(s); // [1, 2, 3, 4, 5, 6]
        System.out.println("========================");
        double[] arr2 = {1.1,22.2,33.3,44.4};
        double average = ArrayUtil.getAverage(arr2);
        System.out.println(average);
    }
}
// ArrayUtil工具类
class ArrayUtil{
    // 私有化构造方法
    // 目的: 为了不让外界创建他的对象
    private ArrayUtil(){}
    // 定义静态方法,方便使用
    public static String printArr(int[] arr){
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < arr.length; i++) {
            // i 索引 arr[i] 元素
            if(i == arr.length - 1){
                sb.append(arr[i]);
            }else{
                sb.append(arr[i]).append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }
    public static double getAverage(double[] arr){
        double sum = 0;
        for (int i = 0; i < arr.length; i++) {
            sum = sum + arr[i];
        }
        return sum / arr.length;
    }
}示例代码:
需求:定义一个集合,用于存储3个学生对象
- 学生类的属性为:name,age,gender
- 定义一个工具类,用于获取集合中最大学生的年龄
import java.util.ArrayList;
public class Test {
    public static void main(String[] args) {
        // 1. 创建一个集合,用来存储学生对象Student
        ArrayList<Student > list = new ArrayList<>();
        // 2.创建3个学生对象
        Student stu1 = new Student("小明",1,"男");
        Student stu2 = new Student("小红",12,"女");
        Student stu3 = new Student("小芳",16,"女");
        // 3.把学生对象,添加到集合中
        list.add(stu1);
        list.add(stu2);
        list.add(stu3);
        // 计算集合中年龄最大的学生
        int studentAgeMax = StudentUtil.getStudentAgeMax(list);
        System.out.println("最大学生的年龄: " + studentAgeMax);
    }
}
// 学生类(标准的javaBean类)
class Student{
    private String name;
    private int age;
    private String gender;
    public Student() {
    }
    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    /**
     * 获取
     * @return gender
     */
    public String getGender() {
        return gender;
    }
    /**
     * 设置
     * @param gender
     */
    public void setGender(String gender) {
        this.gender = gender;
    }
    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
    }
}
// 定义一个工具类,用于获取最大学生的年龄
class StudentUtil{
    private StudentUtil(){}
    // 静态方法
    public static int getStudentAgeMax(ArrayList<Student> list){
        //1.定义一个参照物
        int max = list.get(0).getAge();
        for (Student student : list) {
            int age = student.getAge();
            if (age > max){
                max = age;
            }
        }
        return max;
    }
}
static注意事项
- 静态方法中,只能访问静态
- 非静态方法,可以访问所有
- 静态方法中没有this关键字
2. 继承
- 继承是面向对象三大特征之一
 
- java中提供了一个关键字 extends,用这个关键字,可以让一个类和另一个类建立起继承关系 
  - public class Student extends Person{}
- Student称为子类(派生类), Person称为父类(基类或超类)
 
- 使用继承的好处: 
  - 可以把多个子类重复的代码抽取到父类中,提高代码的复用性
- 子类可以在父类的基础上,增加其他的功能,使子类更强大
 
- 什么时候使用到继承? 
  - 当类与类之间,存在相同(共性)的内容,并满足子类是父类中的哪一种,就可以考虑使用继承,来优化代码
 
- 继承需要学习的点: 
  - 编写自己的父类,使用子类继承
- 继承已经写好的父类
 
- 继承的特点: 
  - java只支持单继承,不支持多继承,但支持多层继承
 
示例代码:
public class Test {
    public static void main(String[] args) {
        // 创建对象并调用方法
        Ragdoll ragdoll = new Ragdoll();
        ragdoll.eat();
        ragdoll.drink();
        ragdoll.catchMouse();
    }
}
// 动物类(父类)
class Animal{
    public void eat(){
        System.out.println("吃饭");
    }
    public void drink(){
        System.out.println("喝水");
    }
}
// 猫类
class Cat extends Animal{
    public void catchMouse(){
        System.out.println("猫在抓老鼠");
    }
}
// 狗类
class Dog extends Animal{
    public void lookHome(){
        System.out.println("狗看家");
    }
}
// 布偶猫
class Ragdoll extends Cat{
}
// 狸花猫
class LiHuaMao extends Cat{
}
// 哈士奇
class Husky extends Dog{
    public void breakHome(){
        System.out.println("哈士奇在拆家");
    }
}
// 泰迪
class Teddy extends Dog{
    public void touch(){
        System.out.println("泰迪又在蹭腿");
    }
}
继承中的成员变量和成员方法访问特点
继承中成员变量的访问特点
- 通过this关键字,访问自身类上的属性
- 通过super关键字,访问父类上的属性

小结:
- 继承中成员变量的访问特点:就近原则 
  - 先在局部位置找,本类成员位置找,父类成员位置找,逐级往上
 
- 如果出现重名的成员变量怎么办? 
继承中成员方法的访问特点,和成员变量访问特点一样
方法的重写
- 当父类的方法不能满足子类现在的需求时,需要进行方法重写
- 方法重写格式: 
  - 在继承体系中,子类出现了和父类一模一样的方法声明,就称子类这个方法是重写的方法
- @Override重写注解:@Override是放在重写后的方法上,校验子类重写时语法是否正确
 
示例代码:
public class Test {
    public static void main(String[] args) {
        XM xm = new XM();
        xm.jn();
    }
}
class Person{
    public void jn(){
        System.out.println("java");
    }
}
class XM extends Person{
    // 重写父类的jn方法
    // 注意: 子类重写父类的方法需要在方法上加上 @Override
    @Override
    public void jn(){
        System.out.println("逆向");
    }
}方法重写注意事项和要求:
继承中的构造方法
构造方法的访问特点:
小结:

3. 多态
基本使用

示例代码:
public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        student.setName("小明");
        student.setAge(10);
        Teacher teacher = new Teacher();
        teacher.setName("王老师");
        teacher.setAge(32);
        Administrator administrator = new Administrator();
        administrator.setAge(53);
        administrator.setName("管理员");
        register(student);
        register(teacher);
        register(administrator);
    }
    // 注册
    // 这个方法即能接收老师,又能接收学生,又能接收管理员
    public static void register(Person p){
        p.show();
    }
}
// 父类
class Person{
    private String name;
    private int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Person{name = " + name + ", age = " + age + "}";
    }
    public void show(){
        System.out.println(name + ", " + age);
    }
}
// 学生类(子类) 基础 父类
class Student extends  Person{
    // 重写父类方法
    @Override
    public void show(){
        System.out.println("学生的信息为: " + getName() + ", " + getAge());
    }
}
// 老师类(子类) 基础 父类
class Teacher extends  Person{
    // 重写父类方法
    @Override
    public void show(){
        System.out.println("老师的信息为: " + getName() + ", " + getAge());
    }
}
// 管理员类(子类) 基础 父类
class Administrator extends  Person{
    // 重写父类方法
    @Override
    public void show(){
        System.out.println("管理员的信息为: " + getName() + ", " + getAge());
    }
}小结:

多态调用成员的特点
- 变量调用:编译看左边,运行也看左边
- 方法调用:编译看左边,运行看右边
示例代码:
public class Test {
    public static void main(String[] args) {
        // 创建对象(多态的方式创建)
        Animal cat = new Cat();
        // 多态中调用成员变量: 编译看左边,运行也看左边
        // 编译看左边: javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有就编译失败
        // 运行也看左边: java运行代码的时候,实际获取的是左边父类中成员变量的值
        System.out.println(cat.name); // 调用的是父类的name
        // 多态中调用成员方法: 编译看左边,运行看右边
        // 编译看左边: javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有就编译失败
        // 运行看右边: java运行代码的时候,实际上是运行子类中的方法
        cat.show(); // Cat-show方法
    }
}
class Animal{
    String name = "动物";
    public void show(){
        System.out.println("Animal-show方法");
    }
}
class Cat extends Animal{
    String name = "猫";
    @Override
    public void show(){
        System.out.println("Cat-show方法");
    }
}
class Dog extends Animal{
    String name = "狗";
    @Override
    public void show(){
        System.out.println("Dog-show方法");
    }
}
多态的优势和弊端

多态的练习
需求:
代码:
public class Test {
    public static void main(String[] args) {
        // 创建对象并调用方法
        Person p1 = new Person("老王",30);
        Dog dog = new Dog(2,"黑");
        p1.keepPet(dog,"骨头");
        System.out.println("========================");
        Cat cat = new Cat(10,"白");
        p1.keepPet(cat,"鱼");
    }
}
// 动物的父类(将猫和狗的共性包装到父类中)
class Animal{
    // 属性
    private int age;
    private String color;
    public Animal() {
    }
    public Animal(int age, String color) {
        this.age = age;
        this.color = color;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    /**
     * 获取
     * @return color
     */
    public String getColor() {
        return color;
    }
    /**
     * 设置
     * @param color
     */
    public void setColor(String color) {
        this.color = color;
    }
    public String toString() {
        return "Animal{age = " + age + ", color = " + color + "}";
    }
    /**
     * 吃东西的方法
     * @param something
     */
    public void eat(String something){
        System.out.println("动物再吃" + something);
    }
}
// 狗类
class Dog extends Animal{
    // 空参构造
    public Dog() {
    }
    // 带父类全部参数的构造
    public Dog(int age,String color) {
        super(age,color);
    }
    // 重写父类的eat方法
    @Override
    public void eat(String something) {
        System.out.println(getAge() + "岁 " + getColor() +"颜色的狗在吃" + something );
    }
    // 狗特有的方法
    public void lookHome(){
        System.out.println("狗看家");
    }
}
// 猫类
class Cat extends Animal{
    // 空参构造
    public Cat() {
    }
    // 带父类全部参数的构造
    public Cat(int age,String color) {
        super(age,color);
    }
    @Override
    public void eat(String something) {
        System.out.println(getAge() + "岁 " + getColor() +"颜色的猫在吃" + something );
    }
    // 猫特有的方法
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}
// 饲养员
class Person{
    private String name;
    private int age;
    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Person{name = " + name + ", age = " + age + "}";
    }
    public void keepPet(Animal a,String something){
        if(a instanceof Dog d) {
            System.out.println("年龄为" + age + "岁的" + name + "养了一只" + a.getColor() + "颜色的" + a.getAge() + "岁的" + "狗");
            a.eat(something);
        } else if (a instanceof Cat d) {
            System.out.println("年龄为" + age + "岁的" + name + "养了一只" + a.getColor() + "颜色的" + a.getAge() + "岁的" + "猫");
            a.eat(something);
        }else{
            System.out.println("没有这种动物");
        }
    }
}
4. 包
什么是包?
- 包就是文件夹。用来管理各种不同功能的java类,方便后期维护
- 包名的规则:域名反写+包的作用,需要全部英文小写,见名知意。 
  - 例如: 
    - 域名为:spider.github.com
- 包那么就命名为:com.github.spider
 
 
- 例如: 
    
使用规则:
- 在com.spider.github 软件包下软件一个名为Student的类 
- 在Test类中通过import关键字引用Student类 
小结:

5. final关键字
- final表示是最终的,不能被改变的
- final可以修饰,方法,类,变量
- 被final修饰的方法,表示该方法是最终方法,不能被重写 
  - 应用场景:当父类中定义的一些方法不希望别人(子类)去改变,就可以使用final修饰
 
- 被final修饰的类,表示该类是最终类,不能被继承 
  - 应用场景: 
    - 安全性:如果一个类的实现已经是完整和安全的,不希望被其他类继承并改变其行为,则可以将该类声明为final。这样可以确保该类的行为不会被修改或者被继承后导致不安全的变化
 
 
- 应用场景: 
    
- 被final修饰的变量,叫常量,只能被赋值一次 
  - 应用场景,当不想变量发生改变时,可以使用final修饰
 
示例代码:
- 被final修饰的方法,表示该方法是最终方法,不能被重写 
- 被final修饰的类,表示该类是最终类,不能被继承 
- 被final修饰的变量,叫常量,只能被赋值一次 
6. 常量
- 实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性
- 常量的命名规范: 
  - 单个单词:全部大写
- 多个单词:全部大写,单词之间用下划线隔开
 
- 细节: 
  - final修饰的变量是基本类型:那么变量存储的数据值不能发送改变
- final修饰的变量是引用类型:那么变量存储的地址值不能发送改变,对象内部可以改变
 
示例代码:
public class Test {
    public static void main(String[] args) {
        // final修饰的变量是基本类型:记录的值不能发生改变
        final double  PI = 3.14;
        // final修饰的变量是引用类型:记录的地址值不能发生改变,内部的属性值还是可以改变的
        final Student S = new Student("小红",13);
        // 记录的地址值不能发生改变
        // S = new Student(); // 报错
        // 内部的属性值还是可以改变的
        S.setAge(100);
        S.setName("小芳");
        System.out.println(S.getName() + ", " + S.getAge());
    }
}
class Student{
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}7. 权限修饰符
- 权限修饰符:是用来控制一个成员能够被访问的范围的
- 权限修饰符可以修饰:成员变量,方法,构造方法,内部类
- 权限修饰符的分类:有4种 
  - 权限修饰符四种范围由大到小:public > protected > default > private。 
- public:public 修饰的成员变量和方法可以被任何类访问。如果一个类是 public 类,那么这个类所在的源文件的文件名必须与类名相同
- protected:protected 修饰的成员变量和方法可以被同一类、同一包内的类以及其他包中的子类
- default:默认的权限修饰符,即不写任何修饰符。同一包内的类可以访问 default 修饰的成员变量和方法,不同包内的类不能访问。
- private:private 修饰的成员变量和方法只能被同一类内的方法访问,其他类无法直接访问。
 
- 权限修饰符四种范围由大到小:public > protected > default > private。
- 权限修饰符的使用规则: 
  - 实际开发中,一般只用private和public 
    - 成员变量私有
- 方法公开
- 特例:如果方法中的代码是抽取其他方法中共性代码,这个方法一般也私有
 
 
- 实际开发中,一般只用private和public 
    
8. 代码块
- 局部代码块: 
- 构造代码块: 
- 静态代码块: 
  - 格式:static {}
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次
- 使用场景:在类加载的时候,做一些数据初始化的时候使用 
 
小结:
9. 抽象类与抽象方法
- 抽象方法:将共性的行为(方法)抽取到父类之后,由于每一个子类执行的内容是不一样的,所以,在父类中不能确定具体的方法体。该方法就可以定义为抽象方法。
- 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类
- 抽象类和抽象方法的定义格式: 
  - 抽象方法语法格式:public abstract 返回值类型 方法名(参数列表);
- 抽象类语法格式:public abstract class 类名{}
 
- 注意事项: 
  - 抽象类不能创建对象
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
- 抽象类可以有构造方法
- 抽象类的子类: 
    - 要么重写抽象类中的所有抽象方法
- 要么是抽象类
 
 
  
练习:
public class Test {
    public static void main(String[] args) {
        // 创建对象
        Frog frog = new Frog("小青蛙",1);
        frog.drink();
        frog.eat();
    }
}
// 抽象类(父类)
abstract class Animal{
    private String name;
    private int age;
    public Animal() {
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Animal{name = " + name + ", age = " + age + "}";
    }
    public void drink(){
        System.out.println(getName() + "在喝水");
    }
    // 抽象方法
    public abstract void eat();
}
// 青蛙-子类
class Frog extends Animal{
    public Frog() {
    }
    public Frog(String name, int age) {
        super(name,age);
    }
    // 实现父类的抽象方法
    @Override
    public void eat() {
        System.out.println("青蛙吃虫子");
    }
}
// 狗-子类
class Dog extends Animal{
    public Dog() {
    }
    public Dog(String name,int age) {
        super(name,age);
    }
    @Override
    public void eat() {
        System.out.println("狗吃屎");
    }
    public String toString() {
        return "Dog{}";
    }
}
// 山羊-子类
class Sheep extends Animal{
    public Sheep() {
    }
    public Sheep(String name,int age) {
        super(name,age);
    }
    @Override
    public void eat() {
        System.out.println("山羊吃草");
    }
}
小结:
10. 接口
接口的定义和使用
- 接口用关键字interface来定义:public interface 接口名称 {}
- 接口不能实例化
- 接口和类之间是实现关系,通过 implements 关键字表示:public class 类名 implements 接口名称 {}
- 接口的子类(实现类) 
  - 要么重写接口中的所有抽象方法
- 要么是抽象类
 
- 注意1:接口和类的实现关系,可以单实现,也可以多实现 
  - public class 类名 implements 接口1,接口2 {}
 
- 注意2:实现类还可以在继承一个类的同时实现多个接口 
  - public class 类名 extends 父类 implements 接口名1,接口名2 {}
 
练习:
public class Test {
    public static void main(String[] args) {
        // 创建青蛙的对象
        Frog frog = new Frog("小青蛙",1);
        frog.eat();
        frog.swim();
    }
}
/*
 * 接口
 * */
interface Swim {
    public abstract void swim();
}
/*
* 父类-动物
* */
abstract class Animal{
    private String name;
    private int age;
    public Animal() {
    }
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    /**
     * 获取
     * @return name
     */
    public String getName() {
        return name;
    }
    /**
     * 设置
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * 获取
     * @return age
     */
    public int getAge() {
        return age;
    }
    /**
     * 设置
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }
    public String toString() {
        return "Animal{name = " + name + ", age = " + age + "}";
    }
    // 吃的-行为
    public abstract void eat();
}
/*
* 兔子-子类
* */
class Rabbit extends Animal{
    public Rabbit() {
    }
    public Rabbit(String name,int age) {
        super(name,age);
    }
    @Override
    public void eat() {
        System.out.println(getName() + "吃胡萝卜");
    }
}
/*
* 狗类-子类
* */
class Dog extends Animal implements Swim{
    public Dog() {
    }
    public Dog(String name,int age) {
        super(name,age);
    }
    @Override
    public void eat() {
        System.out.println(getName() + "吃骨头");
    }
    // 实现Swim接口的swim方法
    @Override
    public void swim() {
        System.out.println(getName() + "狗刨式游泳");
    }
}
/*
* 青蛙-子类
* */
class Frog extends Animal implements Swim{
    public Frog() {
    }
    public Frog(String name,int age) {
        super(name,age);
    }
    @Override
    public void swim() {
        System.out.println(getName() + "蛙泳");
    }
    @Override
    public void eat() {
        System.out.println(getName() + "吃虫子");
    }
}接口中成员的特点
- 成员变量 
  - 只能是常量
- 默认修饰符:public static final
 
- 构造方法 
  - 接口中没有构造方法
 
- 成员方法 
  - 只能是抽象方法
- 默认修饰符:public abstract
- jdk7以前:接口中只能定义抽象方法
- jdk8的新特性:接口中可以定义有方法体的方法
- jdk9的新特性:接口中可以定义私有方法
 
接口和类之间的关系
- 类和类之间的关系 
  - 继承关系,只能单继承,不能多继承,但是可以多层继承
 
- 类和接口的关系 
  - 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
 
- 接口和接口的关系 
  - 继承关系,可以单继承,也可以多继承
 
11. 内部类
初始内部类
内部类的分类:
- 成员内部类:了解
- 静态内部类:了解
- 局部内部类:了解
- 匿名内部类:需要掌握
什么是内部类?
- 就是在一个类的里面,在定义一个类。 
  - 举例:在A类的内部定义B类,B类就被称为内部类 
 
- 举例:在A类的内部定义B类,B类就被称为内部类
为什么要学习内部类?
- 需求:写一个javabean类描述汽车
- 属性:汽车的品牌,车龄,颜色,发动机的品牌,使用年限 
小结:
匿名内部类
- 匿名内部类本质上就是隐藏了名字的内部类
- 语法格式:new 类名或者接口名(){ 重写方法; };
示例代码:
public class Test {
    public static void main(String[] args) {
        // 编写匿名内部类的代码
        new Swim() {
            // 重写方法
            @Override
            public void swim() {
                System.out.println("重写了游泳的方法");
            }
        };
    }
}
interface Swim {
    public abstract void swim();
}
小结:











