• JAVA面向对象三大特征


    一、封装

    1. 介绍

    封装就是将对象的属性保护起来,只能通过类内部的方法来访问
    可以在修改属性时做一些检验防止意外发生,提高安全性
    封装好以后其他人只需要知道怎么调用,不用考虑内部的实现原理

    2. 实现步骤

    1. 将属性私有化(private),使其不能被外部访问
    2. 设置公共的(publicset方法来设置属性的值
    3. 设置公共的(publicget方法来获取属性的值

    3. IDEA快捷键

    alt + insert后选择getter和setter
    快捷键

    4. 与构造器结合

    set方法写在构造器中,可以保证初始化的安全

    5. 示例

    public class Homework {
        private String password = "000000";
    
        public Homework(String password) {
            setPassword(password);
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            if(password.length() == 6){
                this.password = password;
            } else {
                System.out.println("密码不是六位,默认密码为000000");
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    二、继承

    1. 为什么需要继承

    有些类中有很多相同的方法,但是又有一些不同的方法,这就造成了代码冗余。
    将共同的部分抽离成父类(也叫基类,超类),让子类(也叫派生类)去继承可以解决这个问题。
    继承示意图

    2. 基础语法

    使用extends关键字
    父类

    public class Student {
        public String name;
        public int age;
        private float score;
    
        public float getScore() {
            return score;
        }
    
        public void setScore(float score) {
            this.score = score;
        }
    
        public void info() {
            System.out.println("姓名:" + name + " 年龄:" + age + " 分数" + score);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    子类

    //让pupil类继承student类
    public class Pupil extends Student{
        public void testing() {
    //        这里用到了从父类继承的name属性
            System.out.println("小学生" + name + "正在考小学数学");
        }
    
        public static void main(String[] args) {
            Pupil pupil = new Pupil();
            pupil.name = "xiaoming";
            pupil.testing();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3. 细节

    1. 子类继承了所有的属性和方法,但不一定能用。
      私有属性和方法不能直接去访问,非私有的属性和方法可以在子类直接访问,要通过父类提供的公共的方法去访问。

    这里的score是私有属性,可以看到直接使用IDEA会报错
    出错
    2. 子类必须调用父类的构造器完成父类的初始化,因为子类中有一个隐藏的无参的super()函数,super函数在子类构造器的最上面,会被默认调用。
    3. 创建子类对象时,无论子类使用哪个构造器,都会默认调用父类的无参构造器,如果父类没有无参构造器,则必须指明使用父类的哪个构造器。
    4. 如果希望使用父类的某一个构造器,则需要显式得调用。
    5. super必须放在构造器的第一行。
    6. super()this()都只能放在第一行,因此两个方法不能共存。
    7. 所有的类都是Object的子类,Object类是所有类的父类。(在IDEA中ctrl + H可以查看类之间的关系)。
    ctrl+h快捷键

    1. 父类构造器的调用不限于直接父类,将一直追溯至Object。
    2. 子类只能直接继承一个父类,java是单继承机制。
    3. 不能滥用继承,子类和父类之间必须满足is-a的逻辑关系。

    4. 内存本质

    在jvm中的内存

    5. super

    5.1 基本介绍

    super是父类的引用,类似于this是子类本身的引用。
    使用super可以访问父类的属性、方法和构造器。

    5.2 基本语法

    1. super.属性名可以访问父类的属性,但不能访问私有属性。
    2. super.方法名可以访问父类的方法,但不能访问私有方法。
    3. super(参数)可以访问父类的构造器,必须放在第一句。

    5.3 细节

    1. 调用父类构造器的好处:分工明确,父类由父类构造器初始化,子类由子类构造器初始化。
    2. 当子类与父类的属性和方法重名时,必须通过super来访问直接父类的属性和方法,如果不同名使用super和使用this效果相同。
    3. super的访问不限于直接父类,也可以访问爷爷类的成员,如果父类和爷爷类中也有重名类,则遵循就近原则

    5.4 super与this

    super与this的对比

    6. 方法重写(override)

    6.1 基本介绍

    如果子类中的某个方法与父类(不一定是直接父类)中完全相同(方法名,返回类型,参数),则子类中的方法会覆盖掉从父类中继承来的方法。

    6.2 细节

    1. 子类中重写的方法的返回类型可以是父类方法返回类型的的子类
      (例如父类返回Object,则子类可以返回String)。
    2. 子类的参数和方法名要和父类完全相同才可以重写。
    3. 子类方法不能缩小父类方法的访问权限。

    6.3 重写和重载

    重写和重载

    6.4 重写练习题

    题目要求
    题目
    代码

    // 定义父类
    class Person {
        private String name;
        private int age;
    	// 父类的构造器
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void say() {
            System.out.println("我的名字是:" + name + 
            " 我的年龄是:" + age);
        }
    }
    // 定义子类
    class Student extends Person{
    
        private String id;
        private float score;
    	// 子类的构造器
        public Student(String name, int age, String id, float score) {
        	// 调用父类的构造器
            super(name, age);
            this.id = id;
            this.score = score;
        }
        
        public void say() {
        	// 调用父类的say方法
            super.say();
            System.out.println("我的学号是:" + id +
             "我的分数是:" + score);
        }
    
        public static void main(String[] args) {
            Student student = new Student("小明",18,"123456",99);
            student.say();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    三、多态

    1. 基本介绍

    建立在封装和继承之上。
    指的是方法和对象具有多种形态,父类的引用可以指向子类。
    看不懂没关系,往下继续看就明白了。
    举一个动物给动物喂食的案例,不再需要每种动物都重载一次方法,直接使用动物的父类和食物的父类来指向各个子类。
    之后再添加新的子类时也不需要修改feed方法。
    在这里插入图片描述

    2. 具体体现

    2.1 方法的多态

    重写和重载体现多态

    2.2 方法的多态

    1. 一个对象的编译类型和运行类型可以不一样
    2. 编译类型在定义是就已经确定了,不能改变
    3. 运行类型是可以变化的
    4. 编译类型看等号的左边,运行类型看等号的右边

    例如animal和cat是两个类
    animal o = new cat();
    定义的o编译类型为animal,运行类型为cat
    示例

    3. 细节

    3.1 前提条件

    两个对象(类)存在继承关系

    3.2 向上转型

    1. 本质: 父类的引用指向了子类的对象
    2. 语法: 父类 引用名 = new 子类()
    3. 特点:
      • 编译类型看左边,运行类型看右边。
      • 可以直接调用父类中的所有成员(需要遵守访问权限)。
      • 不能调用子类中的特有成员,只能调用重写的成员,在编译阶段,能调用那些成员是由编译类型决定的。
      • 运行效果看子类的具体实现,调用方法时是从运行类型开始查找。

    3.3 向下转型

    1. 向下转型的目的是为了调用子类的特有成员。
    2. 语法:子类 引用名= (子类类型)父类对象
    3. 只能强转父类的引用,不能强转父类的对象(向下转型的前提是向上转型,经历过向上转型的对象(引用)才可以被向下转型)
    4. 要求父类的引用必须指向当前目标类型的对象
    5. 可以调用子类的所有成员

    3.4 属性的重写

    • 属性没有重写和转型一说,属性的值直接看编译类型
    • instanceof,可以查看一个对象是否是某个类型或者其子类型(运行类型)

    例如:A instanceof B,检查A对象是否是B类型,或者A对象是否是B类型的子类型,返回布尔值

    4. 应用场景

    4.1 多态数组

    1. 定义:数组定义的类型为父类类型,实际存储的对象为子类类型。
    2. 数组中子类特有的方法可以通过向下转型调用。
    3. 可以使用instanceof关键字判断转型为哪个子类。
    //Teacher类
    public class Teacher extends Person{
        public static void main(String[] args) {
        	// 向上转型 将Student和Teacher都存储在Person数组中
            Person[] people = new Person[5];
            people[0] = new Person("砂糖",12);
            people[1] = new Student("刻晴",16,88.0);
            people[2] = new Student("蜜莓",14,80.0);
            people[3] = new Teacher("凯尔希",100,80000);
            people[4] = new Teacher("钟离",5000,0);
    
            for (int i = 0; i < people.length; i++) {
            	//instanceof 与 向下转型结合调用子类特有方法
                if(people[i] instanceof Student){
                    Student student = (Student)people[i];
                    student.study();
                } else if(people[i] instanceof Teacher){
                    Teacher teacher = (Teacher)people[i];
                    teacher.teach();
                }
               people[i].say(people[i].getAge(), people[i].getName());
            }
    
    
        }
        private int money;
    
        public Teacher(String name, int age, int money) {
            super(name, age);
            this.money = money;
        }
    
        public int getMoney() {
            return money;
        }
    
        public void setMoney(int money) {
            this.money = money;
        }
    
        @Override
        public void say(int age, String name) {
            super.say(age, name);
            System.out.println("我的工资是:" + money);
        }
    
        public void teach(){
            System.out.println(getName() + "正在讲课");
        }
    }
    //Student 类
    public class Student extends Person{
        private double score;
    
        public Student(String name, int age, double score) {
            super(name, age);
            this.score = score;
        }
    
        public double getScore() {
            return score;
        }
    
        public void setScore(double score) {
            this.score = score;
        }
    
        public void say(int age, String name) {
            super.say(age, name);
            System.out.println("我的分数是:" + score);
        }
    
        public void study(){
            System.out.println(getName() + "正在学习");
        }
    }
    //Person 类
    public class Person {
        private String name;
        private int age;
    
        public Person(String name, int age) {
            setAge(age);
            setName(name);
        }
    
        public Person() {
    
        }
    
        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 say(int age,String name) {
            System.out.println("我的名字是:" + name + "我的年龄是" + age);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    4.2 多态参数

    方法定义的形参为父类,实参可以是子类。
    题目示例

    //test类
    public class test {
        public static void main(String[] args) {
            sass tom = new sass("tom", 2000);
            less milan = new less("milan", 5000, 200000);
            test test = new test();
            test.show(tom);
            test.show(milan);
            test.testwork(tom);
            test.testwork(milan);
        }
    
        public void show(css e){
            System.out.println(e.getMoney());
        }
    	// 形参参数为css父类,传入的实参为其子类
        public void testwork(css e){
            if(e instanceof less){
                ((less)e).manage();
            } else if(e instanceof sass){
                ((sass)e).work();
            } else {
                System.out.println("自己检查哪里出错了");
            }
        }
    }
    //css类
    public class css {
        String name;
        private int money;
    
        public css(String name, int money) {
            this.name = name;
            this.money = money;
        }
    
        public int getMoney() {
           return money * 12;
        }
    }
    
    //sass类
    public class sass extends css{
        public void work(){
            System.out.println("员工在工作");
        }
    
        public sass(String name, int money) {
            super(name, money);
        }
    	//方法重写
        @Override
        public int getMoney() {
            return super.getMoney();
        }
    }
    // less类
    public class less extends css {
        int bonus = 1000;
    
        public less(String name, int money, int bonus) {
            super(name, money);
            this.bonus = bonus;
        }
    
        public void manage(){
            System.out.println("领导在管理");
        }
    
        @Override
        public int getMoney() {
            return super.getMoney() + bonus;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
  • 相关阅读:
    企业架构LNMP学习笔记49
    设计模式深度解析:适配器模式与桥接模式-灵活应对变化的两种设计策略大比拼
    万字 HashMap 详解,基础(优雅)永不过时
    使用 Python 截屏
    汉字风格迁移篇---汉字笔划提取、数据集和基准的实例分割
    docker搭建私有仓库并推送本地镜像
    学习OpenCV——cv::inpaint函数(三)
    FT2004(D2000)开发实战之AMD R5 230显卡驱动适配
    链表oj3(Leetcode)——相交链表;环形链表
    【SQL解析】- Druid SQL AST 01
  • 原文地址:https://blog.csdn.net/m0_66711291/article/details/125463138