03-面向对象

面向对象

面对对象相关概述详解:

1.什么是面向过程?
	它是一种编程思想,强调是以 过程 为基础完成各种操作,每一步都要亲力亲为。
    代表语言C语言
    
2.什么是面向对象?
	它是一种编程思想,强调是以 对象 为基础完成各种操作,把事情交给对象做,我们负责管理对象即可。
	代表语言Java。
	
	思想特点:
		1.把复杂的事情简单化。
		2.更符合人们的思考习惯。
		3.把程序员从执行者变成指挥者。
  • Java语言是用来描述现实世界事物的, 最基本的单位是: 类。
    • **类:**是一个抽象的概念, 看不见, 也摸不着, 它是属性和行为的集合.
    • **对象:**类的具体 体现和实现.
    • 属性:就是用来描述事物外在特征的(名词)也叫成员变量, 和以前定义变量类似, 现在先写到 类中, 方法外, 而且成员变量有默认值.
    • 行为:就是用来指事物能够做什么(动词)也叫成员方法,,和以前定义方法类似, 先不写static.

类的实现

1.如何实现一个类?

public class 类名{
	//属性:名词,也叫成员变量
    
    //行为:动词,也叫成员方法
}

2.如何使用类中的成员?
   类名 对象名 = new 类名();
	然后通过 对象.的方式调用即可。
    
3.例如:
    Student s = new Student(); 	//创建学生对象
	s.study();		//学生在学习,即:调用Student#study()方法。

  • 案例:学生类
    • 用来描述手机的(属性, 行为),像这样的用来描述事物的类叫: 实体类, 也叫: JavaBean类, POJO类.
public class Student {
    //属性(成员变量):  姓名, 年龄, 性别
    String name;        //姓名
    int age;            //年龄
    String sex;         //性别

    //行为(成员方法): 学习, 吃饭, 睡觉
    public void study() {
        System.out.println("好好学习, 天天向上!");
    }

    public void eat() {
        System.out.println("为了保持精力, 要按时吃饭.");
    }

    public void sleep() {
        System.out.println("为了保持精力, 要按时睡觉.");
    }
  • 案例:学生类的测试类

    • 概述: 所谓的使用类, 就是使用类中的成员(成员变量和成员方法)

      格式:
          1. 创建该类的对象.
              类名 对象名 = new 类名();
              
          2. 通过 对象名. 的形式来使用类中的成员.
              对象名.成员变量
              对象名.成员方法(参数1, 参数2)
      
package com.itheima.demo01_quickstart;

//案例: 学生类的测试类
/*
    概述: 所谓的使用类, 就是使用类中的成员(成员变量和成员方法)

    格式:
        1. 创建该类的对象.
            类名 对象名 = new 类名();
        2. 通过 对象名. 的形式来使用类中的成员.
            对象名.成员变量
            对象名.成员方法(参数1, 参数2)
 */
public class StudentTest {
    public static void main(String[] args) {
        //需求: 使用学生类中的成员.
        //1. 创建学生类的对象.
        Student s = new Student();

        //2. 访问成员变量.
        //String name = s.name;       //把成员变量name的值, 赋值给局部变量name
        System.out.println(s.name);   //null
        System.out.println(s.age);    //0
        System.out.println(s.sex);    //null
        System.out.println("------------------");

        //3. 给成员变量赋值
        s.name = "刘亦菲";
        s.age = 33;
        s.sex = "女";
        //4. 打印成员变量值.
        System.out.println(s.name);   //刘亦菲
        System.out.println(s.age);    //33
        System.out.println(s.sex);    //女
        System.out.println("------------------");

        //5. 访问成员方法
        s.study();
        s.eat();
        s.sleep();
    }
}
  • 案例: 定义手机类
package com.itheima.demo02_phone;

//案例: 定义手机类, 用来描述手机的(属性, 行为), 像这样的用来描述事物的类叫: 实体类, 也叫: JavaBean类, POJO类.
public class Phone {
    // 属性: 也叫成员变量, 就是用来描述事物的外在特征的(即: 名词)
    String brand;           //品牌
    int price;              //价格
    String color;           //颜色

    // 行为: 打电话(call), 发短信(sendMessage)
    //打电话
    public void call(String name) {   //夯哥
        System.out.println("给" + name + "打电话!...");
    }

    //发短信
    public void sendMessage(String name) {
        System.out.println("给" + name + "发短信!...");
    }
}

  • 手机类的测试类
package com.itheima.demo02_phone;

//案例: 手机类的测试类.
public class PhoneTest {
    //main方法是程序的主入口, 所有的代码都是从这里开始执行的.
    public static void main(String[] args) {
        //1. 创建手机类的对象.
        Phone p = new Phone();
        //2. 设置成员变量值.
        p.brand = "华为";
        p.price = -5999;
        p.color = "黑色";

        //3. 打印成员变量值.
        System.out.println(p.brand);
        System.out.println(p.price);
        System.out.println(p.color);

        //4. 调用成员方法
        p.call("夯哥");
        p.sendMessage("夯哥");
    }
}

成员变量和局部变量

概述和区别
  • 概述:
    成员变量: 定义在类中, 方法外的变量.
    局部变量: 定义在方法中, 或者方法声明上的变量.

  • 区别:

    • 1)定义位置不同.
      成员变量:定义在类中, 方法外的变量.
      局部变量:定义在方法中, 或者方法的形参上的变量.
    • 2)在内存中的存储位置不同.
      成员变量: 存储在堆内存.
      局部变量: 存储在栈内存.
    • 3)生命周期不同.
      成员变量: 随着对象的创建而存在, 随着对象的消失而消失.
      局部变量: 随着方法的调用而存在, 随着方法的调用完毕而消失.
    • 4)初始化值不同.
      成员变量:有默认值.
      例如:
      String: null
      int: 0
      double: 0.0
      局部变量:没有默认值, 必须先定义, 再赋值, 然后才能使用.
  • 案例: 演示成员变量和局部变量的区别

package com.itheima.demo03_variable;

//案例: 演示成员变量和局部变量的区别.

public class VariableDemo {
    //成员变量
    int x;

    public void show() {
        //局部变量
        //int y;            //这样写会报错, 因为局部变量没有默认值.
        int y = 20;
        System.out.println(x);      //10
        System.out.println(y);      //20
    }
}

  • 案例: 测试类, 用来演示局部变量和成员变量不同的
package com.itheima.demo03_variable;

//案例: 测试类, 用来演示局部变量和成员变量不同的.
public class VariableDemoTest {
    public static void main(String[] args) {
        //需求: 调用VariableDemo#show()方法.
        //1. 创建VariableDemo类的对象.
        VariableDemo vd =  new VariableDemo();
        //2. 调用show()方法.
        vd.show();
    }
}

封装

private关键字

  • 概述:
    它是一个访问权限修饰符, 表示私有的意思,可以修饰类的成员(成员变量和成员方法).

  • 特点:
    被它修饰的内容, 只能在本类中直接使用.

  • 结论:

    1. 封装就是隐藏对象的属性和实现细节, 仅对外提供一个公共的访问方式.
  • 应用场景:
    1.实际开发中,所有的属性都要私有化,即:用private修饰。
    2.实际开发中,我们也会把那些不需要外界直接访问的内容也会用private修饰。

  • 定义学生类 (JavaBean类, 实体类, POJO类)

package com.itheima.demo04_student;

//定义学生类(JavaBean类, 实体类, POJO类)
public class Student {
    //属性, 也叫成员变量, 即: 名词.
    String name;        //姓名.
    private int age;            //年龄

    //针对于被private修饰的变量, 需要对外提供一个公共的访问方式.
    //设置变量age的值.
    public void setAge(int a) {
        //针对于用户录入的值a, 我们可以判断
        if (a >= 0 && a <= 200) {
            //合法年龄, 就设置.
            age = a;
        }
    }
    //获取变量age的值.
    public int getAge() {
        return age;
    }

    //行为, 也叫成员方法, 即: 动词.
    public void show() {
        System.out.println(name + "..." + age);
    }
}

  • 案例: 学生类的测试类
package com.itheima.demo04_student;

//案例: 学生类的测试类

public class StudentTest {
    public static void main(String[] args) {
        //1. 创建学生类的对象.
        Student s = new Student();
        //2. 设置成员变量值.
        s.name = "刘亦菲";
        /*
            下述的代码, 用户是可以直接访问 age成员变量的, 这样做比较危险,
            因为用户可以给该变量设置一些非法值, 这样我们的程序就有可能出问题,
            针对于这种情况, 我们可以通过 private 关键字解决.

            当我们给类的成员变量加上private修饰后, 我们发现一个新问题:
            外界居然无法直接访问 被private修饰的变量了, 该如何解决呢?
                只需要对外提供一个公共的访问方式即可, 让可以可以操作变量.
                1. 可以设置变量的值.
                2. 可以获取变量的值.
         */
        //s.age = -33;
        //以下为: 采用封装后的代码.
        //设置年龄
        s.setAge(-33);

        //获取年龄
        System.out.println(s.getAge());

        //3. 打印成员变量值.
        /*System.out.println(s.name);
        System.out.println(s.age);*/
        //System.out.println(s);      //打印地址值.
        s.show();
    }
}

  • 定义学生类, 用来演示"标准"的类的定义
package com.itheima.demo05_student;

//定义学生类, 用来演示"标准"的类的定义
/*
    实际开发中, 如非必要, 成员变量全部用private修饰, 其他全部用public修饰.
 */
public class Student {
    //属性, 成员变量, 全部用private修饰.
    private String name;        //姓名
    private int age;            //年龄

    //getXxx(), setXxx()
    //设置姓名
    public void setName(String n){
        name = n;
    }
    //获取姓名
    public String getName() {
        return name;
    }

    //设置年龄
    public void setAge(int a) {
        //这里可以做判断, 但是不用做, 因为数据从前端传过来的时候
        //就是已经校验过的, 合法的数据.
        age = a;
    }

    //获取年龄
    public int getAge() {
        return age;
    }

    //行为, 成员方法, 全部用public修饰.
    //学习
    public void study() {
        System.out.println("键盘敲烂, 月薪过万!");
    }

    //吃饭
    public void sleep() {
        System.out.println("为了保持精力,要按时休息!");
    }

}

  • 案例: 学生类的测试类, 用来演示"标准"的类的定义
package com.itheima.demo05_student;

//案例: 学生类的测试类, 用来演示"标准"的类的定义
public class StudentTest {
    public static void main(String[] args) {
        //1. 创建学生类的对象.
        Student s = new Student();
        //2. 设置属性.
        s.setName("刘亦菲");
        s.setAge(-33);

        //3. 打印属性.
        System.out.println(s.getName());
        System.out.println(s.getAge());

        //4. 调用方法.
        s.study();
        s.sleep();
    }
}

this关键字:

  • 概述:
    代表本类当前对象的引用, 即: 谁调用, this就代表谁.

  • 作用:
    用来解决局部变量和成员变量重名问题的.

  • 记忆: 使用变量的原则
    使用变量遵循"就近原则", 局部位置有就使用, 没有就去本类的成员位置找,
    有就使用, 本类没有还会去父类中找.

  • 学生类, 用来演示this关键字的

package com.itheima.demo06_this;

//学生类, 用来演示this关键字的.

public class Student {
    //成员变量
    int x = 10;

    public void method() {
        //局部变量
        int x = 20;
        System.out.println(this.x);         //10
        System.out.println(x);              //20
    }
}

  • 学生类的测试类
package com.itheima.demo06_this;

//学生类的测试类
public class StudentTest {
    public static void main(String[] args) {
        //1. 创建学生类的对象.
        Student s = new Student();
        //2. 调用Student#method()
        s.method();         //this.x -> s.x         10, 20
        System.out.println("-----------");

        //3. 升级版演示: 谁调用, this就代表谁.
        Student s2 = new Student();
        s2.x = 100;
        s2.method();        //this.x -> s2.x        100, 20
    }
}
  • 定义学生类, 用来演示"标准版的JavaBean类的编写
package com.itheima.demo07_student;

//定义学生类, 用来演示"标准版的JavaBean类的编写"
public class Student {
    //属性, 成员变量, 全部私有.
    private String name;        //姓名
    private int age;            //年龄

    //getXxx(), setXxx()
    //设置姓名
    public void setName(String name) {
        this.name = name;
    }
    //获取姓名
    public String getName() {
        //return this.name;       //就近原则.
        return name;              //就近原则, 局部没有, 就去本类的成员位置找.
    }
    //设置年龄
    public void setAge(int age) {
        this.age = age;
    }
    //获取年龄
    public int getAge() {
        return  age;
    }

    //行为, 成员方法
    public void study() {
        System.out.println("键盘敲烂, 月薪过万!");
    }

    public void sleep() {
        System.out.println("为了保持精力学习, 一定要保证充足的睡眠!");
    }
}

  • 案例: 学生类的测试类
package com.itheima.demo07_student;

//案例: 学生类的测试类
public class StudentTest {
    public static void main(String[] args) {
        //1. 创建学生对象.
        Student s = new Student();
        //2. 设置属性.
        s.setName("刘亦菲");
        s.setAge(33);
        //3. 打印属性.
        System.out.println(s.getName());
        System.out.println(s.getAge());

        //4. 调用方法.
        s.study();
        s.sleep();
    }
}

构造方法

  • 作用:
    就是用来创建对象的, 捎带着可以给对象的各个属性赋值.
    大白话解释:就是用来实现, 创建对象的同时, 给该对象的各个成员变量赋值.

  • 特点:

    1. 构造方法名必须和类名完全一致, 包括大小写.

    2. 构造方法没有具体的返回值,返回值的类型、void都不能写.

    3. 构造方法没有具体的返回值, 但是可以写return;因为return是用来结束方法的, 构造方法也算方法, 所以可以有return.

    4. 构造方法可以重载.

    5. 实际开发中,如非必要,建议都要写:空参,全参构造

  • 注意事项

    • 如果我们不给构造方法, 系统会默认给一个空参构造.
    • 如果我们给了构造方法, 系统就不给了.
package cn.itcast.javase.面向对象;

public class Student {
    private String name;
    private int age;

    public Student(){
        System.out.println("空参");
        return;
    }

    public Student(String name,int age){
        this.age = age;
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

  • 学生类的测试类
    • setXxx( ): 用来修改指定对象的指定属性值的, 不会创建新对象.
    • 构造方法:
      用来创建对象的, 捎带着可以给对象的各个属性赋值,
      重复调用构造方法, 会创建新对象.
public class StudentTest {
    public static void main(String[] args) {
        Student s = new Student();

        Student s2 = new Student();
        s2.setName("刘亦菲");
        s2.setAge(33);
        System.out.println(s2.getName() + " " + s2.getAge());   //刘亦菲 33

        Student s3 = new Student("李四", 23);		//调用构造方法并给值
        System.out.println(s3.getName() + " " + s3.getAge());   //李四 23
    }
}

标准的类的定义和使用

标准类的定义格式
    public class 类名{
        //属性, 全部私有

        //构造方法, 空参, 全参.

        //getXxx(), setXxx()

        //行为, 成员方法.
    }
  • 定义一个标准的学生类, 即: JavaBean类, 也叫POJO类.
package com.itheima.demo09_student;

//定义一个标准的学生类, 即: JavaBean类, 也叫POJO类.

public class Student {
    //属性, 全部私有
    private String name;        //姓名
    private int age;            //年龄

    //构造方法, 空参, 全参.
    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //getXxx(), setXxx()
    //关于姓名
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    //关于年龄
    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    //行为, 成员方法.
    public void study() {
        System.out.println("键盘敲烂, 月薪过万!");
    }
}

  • 学生类的测试类
package com.itheima.demo09_student;

//案例: 学生类的测试类
public class StudentTest {
    public static void main(String[] args) {
        //1. 测试空参构造.
        //1.1 创建对象.
        Student s = new Student();
        //1.2 设置属性值.
        s.setName("刘亦菲");
        s.setAge(33);
        //1.3 打印属性值.
        System.out.println("姓名: " + s.getName());
        System.out.println("年龄: " + s.getAge());
        //1.4 调用方法
        s.study();
        System.out.println("-------------------");

        //2. 测试全参构造.
        //2.1 创建对象, 直接给对象的各个属性赋值.
        Student s2 = new Student("赵丽颖", 31);
        //2.2 打印属性值.
        System.out.println("姓名: " + s2.getName());
        System.out.println("年龄: " + s2.getAge());
        //2.3 调用方法
        s2.study();
    }
}

继承

继承概述与案例

  • 概述:

    • 实际开发中, 我们发现好多类中的部分内容是相似的, 每次写很麻烦, 于是我们就想着能不能优化这个问题。
    • 针对于这种情况, 我们可以把这些相似的内容抽取出来, 然后单独的放到一个类中, 然后让 多个类(子类)和这个类(父类)产生关系, 这个关系就叫 继承。
    • Java继承用中,继承用关键字 extends 表示。
  • 格式

  • public class 子类 extends 父类 {
    }
    
  • 好处:

    1. 提高了代码的复用性.
    2. 提高了代码的可维护性.
    3. 让类与类之间产生关系, 是多态的前提.
  • 弊端:让类与类之间产生关系, 也就让类的耦合性增强了.

开发原则:  高内聚, 低耦合.

大白话解释:
	内聚: 指的是类自己独立完成某些事情的能力.
	耦合: 指的是类与类之间的关系.
	接口(干爹)的出现降低了类与类之间的耦合性
  • 人类, 在这里充当的角色是父类.
public class Person {   //ctrl + 字母H: 查看类的继承关系树.
    //属性
    private String name;
    private int age;

    //构造方法, 如果我们不写, 系统会默认加一个: 空参构造.

    //getXxx(), setXxx()
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //行为
    public void eat() {
        System.out.println("人要吃饭");
    }
    public void sleep() {
        System.out.println("人要睡觉");
    }

}

  • 老师类
package com.itheima.demo02_extends;

//案例: 老师类
public class Teacher extends Person {

    //老师类独有的功能: 讲课
    public void teach() {
        System.out.println("老师要讲课!");
    }
}
  • 学生类
package com.itheima.demo02_extends;

//案例: 学生类
public class Student extends Person {

    //学生类独有的功能: 学习
    public void study() {
        System.out.println("好好学习, 天天向上!");
    }
}

  • 测试类
package com.itheima.demo02_extends;

//测试类
public class PersonTest {
    public static void main(String[] args) {
        //1. 测试老师类
        Teacher t = new Teacher();
        //属性
        //从Person类继承.
        t.setName("刘亦菲");
        t.setAge(33);
        System.out.println(t.getName() + "..." + t.getAge());
        //方法
        t.eat();        //从Person类继承.
        t.sleep();      //从Person类继承.
        t.teach();      //本类的独有功能.
        
        //2. 测试学生类, 留给你自己写.
        Student s = new Student();
        s.setName("李四");
        s.setAge(32);
        System.out.println(s.getName() + " " + s.getAge());

        s.study();
        s.teach();
        s.eat();
        s.sleep();
    }
}

Java中的继承关系特点

结论:

  1. 在Java中, 类与类之间只能单继承, 不能多继承.
  2. 在Java中, 类与类之间可以多层继承.
  • 案例:
// 爷爷类

public class GrandFather {
    public void grandFatherSay() {
        System.out.println("爷爷都是从孙子过来的. ");
    }
}

// 爸爸类

public class Father extends GrandFather {
    public void fatherSay() {
        System.out.println("爸爸都是从儿子过来的");
    }
}

// 儿子类

public class Son extends  Father {
    public void sonSay() {
        System.out.println("son...");
    }
}

// 儿子测试类
public class SonTest {
    public static void main(String[] args) {
        //1. 创建Son类对象.
        Son s = new Son();
        //2. 调用Son类中成员方法
        s.sonSay();         //Son类本身的方法.
        s.fatherSay();    //从Father类中继承过来的.
        s.grandFatherSay(); //从GrandFather类中继承过来的.
    }
}

继承关系中的成员特点

成员变量特点
“就近原则”
使用变量遵循"就近原则", 局部位置有就使用, 没有就去本类的成员位置找,
有就使用, 没有就去父类的成员位置找, 有就使用, 没有就报错.
    
这里不考虑父类的父类这种情况,因为会一直找下去,直至Object类,如果还没有,就报错。
super关键字简介:
概述:
它表示当前对象的父类的内存空间标识,可以理解为:父类对象的引用,但是严格意义上它不是。
super和this的区别
1.本质不同
	this:	代表本类当前对象的引用。
	super:	代表本类当前对象的父类的内存空间标识
	
2.用法不同
	this.成员变量	调用的本类的变量
	super.成员变量	调用的是父类的成员变量
	
	this(值1,值2....)		访问的是本类的构造方法
	super(值1,值2...)		访问的是父类的构造方法
	
	this.成员方法名(值1,值2.....)	访问的是本类的成员方法
	super.成员方法名(值1,值2.....)	访问的是父类的成员方法

案例:

//父类
public class Father {
    int age = 30;       //父类的成员变量
}

//子类
public class Son extends Father{
    int age = 20;       //本类的成员变量.

    public void show() {
        int age = 10;   //局部变量
        System.out.println(age);                //10
        System.out.println(this.age);          //20
        System.out.println(super.age);        //30
    }
}

//测试类
public class FatherTest {
    public static void main(String[] args) {
       //1. 创建Son类对象.
        Son s = new Son();
        //2. 调用show()方法
        s.show();
    }
}
构造方法的特点
  • 结论
1. 子类中所有的构造方法的第一行默认都有一个 super() 去访问父类的空参构造,为什么这样设计?
	用于子类对象访问父类数据前, 对父类数据进行初始化.
	大白话解释: 即每一个构造方法的第一行都有一个: super()

2. 为什么默认访问的是空参,而不是带参或者全参构造?
	所有的类都直接或者间接继承自Object类, 它里面只有一个空参构造,Object类是所有类的父类.

3. 父类没有空参构造怎么办?
	方式1:可以通过 super(参数)的形式访问父类的带参构造.
	方式2:也可以this(参数)的形式访问本类的其他构造.

但是这样做比较麻烦, 所以我们建议, 永远手动给出空参构造.

4.实际开发中的做法:
	子类的空参构造 -> 父类的空参构造
	子类的全参构造 -> 父类的全参构造
  • 父类
package cn.itcast.javase.继承;

public class Father {
//    public Father() {
        super();        //Object类的
//        System.out.println("Father类的 空参构造 1");
//    }
    public Father(String name,int age){
        super();        //Object类的
        System.out.println("Father类的 全参构造 2");
    }
}

  • 子类
package cn.itcast.javase.继承;

public class Son extends Father {
    public Son() {
//        super();        //初始化父类成员的
        super("王五", 23);
        System.out.println("Son类的 空参构造 3");
    }

    public Son(String name, int age) {
//        super();        //初始化父类成员的
//        super(name, age);
        this();
        System.out.println("Son类的 全参构造 4");
    }
}
  • 测试类
package cn.itcast.javase.继承;

/**
 * @author YULIANG
 */
public class FatherTest {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println("------------");
        Son s2 = new Son("李四", 12);

    }
}
成员方法的特点
  • 特点:
    • 继承关系中, 调用成员方法时, 也遵循"就近原则", 本类中有, 就直接调用,
      本类中没有, 就去父类查找, 有就调用, 没有就报错.
//父类
public class Father {

    public void method(){
        System.out.println("Father method ...");
    }
}

//子类
public class Son extends Father {

    public void method() {
        System.out.println("Son method...");
    }
}

//测试类
public class FatherTest {
    public static void main(String[] args) {
        Son son = new Son();
        son.method();
    }
}

方法重写

  • 概述

    • 子类出现和父类一模一样的方法时, 称为:方法重写.
    • 方法重写要求返回值的数据类型也必须一致.
  • 应用场景

    • 当子类需要沿袭父类的功能,但是功能主体又有自己额外需求的时候,就可以考虑使用方法重写了。
    • 这样沿袭了父类的功能,也加入了自己独有的功能。
  • 注意事项:

      1. 子类重写父类方法时, 要用 @Override 注解修饰.
      1. 父类的私有方法,子类无法重写.
      1. 进行方法重写时,子类方法的访问权限 不能低于 父类方法的访问权限。

      public > protected > 默认 > private

  • 父类

public class Phone {
    public void call(String name) {
        System.out.println("给" + name + "打电话");
    }
}
  • 子类
public class NewPhone extends Phone {
    //重写Phone类的call()方法。
    @Override
    public void call(String name) {
        //沿袭父类的功能
        super.call(name);
        //加入自己独有的需求
        System.out.println("给" + name + "发彩信");
    }
}
  • 测试类
public class PhoneTest {
    public static void main(String[] args) {
        NewPhone p = new NewPhone();
        p.call("李四");
    }
}
继承案例
  • 人类
package com.itheima.demo08_exercise;

//父类, 里边定义的是整个继承体系的: 共性内容.
public class Person {
    //属性.
    private String name;
    private int age;
    //构造方法.

    public Person() {
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    //getXxx(), setXxx()

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //行为.
    public void eat() {
        System.out.println("人要吃饭!");
    }
}

  • 老师类
package com.itheima.demo08_exercise;

//老师类
public class Teacher extends Person{
    //属性.
    //构造方法, 子类的空参访问父类的空参, 子类的全参访问父类的全参.
    public Teacher() {
        super();
    }

    public Teacher(String name, int age) {
        super(name, age);
    }

    //getXxx(), setXxx(), 从父类继承.

    //行为, 这里可以定义本类独有的行为.
    //重写父类的eat()方法
    @Override
    public void eat() {
        System.out.println("老师喝牛肉汤!...");
    }

    //加入老师类独有的功能
    public void teach() {
        System.out.println("老师要激情高涨的讲课, 帮助学员实现高薪就业!...");
    }
}

  • 学生类
package com.itheima.demo08_exercise;

//学生类
public class Student extends Person{
    //属性.
    //构造方法, 子类的空参访问父类的空参, 子类的全参访问父类的全参.
    public Student() {
        super();
    }

    public Student(String name, int age) {
        super(name, age);
    }

    //getXxx(), setXxx(), 从父类继承.

    //行为, 这里可以定义本类独有的行为.
    //重写父类的eat()方法
    @Override
    public void eat() {
        System.out.println("学生吃牛肉!...");
    }

    //加入学生类独有的功能
    public void study() {
        System.out.println("键盘敲烂, 月薪过万!...");
    }
}

  • 测试类
package com.itheima.demo08_exercise;

public class PersonTest {
    public static void main(String[] args) {
        //1. 测试老师类, 空参构造.
        //1.1 创建对象.
        Teacher t1 = new Teacher();
        //1.2 给属性赋值.
        t1.setName("张三");
        t1.setAge(20);
        //1.3 打印属性值.
        System.out.println(t1.getName() + " " + t1.getAge());
        //1.4 调用方法
        t1.eat();
        t1.teach();
        System.out.println("-------------------------");

        //2. 测试老师类, 全参构造.
        //2.1 创建对象, 并给属性赋值.
        Teacher t2 = new Teacher("李四", 23);
        //2.2 打印属性值.
        System.out.println(t2.getName() + " " + t2.getAge());
        //2.3 调用方法
        t2.eat();
        t2.teach();
        System.out.println("-------------------------");

        //1. 测试学生类, 空参构造.
        //1.1 创建对象.
        Student s1 = new Student();
        //1.2 给属性赋值.
        s1.setName("王五");
        s1.setAge(23);
        //1.3 打印属性值.
        System.out.println(s1.getName() + " " + s1.getAge());
        //1.4 调用方法
        s1.eat();
        s1.study();
        s1.teach();
        System.out.println("-------------------------");

        //2. 测试学生类, 全参构造.
        //2.1 创建对象, 并给属性赋值.
        Student s2 = new Student("赵六", 42);
        //2.2 打印属性值.
        System.out.println(s2.getName() + " " + s2.getAge());
        //2.3 调用方法
        s2.eat();
        s2.study();
        s2.teach();
    }
}

多态

概述
  • 同一个事物(或者对象)在不同时刻表现出来的不同状态, 形态.

前提条件:

    1. 要有继承(或者实现)关系.
    1. 要有方法重写,不然多态毫无意义.
    1. 要有父类引用(或者父接口)指向子类对象.
成员访问特点
  • **成员变量:**编译看左,运行看左

    • 编译期间检查左边的类型****是否有该变量,有则编译通过,没有则编译报错。
    • 运行期间具体用的是左边类中的该变量
  • **成员方法:**编译看左,运行看右

    • 编译期间检查左边的类型是否有该方法,有则编译通过,没有则编译报错。
    • 运行期间具体用的是右边类中的 该方法

总结:

​ 只有成员方法是编译看左,运行看右,其他都是编译运行看左,

​ 因为只有成员方法有方法重写。

  • 案例
//父类
public class Animal {
    int age = 20;
    public void eat() {
        System.out.println("动物要吃饭");
    }
}

//子类
public class Cat extends Animal {
    int age = 30;
    @Override
    public void eat() {
        System.out.println("猫要吃鱼");
    }
}

//测试类
public class AnimalTest {
    public static void main(String[] args) {

        //猫是猫,这个是 自己(本类)指向自己(本类的对象),不是多态
        Cat c = new Cat();
        c.eat();

        System.out.println("-----------------");

        //Cat c2 = new Animal();    //动物是猫,这句话是错误的

        //猫是动物,这个才是父类引用指向子类对象,叫:多态
        Animal an = new Cat();
        
        //多态访问成员变量:编译看左,运行看左
        System.out.println(an.age);
        
        //多态访问成员方法:编译看左,运行看右
        an.eat();
    }
}

多态的好处与弊端

  • 好处:提高了代码的扩展性.

  • 弊端: 父类引用不能直接使用子类的特有成员.

如何解决上述的问题?

​ 通过向下转型解决,

​ 即: 多态形式的创建对象的操作 -> 转变成 普通的创建对象的操作.

示例:
Animal an = new Cat();	向上转型,猫 -> 动物	double d = 10;  隐式类型转换
Cat c = (Cat)an;		向下转型,动物 ->int a = (int)d; 强制类型转换
演示向上转型和向下转型
//父类, 动物类
public class Animal {
    public void eat() {
        System.out.println("动物要吃");
    }
}

//子类, 猫类
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }

    public void catchMouse() {
        System.out.println("猫会抓老鼠!....");
    }
}

//动物类案例测试类.
public class AnimalTest {
    public static void main(String[] args) {
        //1 多态形式的创建猫类对象
        Animal an = new Cat();
        //2. 演示多态的弊端.
        an.eat();               //编译看左 运行看右.

        //3. 升级功能: 尝试通过多态版的 猫类对象, 调用猫类中独有的 catchMouse()功能.
        //an.catchMouse();      //这样做不行, 因为an是Animal动物类的引用, 我们不能说  动物会抓老鼠

        //4. 通过向下转型, 把 多态版的 猫类对象 ->  Cat类型的猫类对象.
        Cat c = (Cat)an;          //引用类型的: 向下转型,     即: 大 -> 小.
        c.catchMouse();
        //int a = (int)10.3;        基本类型的: 强制类型转换, 即: 大 -> 小.
    }
}

猫狗案例(多态版)

  • 动物类
//父类, 动物类
public class Animal {
    //属性, 姓名, 年龄
    private String name;
    private int age;

    public Animal() {
    }

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //行为, 吃饭
    public void eat() {
        System.out.println("动物要吃饭!");
    }
}

  • 狗类
//子类: 狗类
public class Dog extends Animal{
    //构造方法
    public Dog() {
    }

    public Dog(String name, int age) {
        super(name, age);
    }

    //成员方法
    //重写Animal#eat()
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    //定义自己独有的行为
    public void lookHome() {
        System.out.println("狗会看家!");
    }
}

  • 猫类
//子类: 猫类
public class Cat extends Animal{
    //构造方法
    public Cat() {
    }

    public Cat(String name, int age) {
        super(name, age);
    }

    //成员方法
    //重写Animal#eat()

    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    //定义自己独有的行为
    public void catchMouse() {
        System.out.println("猫会抓老鼠");
    }
}
  • 测试类
//测试类:
public class AnimalTest {
    public static void main(String[] args) {
        //1. 通过多态的方式测试 狗类的空参对象.
        //1.1 创建对象.
        Animal an = new Dog();
        //1.2 设置属性
        an.setAge(23);
        an.setName("旺财");
        //1.3 打印属性
        System.out.println(an.getAge() + " " + an.getName());
        //1.4 调用方法
        an.eat();
       /* 1.5 调用狗类的独有的方法, 需要向下转型, 因为多态的弊端是:
        父类引用不能直接使用子类的特有成员.*/
        Dog an2 = (Dog) an;
        an2.lookHome();

        System.out.println("---------------------------");

        //2. 通过多态的方式测试 狗类的全参对象.
        //2.1 创建对象, 并设置属性
        Dog d1 = new Dog("哮天犬", 450);
        //2.2 打印属性
        System.out.println(d1.getAge() + " " + d1.getName());
        //2.3 调用方法
        d1.eat();
        //2.4 调用狗类的独有的方法.
        d1.lookHome();
    }
}

多态在实际开发中的应用

  • 多态在生产环境具体的用法如下
    • 父类型可以作为方法的形参类型,这样可以接收其任意的子类对象,根据调用成员方法的规则(编译看左,运行看右)
    • 实现:传入什么类型的子类对象,就调用其对应的的成员方法
//父类 
public class Animal {
    int age = 30;

    public void eat() {
        System.out.println("动物要吃饭!");
    }
}

//子类
public class Dog extends Animal {
    int age = 25;

    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    //自己独有的行为
    public void lookHome() {
        System.out.println("狗会看家");
    }
}

//子类
public class Cat extends Animal {
    int age = 20;
    
   @Override
   public void eat(){
       System.out.println("猫吃鱼!");
   }
   public void catchMouse(){
       System.out.println("猫会抓老鼠");
   }
}

//测试类
public class Demo02 {
    public static void main(String[] args) {
        Cat c = new Cat();
        printAnimal(c);

        Dog d = new Dog();
        printAnimal(d);
    }

    public static void printAnimal(Animal an) {//Animal an = new Dog(); 
        //根据多态访问成员方法的规则: 编译看左, 运行看右.
        an.eat();
    }
}

instanceof关键字

  • 概述:

    • 它是一个关键字,用来判断 指定的引用(对象) 是否是 某一个类型的对象.
  • 格式:

    • 引用(对象) instanceof 数据类型 //判断
  • 例如

    • Cat c = new Cat();
      	c instanceof Cat        ->  true
          c instanceof Dog        ->  false
      

案例:

//测试类
public class Demo02 {
    public static void main(String[] args) {
        Cat c = new Cat();
        printAnimal(c);

        Dog d = new Dog();
        printAnimal(d);
    }

    public static void printAnimal(Animal an) {
        an.eat();
        
        //判断传入的是否是猫类
        if (an instanceof Cat){
            //走到这里, 说明是猫类对象, 向下转型, 然后调用方法即可.
            Cat c = (Cat)an;
            c.catchMouse();
        }else if (an instanceof Dog){
            //走到这里, 说明是狗类对象, 向下转型, 然后调用方法即可.
            Dog d = (Dog)an;
            d.lookHome();
        }
/*
虽然我们用instanceof关键字解决了判断an是哪种具体的子类对象这个问题,但是又带来一个新的问题。

即:当需求变化的时候(又有子类加入的时候),我们还需要修改源码,和十大黄金开发原则之
“对修改关闭,对扩展开放”相违背,即:需求变化的时候,建议我们加东西,而不是改目前的源码。

可以通过 抽象工厂方法设计模式解决,即:每一种子类,都创建与其对应的工厂类。需求变化的时候,我们只要加代码即可,不需要修改源码。*/
    }
}

final关键字

  • 概述:final是一个关键字, 表示最终的意思, 可以修饰类, 成员变量, 成员方法.
    • 修饰的类: 表示最终类,不能被别的类继承, 但是可以继承其他的类.
    • 修饰的变量: 表示常量, 只能被赋值一次.
    • 修饰的方法: 表示最终方法,子类可以继承,但不能被子类重写.
//父类
//public final class Father extends Object(){ Father类不能被继承。
public class Father {
    public final void method(){
        System.out.println("绝密文件,不能动");
    }
}

//子类
public class Son extends Father{
/*    @Override
    public void method() {
        System.out.println("删除文件");
    }*/
}

//测试类
public class FatherTest {
    public static void main(String[] args) {
        final int a = 10;
        //a = 20;     //报错,常量只能赋值一次,值不能修改
        System.out.println(a);

        Son s = new Son();
        s.method();
    }
}
演示自定义常量的细节
  • 请问怎么理解"final修饰的变量是一个常量, 其值只能赋值一次这个问题" ?

    • final修饰的变量如果是基本类型,则:数值不能改变
    • final修饰的变量如果是引用类型,则:地址值不能改变,里面的属性值可以变化
  • final修饰的变量如果是成员变量,则必须手动赋值,不能用默认值为什么?

    • 成员变量默认都是有默认值的
    • final修饰的变量只能赋值一次,不能重复赋值
    • 如果final修饰的变量采用了变量的默认值,此时用户就无法手动再修改值了,需要用户手动给值,即:final修饰的成员变量没有默认值
public class Father {
}

//子类
public class Son extends Father{
    int age;
//    final int num;  报错
    final int num = 0;  //必须手动给值
}

//测试类
public class Demo02 {
    public static void main(String[] args) {
        //1. 演示  如果修饰的基本类型的常量: 是数值不能发生变量.
        final int a = 10;
        //a = 20;       //这样写会报错.
        System.out.println(a);
        System.out.println("-----------------------");

        //2. 演示: 如果修饰的引用类型的常量: 地址值不能发生变化, 
        //	 但是该对象的属性值可以发生变化.
        final Son s = new Son();
        s.age = 18;

        System.out.println(s.age);  //18

        //3.演示final修饰的变量如果是成员变量,则必须手动赋值,不能用默认值
        System.out.println(s.num);  //20
    }
}

static关键字

  • 概述
    • 它是一个关键字, 表示静态的意思, 可以修饰成员变量成员方法.
  • 特点
    • 随着类的加载而加载.
    • 优先于对象存在.
    • 被static修饰的内容, 能被该类下所有的对象所共享.
    • 静态内容可以被 类名. 的形式直接调用,也可以被 对象名. 的形式调用,推荐使用前者。
//学生类
public class Student {
    String name;
    int age;
    static String graduateFrom;

    public void show() {
        System.out.println(name + "..." + age + "..." + graduateFrom);
    }
}

//测试类
public class StudentTest {
    public static void main(String[] args) {
        //类名. 的形式调用
        Student.graduateFrom = "武软";
        System.out.println(Student.graduateFrom);
        
        Student s = new Student();
        s.age = 23;
        s.name = "李四";
        s.show();
        System.out.println(s.age + " " + s.name);

        Student s3 = new Student();
        s3.name = "高圆圆";
        s3.age = 35;
        Student.graduateFrom = "传智学院";
        s3.show();
    }
}
静态方法的注意事项
  • 判断是否使用静态的最大的依据是:看该成员是否被该类下所有的对象所共享,如果是,就可以虑使用静态。
  • 静态只能访问静态,即:静态方法只能访问 静态方法静态变量
    • 因为静态是优先于非静态内容存在的,先进内存的不能访问后进内存的。
    • 非静态方法可以访问所有成员(非静态变量 和 方法, 静态变量 和 方法)
  • 在静态方法中, 是没有this, super关键字的。因为它们只有创建对象才会有,而静态是优先于对象存在的
  • 实际开发中,static 一般和 public 、final 相结合使用。

总结:先进内存的不能访问后进内存的。

//学生类
public class Student {
    String name = "刘亦菲";        //非静态成员变量
    static int age = 33;           //静态的成员变量

    public void show1() {
        System.out.println(name);
        System.out.println(age);
        //this.show2();         标准写法
        show2();

        //Student.show3();      标准写法
        show3();                //因为是访问本类的静态成员方法, 所以可以省略类名不写.
        show4();
        System.out.println("show1方法  非静态方法");
    }

    public void show2() {
        System.out.println("show2方法  非静态方法");
    }

    public static void show3() {
        //System.out.println(name);       //非静态成员变量
        System.out.println(age);         //静态成员变量

        //this.show2();                   //非静态方法
        Student.show4();                //静态方法

        System.out.println("show3方法  静态方法");
    }

    public static void show4() {
        System.out.println("show4方法  静态方法");
    }
}

//测试类
public class StudentTest {
    public static void main(String[] args) {
        Student s = new Student();
        //s.show1();  
        //结论: 非静态方法可以访问所有成员(非静态变量和方法, 静态变量和方法)

        //s.show3();    这样写不报错, 只是不推荐.
        Student.show3();    //静态方法只能访问静态成员
    }
}

抽象类

概述:
    1. 没有方法体的方法, 叫抽象方法, 用abstract修饰.
    1. 有抽象方法的类一定是抽象类, 抽象类也用 abstract修饰.
特点:
    1. 抽象类和抽象方法都用abstract关键字修饰.
    1. 抽象类中不一定有抽象方法, 但是有抽象方法的类一定是抽象类.
    1. 抽象类不能实例化.

      那么抽象类如何实例化呢?

      通过 抽象类多态 实现。

    1. 抽象类的子类:

      如果是普通类, 则必须重写父类的所有的抽象方法.

      如果是抽象类, 则可以不用重写父类的所有抽象方法.

//父类, 动物类
public abstract class Animal {
    //1.类中有一个抽象方法eat(), 还有一个非抽象方法sleep().
    public abstract void eat();

    public void sleep() {
        System.out.println("动物要睡!");
    }
}

//子类, 猫类
//抽象类的子类如果是抽象类, 则可以不用重写父类的所有抽象方法.
//public abstract class Cat extends Animal{


//抽象类的子类如果是普通类, 则必须重写父类的所有的抽象方法.
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }
}

//测试类
public class AnimalTest {
    public static void main(String[] args) {
        //1. 演示: 抽象类不能实例化.
        //Animal an = new Animal();   这样写会报错.


        //2. 抽象类可以通过创建其子类对象的形式, 来完成抽象类的初始化.
        //抽象类多态
        Animal an = new Cat();
    }
}
抽象类的成员特点
  • **结论:**抽象类中可以有 变量, 常量, 构造方法, 非静态方法,静态方法,抽象方法。
    就是比普通类多一种抽象方法,而且抽象方法还可以不写。

  • 问题一:思考: 既然抽象类不能实例化, 那要构造方法有什么用?

  • 用于子类对象访问父类数据前, 对父类数据进行初始化.

  • 问题二:抽象类中的抽象方法和非抽象方法的作用是什么?

    • 抽象方法:强制要求子类必须完成某些事情.
    • 非抽象方法:让子类继承, 提高代码的复用性.
//父类, 表示老师类.
public abstract class Teacher {
    //属性.
    private String name;
    private int age;

    //构造方法
    public Teacher() {
    }

    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
    }

    //getXxx(), setXxx()
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //行为
    //抽象方法, 讲课.
    public abstract void teach();
}

//子类, 基础班老师
public class BasicTeacher extends Teacher{
    //构造方法
    public BasicTeacher() {
    }

    public BasicTeacher(String name, int age) {
        super(name, age);
    }

    //重写Teacher#teach()
    @Override
    public void teach() {
        System.out.println("基础班老师讲: JavaSE");
    }
}

//子类, 就业班老师
public class WorkTeacher extends Teacher{
    //构造方法
    public WorkTeacher() {
    }

    public WorkTeacher(String name, int age) {
        super(name, age);
    }

    //重写Teacher#teach()
    @Override
    public void teach() {
        System.out.println("就业班老师讲: JavaEE, Linux, Hadoop...");
    }
}

//测试类
public class TeacherTest {
    public static void main(String[] args) {
        //1. 测试基础班老师, 空参.
        //抽象类多态版
        Teacher b1 = new BasicTeacher();
        b1.setAge(23);
        b1.setName("李四");
        System.out.println(b1.getAge() + " " + b1.getName());
        b1.teach();

        //2. 测试基础班老师, 全参.
        Teacher b2 = new BasicTeacher("王五",45);
        System.out.println(b2.getAge() + " " + b2.getName());
        b2.teach();
    }
}

接口

接口简介

  • 概述
    • 它是一种比抽象类更加抽象的存在,里面有且只能有常量抽象方法(JDK1.8以前)。
    • (jdk1.8以后)接口可以写 静态方法默认方法,静态方法直接写,默认方法要用 default修饰
  • 特点
    • 接口用interface关键字修饰.
    • 类和接口之间是实现关系, 用implements关键字表示.
    • 接口不能实例化.
      • 那接口如何实例化呢?
        • 可以通过多态的方式, 创建其子类对象, 来完成接口的实例化. 这也叫: 接口多态.
    • 接口的子类:
      • 如果是普通类, 则必须重写父接口中所有的抽象方法.
      • 如果是抽象类, 则可以不用重写父接口中的抽象方法.
//猫类
public class Cat implements Jumpping {
    @Override
    public void jump() {
        System.out.println("猫会跳高");
    }

    public void catchMouse() {
        System.out.println("猫会抓老鼠");
    }
}

//接口
public interface Jumpping {
    public abstract void jump();
}

//测试类
public class CatTest {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.catchMouse();
        c.jump();       //这个方法, 是Cat从Jumpping接口中实现过来的.

        System.out.println("------------------");

        //测试接口多态
        Jumpping jm = new Cat();
        jm.jump();
        
        //向下转型
        Cat c2 = (Cat)jm;
        c2.catchMouse();
    }
}

成员特点:

//即:接口中能写什么,不能写什么

  • JDK1.8以前:
    • 接口中有且只能有 常量抽象方法,原因如下:
      • 变量有默认修饰符:public、static、final
      • 方法有默认修饰符:public、abstract
  • JDK1.8以后:
    • 接口可以写 静态方法默认方法了,静态方法直接写,默认方法要用 default修饰
public interface Myinterface {
    //常量
    //public static final int age = 20;
    int age = 20;   //简写格式

    //抽象方法
    //public abstract void eat();
    void eat();     //简写格式

    public static void show() {
        System.out.println("静态方法,JDK1.8新特性");
    }

    public default void method() {
        System.out.println("非静态方法(默认方法),JDK1.8新特性");
    }
}

类与接口之间的关系

  • 类与类:继承关系,只能单继承,不能多继承,但可以多层继承。

  • 类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。

  • 接口与接口:继承关系,可以单继承,也可以多继承。

抽象类与接口的区别

  • 1.成员特点的区别

    • 抽象类:变量、常量、构造方法、静态方法,非静态方法、抽象方法。
    • 接口:常量、静态方法、非静态方法(默认方法)、抽象方法。
  • 2.关系特点的区别

    • 类与类:继承关系,只能单继承,不能多继承,但可以多层继承。

    • 类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。

    • 接口与接口:继承关系,可以单继承,也可以多继承。

  • 3.设计理念的区别

    • 抽象类:定义的是整个继承体系的 共性内容。
    • 接口:定义的是整个个继承体系的 扩展内容。
运动员和教练案例

细节:

​ 1.分析的时候 从具体到抽象

​ 2.写代码的时候 从抽象到具体

  • 需求:

    • 已知有乒乓球运动员(PingPangPlayer)和篮球运动员(BasketballPlayer), 乒乓球教练(PingPangCoach)和篮球教练(BasketballCoach).
    • 他们都有姓名和年龄, 都要吃饭, 但是吃的东西不同.
    • 乒乓球教练教如何发球, 篮球教练教如何运球和投篮.
    • 乒乓球运动员学习如何发球, 篮球运动员学习如何运球和投篮.
    • 为了出国交流, 跟乒乓球相关的人员都需要学习英语.
  • 人类,抽象类

package com.itheima.demo11_coach;
//人类
public abstract class Person {
    //属性:姓名,年龄
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    //行为:吃饭
    public abstract void eat();
}

  • 运动员类,抽象类,继承Person类。
package com.itheima.demo11_coach;

//运动员类,抽象类,继承Person类。
public abstract class Player extends Person {
    //构造方法:子空 -> 父空, 子全 -> 父全

    public Player() {
    }

    public Player(String name, int age) {
        super(name, age);
    }

    //特有的行为
    public abstract void study();
}
  • 教练类,抽象类,继承Person类。
package com.itheima.demo11_coach;

//教练类,抽象类,继承Person类。
public abstract class Coach extends Person {
    //构造方法:子空 -> 父空, 子全 -> 父全

    public Coach() {
    }

    public Coach(String name, int age) {
        super(name, age);
    }

    //特有的行为
    public abstract void teach();
}
  • 接口
package com.itheima.demo11_coach;

//接口,实现说英语的功能
public interface Speak {
    //表示具有 说英语的功能,因为是接口,所以 public abstract 可以省略
//    public abstract void speakEnglish();
    void speakEnglish();
}
  • 篮球运动员类,继承运动员类
package com.itheima.demo11_coach;

//篮球运动员类,继承运动员类
public class BasketballPlayer extends Player {
    //构造方法:子空 -> 父空, 子全 -> 父全

    public BasketballPlayer() {
    }

    public BasketballPlayer(String name, int age) {
        super(name, age);
    }

    //重写Person#eat()
    @Override
    public void eat() {
        System.out.println("篮球运动员吃 牛肉 喝羊奶");
    }

    //重写Player#study()
    @Override
    public void study() {
        System.out.println("篮球运动员学习 运球 投篮");
    }

}
  • 乒乓球运动员类,继承运动员类,实现讲英语接口
package com.itheima.demo11_coach;

//乒乓球运动员类,继承运动员类,实现讲英语接口
public class PingPnagPlayer extends Player implements Speak{

    //构造方法:子空 -> 父空, 子全 -> 父全
    public PingPnagPlayer() {
    }

    public PingPnagPlayer(String name, int age) {
        super(name, age);
    }


    //重写Person#eat()
    @Override
    public void eat() {
        System.out.println("乒乓球运动员吃 羊肉 喝牛奶");
    }

    //重写Player#study()
    @Override
    public void study() {
        System.out.println("乒乓球运动员练习 打乒乓球");
    }

    //重写Speak#speakEnglish()
    @Override
    public void speakEnglish() {
        System.out.println("乒乓球运动员 学习讲英语");
    }
}

  • 乒乓球教练类,继承教练类,实现讲英语接口
package com.itheima.demo11_coach;

//乒乓球教练类,继承教练类,实现讲英语接口
public class PingPnagCoach extends Coach implements Speak {

    //构造方法:子空 -> 父空, 子全 -> 父全
    public PingPnagCoach() {
    }

    public PingPnagCoach(String name, int age) {
        super(name, age);
    }

    //重写Person#eat()
    @Override
    public void eat() {
        System.out.println("乒乓球运动员吃 羊肉 喝牛奶");
    }

    //重写Player#teach()
    @Override
    public void teach() {
        System.out.println("乒乓球运动员练习 打乒乓球");
    }

    //重写Speak#speakEnglish()
    @Override
    public void speakEnglish() {
        System.out.println("乒乓球运动员 学习讲英语");
    }
}

  • 篮球教练类,继承教练类
package com.itheima.demo11_coach;

//篮球教练类,继承教练类
public class BasketballCoach extends Coach {
    //构造方法:子空 -> 父空, 子全 -> 父全

    public BasketballCoach() {
    }

    public BasketballCoach(String name, int age) {
        super(name, age);
    }

    //重写Person#eat()
    @Override
    public void eat() {
        System.out.println("篮球教练吃 牛肉 喝羊奶");
    }

    //重写Coach#teach()
    @Override
    public void teach() {
        System.out.println("篮球教练教 运球 投篮");
    }

}

  • 测试类
package com.itheima.demo11_coach;

public class Demo01 {
    public static void main(String[] args) {
        //测试乒乓球运动员
        //抽象类多态
        Person p1 = new PingPnagPlayer("马龙", 32);
        Player p2 = new PingPnagPlayer("马龙", 32);
        //接口多态
        Speak s = new PingPnagPlayer("马龙", 32);
        //标准写法 自己接收自己
        PingPnagPlayer p3 = new PingPnagPlayer("马龙", 32);
        System.out.println(p3.getName() + " " + p3.getAge());
        p3.eat();
        p3.study();
        p3.speakEnglish();

        System.out.println("----------------------------");
        
        //测试乒乓球教练
        //抽象类多态
        Person pp1 = new PingPnagCoach("刘国梁", 45);
        Coach pp2 = new PingPnagCoach("刘国梁", 45);
        //接口多态
        Speak s2 = new PingPnagCoach("刘国梁", 45);
        //标准写法 自己接收自己
        PingPnagCoach pp3 = new PingPnagCoach("刘国梁", 45);
        System.out.println(pp3.getName() + " " + pp3.getAge());
        pp3.eat();
        pp3.teach();
        pp3.speakEnglish();

    }
}

概述:
  • 包就是文件夹,在Java中用 package 关键字修饰,包名要全部小写, 多级包之间用 . 隔开,一般是公司的域名反写。

  • 包就是对 类 做分类管理的

  • 定义包的格式:

    • package 包名1.包名2.包名3…; //包名根据需求可以写多级.
如何分包:
  • 按照模块分: //了解
    • com.itheima.student //包
      • AddStudent.java //类
      • DeleteStudent.java
    • com.itheima.teacher //包
      • AddTeacher.java //类
  • 按照操作分: //了解
    • com.itheima.add //包
      • AddStudent.java //类
    • com.itheima.delete //包
      • DeleteStudent.java //类
  • 实际开发分包法: //掌握
    • com.itheima.controller //控制层,负责和浏览器交互的
    • com.itheima.service //业务层,负责在controller 和 dao层之间协调业务的
    • com.itheima.dao //数据访问层,负责和数据库交互的
    • com.itheima.pojo //存储所有的JavaBean类
    • com.itheima.utils //存储所有工具类
导包:
  • 格式:

    • import 包名1.包名2.包名3.*;
      import 包名1.包名2.包名3.类名;
      
  • 示例:

    • import java.util.Scanner;		//只导入Scanner一个类,	更推荐
      import java.util.*;				//导入java.util包下所有的类和接口
      

注意事项:

  • java.lang包下的类可以直接使用, 无需导入, 如果使用其他包下的类, 则必须先导包.
  1. public修饰的类叫: 公共类, 也叫顶级类, 在一个.java文件中, 顶级类只能有一个, 且必须和文件名一致.
package com.itheima.demo11_coach;

import java.util.Date;
import java.util.Scanner;

public class Demo01 {
    public static void main(String[] args) {
        //需求1:不用导包,如何调用指定的类呢?     了解。
        //包名 + 类名   = 全类名
        //java.util.Scanner sc = new Scanner(System.in);

        //需求2:导包的思路
        //Scanner sc = new Scanner(System.in);

        //需求3:如果某两个不同的包下都有相同的类,此时就要用到 全类名写法了。
        Date d1 = new Date();

        //可以写全类名
        java.sql.Date d2 = new java.sql.Date(10L);
    }
}

**面试题:**在一个 .java文件中,package,import,class 三者之间有无顺序关系?

  • 有,先写package,且一个.java文件中,package语句只能有一个。

  • 再写 **import:**表示导包,它是写在package和class之间的,根据需求可以写多个。

  • 最后写 **class:**表示修饰类,一个.java文件中可以写多个,但是建议只写一个。

  • 细节

    • 被public 修饰的类叫 公共类,也叫顶级类,在一个.java文件中,公共类只能有一个,且该类名必须和文件名一致。

四大权限修饰符

测试的结论图:

private默认protectedpublic
同一个类中
同一个包中的类(无关类或者子类)
不同包下的类(子类)
不同包下的类(无关类)

结论

  1. 四大访问权限修饰符的范围从大到小分别是: public > protected > 默认 > private

  2. 在实际开发中, 如非必要, 一般都是属性全部用private修饰, 其它都用public修饰

  3. 四大访问权限修饰符各自的作用分别如下:

    private: 强调的是给 自己 使用的

    默认: 强调的是给 同包下的类 使用的

    protected: 强调的是给 子类 使用的

    public: 强调的是给 大家 使用的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值