Java三大特性

一、封装encapsulation

封装:把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作,才能对数据进行操作。

  1. 隐藏实现细节
  2. 对数据进行验证,保证安全合理

1.封装的实现

  1. 将属性进行私有化,使其不能被直接修改
  2. 提供一个公共的set方法,用于对该属性赋值,且判断赋值是否合理
  3. 提供一个公共的get方法,用于获取属性的值

2.代码示例

新建com.aroma包,在包下新建 Person类

java 复制代码
package com.aroma;

public class Person {
    public String name;
    private int age;
    private double salary;
    private String job;

    public Person() {
    }

    public Person(String name, int age, double salary, String job) {
        this.setName(name);
        this.setAge(age);
        this.setSalary(salary);
        this.setJob(job);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name.length() >=2 && name.length() <= 6) this.name = name;
        else{
            System.out.println("名字过长或过短,使用默认名字:无名客");
            this.name = "无名客";
        }
    }

    public void setAge(int age) {
        if (age <= 0 || age > 120){
            System.out.println("年龄不合理,使用默认年龄:18");
            this.age = 18;
        }
        else this.age = age;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public void showInfo() {
        System.out.println("姓名:" + this.name + ",年龄:" + this.age + ",薪水:" + this.salary + ",工作:" + this.job);
    }
}

在Main.java里测试:

java 复制代码
import com.aroma.Person;

public class Main {
    public static void main(String[] args) {
        Person person = new Person("aroma", 121, 10000, "IT");
        person.showInfo();
    }
}

结果如下:

二、继承extends

当多个类存在相同的属性和方法时,抽象一个父类,在该父类中定义这些相同的属性和方法,其所有子类不再需要重新定义这些属性和方法。

  • ctrl+H可以查看类的层级关系
java 复制代码
class subClass extends parentClass {}
  • 子类subClass会自动拥有父类定义的属性和方法
  • 父类,又名 超类、基类
  • 子类,又名:派生类
  • 继承可以解决代码复用
  • 子类继承父类所有的属性和方法,但子类无法访问父类的私有private属性,可以通过公共的方法getXXX()来访问
  • 子类必须调用父类的构造器,完成父类的初始化

1.注意事项

  1. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会调用父类的无参构造器。
  2. 若父类没有提供无参构造器(意思就是父类写了有参构造器,但是没有写无参构造器,而此时无参构造器已经被覆盖了,相当于没有无参构造器了),则必须在子类的构造器中用【super】去 指定使用父类的所拥有的构造器 来 完成对父类的初始化工作,否则编译不会通过。
  3. super(指定父类构造器的参数列表);必须放在子类构造器的第一行
  4. this();也只能放在第一行【this();用于调用本类的其他构造器】
  5. 所以,super和this不能放在同一个构造器中
  6. Object类是java所有类的基类,反过来就是java所有类都是Object类的子类
  7. 子类最多只能继承一个父类(指直接继承),即 Java中是单继承机制

2.super关键字

super代表父类的引用,用于访问父类的属性、方法和构造器。

  1. super.属性名:访问父类的属性,但不能访问父类的private属性
  2. super.方法名(参数列表):访问父类的方法,但不能访问父类的private方法
  3. super(参数列表);:访问父类的构造器。该句只能放在构造器里的第一行,且只能出现一句。
  • super的访问不限于 直接父类,若爷爷类和本类中有同名的成员(属性和方法),也可以通过super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用supper遵循就近原则。
区别点 this super
访问属性 访问本类中的属性,如果本类没有此属性则从父类中继续查找 访问父类中的属性
调用方法 访问本类中的方法,如果本类没有此方法则从父类中继续查找 访问父类中的方法
调用构造器 调用本类构造器,必须放在构造器的第一行 调用父类构造器,必须放在子类构造器的第一行
特殊 表示当前对象 子类中访问父类对象

3.方法重写/覆盖Override

  • 子类的方法的 【形参列表,方法名称】 和父类方法的【形参列表,方法名称】完全一样
  • 子类方法的返回类型和父类返回类型一样,或父类返回类型的子类。

例:父类返回类型是Object,子类返回类型是String

  • 子类方法不能缩小父类方法的访问权限(public > protected > 默认 > private)
名称 发生范围 方法名 参数列表 返回类型 修饰符
重载overload 同类 必须相同 返回类型、个数或顺序至少一个不同 无要求 无要求
重写override 父子类 必须相同 必须相同 相同或子类返回类型是父类的子类 子类修饰符不能比父类小

三、多态polymorphic

  • 为解决"代码复用性不高,不利于代码维护",提出【多态】
  • 多态:方法或对象具有多种形态,多态是建立在封装和继承基础上的。
  1. 方法的多态:重写、重载

1.对象的多态

  1. 一个对象的编译类型和运行类型可以不一致
  2. 编译类型在定义对象时确定,不能更改
  3. 运行类型是可以变化的
  4. 编译类型:定义对象时"="左边;运行类型:定义对象时"="右边
java 复制代码
Animal animal = new Dog(); // 编译类型是Animal,运行类型是Dog
animal = new Cat(); // 运行类型变成Cat,但编译类型仍是Animal

2.注意事项

  • 多态的前提:两个对象(类)存在继承关系
  • 属性没有重写之说,属性的值看编译类型
  • instanceOf(比较操作符):用于判断对象的运行类型是否为XX类型或XX类型的子类

3.多态的向上转型

  1. 本质:父类的引用指向子类的对象
  2. 语法:父类类型 引用名 = new 子类类型();
  3. 编译类型:父类类型;运行类型:子类类型
  4. 特点:可以调用父类中的所有成员(须遵循访问权限)、不能调用子类中的特有成员、最终运行效果看子类的具体实现。
  5. 调用规则:

1)调用方法先在子类类型中查找,若没有需要的方法,则在父类类型里查找;

2)调用属性是看编译类型(父类)

4.多态的向下转型

  1. 语法:子类类型 引用名 = (子类类型) 父类引用;
  2. 要求父类引用必须指向的是当前目标类型的对象
  3. 编译类型:子类类型;运行类型:子类类型
  4. 只能强转父类的引用,不能强转父类的对象
  5. 当向下转型后,可以调用子类类型中所有的成员

⭐5.动态绑定机制

动态绑定机制(Dynamic Binding)

  1. 当调用对象【方法】时,该方法会和 该对象的内存地址/运行类型 绑定
  2. 当调用对象【属性】时,没有动态绑定机制,哪里声明,哪里使用
  • A a = new B();

定义对象a,其编译类型为A,运行类型为B

  • 【1】System.out.println(a.sum());

调用对象a的sum()方法,该方法与对象a的运行类型B绑定。

先找B类里的sum()方法:

1)有则执行B类的sum()

  • B类的sum()方法体为return i + 20;

调用属性 i,而属性没有动态绑定机制。方法是在B类里的,则此 i 在B类声明,故 i = 20。

2)无则继续向上找B的父类A类的sum()

  • A类的sum()方法体为return getI() + 10;

调用方法getI(),该方法也与对象a的运行类型B绑定。

先找B类里的getI()方法,有则执行B类的getI()

  • B类的getI()方法体为return i;

调用属性 i,而属性没有动态绑定机制。方法是在B类里的,则此 i 在B类声明,故 i = 20。

  • 【2】System.out.println(a.sum1());

调用对象a的sum1()方法,该方法与对象a的运行类型B绑定。

先找B类里的sum1()方法:

1)有则执行B类的sum1()

  • B类的sum1()方法体为return i + 10;

调用属性 i,而属性没有动态绑定机制。方法是在B类里的,则此 i 在B类声明,故 i = 20。

2)无则继续向上找B的父类A类的sum1()

  • A类的sum1()方法体为return i + 10;

调用属性 i,而属性没有动态绑定机制。方法是在A类里的,则此 i 在A类声明,故 i = 10。

java 复制代码
import com.aroma.Account;
import com.aroma.Person;

public class Hello {
    public static void main(String[] args) {
        // 对象a - 编译类型:A; 运行类型:B
        A a = new B();
        // 对象调用方法先找该对象的运行类(该方法与该对象的运行类型绑定)
        System.out.println(a.sum()); // 运行类B有sum()方法,在方法体里执行 i + 20
        System.out.println(a.sum1()); // 运行类B有sum1()方法,在方法体里执行 i + 10
        // 方法体里调用属性(此时A类和B类均有所需要的属性),没有动态绑定机制,则i是在运行类型B类里声明的,则使用i = 20
    }
}

class A {
    public int i = 10;

    public int sum() {
        return getI() + 10;
    }

    public int sum1() {
        return i + 10;
    }

    public int getI() {
        return i;
    }
}

class B extends A {
    public int i = 20;

    public int sum() {
        return i + 20;
    }

    public int sum1() {
        return i + 10;
    }

    public int getI() {
        return i;
    }
}
java 复制代码
import com.aroma.Account;
import com.aroma.Person;

public class Hello {
    public static void main(String[] args) {
        // 对象a - 编译类型:A; 运行类型:B
        A a = new B();

        // 1.对象调用方法先找该对象的运行类,而此种情况下运行类型B里没有sum()和sum1()方法
        // 2.找B类的父类A类,此时A类里有sum()和sum1()方法
        System.out.println(a.sum()); // 执行A类里的sum(),方法体为getI() + 10
        // 3.方法体里又调用getI()方法【方法和该对象的运行类型绑定,所以先找运行类B类里的getI()
        // 4.运行类B类里有getI(),return i;
        // 5.这里的属性i是在B类声明的,则i = 20,则getI() = 20,a.sum() = 20 + 10 = 30
        System.out.println(a.sum1()); // 执行A类里的sum1(),方法体为i + 10
        // 6.这里的属性i是在A类声明的,则i = 10,则a.sum1() = 10 + 10 = 20
    }
}

class A {
    public int i = 10;

    public int sum() {
        return getI() + 10;
    }

    public int sum1() {
        return i + 10;
    }

    public int getI() {
        return i;
    }
}

class B extends A {
    public int i = 20;

    public int getI() {
        return i;
    }
}

6.应用:多态数组

多态数组:数组的定义类型为父类类型,里面保存的实际元素类型为子类类型

1)应用实例:要求创建1个Person对象,2个Student对象和2个Teacher对象,统一放在数组中,并调用每个对象的say()

java 复制代码
package test;

public class Main {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("jack", 20);
        persons[1] = new Student("aroma", 22, 100);
        persons[2] = new Student("kira", 23, 60);
        persons[3] = new Teacher("nancy", 32, 3000);
        persons[4] = new Teacher("vicky", 35, 4000);
        System.out.println("姓名    年龄 成绩/薪水");
        for (int i = 0; i < persons.length; i++) {
            System.out.println(persons[i].say()); // 动态绑定机制:persons[i]的运行类型会根据实际情况进行改变
        }
    }
}

class Person {
    private String name;
    private int age;

    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 String say() {
        return name + "\t" + age;
    }
}

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(int score) {
        this.score = score;
    }

    public String say() {
        return super.say() + " " + score;
    }
}

class Teacher extends Person {
    private double salary;

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String say() {
        return super.say() + " " + salary;
    }
}

2)应用示例:Teacher类有teach(),Student类有study(),如何调用子类特有的方法

java 复制代码
package test;

public class Main {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("jack", 20);
        // 多态的向上转型:此时对象是无法调用运行类型特有的方法
        persons[1] = new Student("aroma", 22, 100);
        persons[2] = new Student("kira", 23, 60);
        persons[3] = new Teacher("nancy", 32, 3000);
        persons[4] = new Teacher("vicky", 35, 4000);
        System.out.println("姓名    年龄 成绩/薪水");
        for (int i = 0; i < persons.length; i++) {
            System.out.println(persons[i].say()); // 动态绑定机制:persons[i]的运行类型会根据实际情况进行改变
            // 判断对象的运行类型,利用多态的向下转型,再调用运行类型特有的方法
            if (persons[i] instanceof Teacher) {
                ((Teacher) persons[i]).teach();
            }else if (persons[i] instanceof Student) {
                ((Student) persons[i]).study();
            } else if (persons[i] instanceof Person) {
                System.out.println("该对象类型为Person,不做任何处理");
            } else {
                System.out.println("该对象的类型有误,请检查代码");
            }
        }
    }
}

class Person {
    private String name;
    private int age;

    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 String say() {
        return name + "\t" + age;
    }
}

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(int score) {
        this.score = score;
    }

    public String say() {
        return super.say() + " " + score;
    }

    public void study() {
        System.out.println("学生" + getName() + "正在学习...");
    }
}

class Teacher extends Person {
    private double salary;

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String say() {
        return super.say() + " " + salary;
    }

    public void teach() {
        System.out.println("老师" + getName() + "正在授课...");
    }
}

7. 应用:多态参数

多态参数:方法定义的形参类型为父类类型,实参类型允许为子类类型

1)应用示例:主人给动物(猫、狗)喂食(鱼、骨头)

java 复制代码
public class Main {
    public static void main(String[] args) {
        Master master = new Master("aroma");
        Cat cat = new Cat("牛奶");
        Dog dog = new Dog("大黄");
        Fish fish = new Fish("鱼罐头");
        Bone bone = new Bone("骨头罐头");
        master.feed(cat, fish);
        master.feed(dog, bone);
    }
}

class Master {
    private String name;

    public Master() {
    }

    public Master(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    public void feed(Animal animal, Food food) {
        System.out.println("主人" + name + "给" + animal.getName() + "吃" + food.getFoodName());
    }
}

class Animal {
    private String name;

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

    public String getName() {
        return name;
    }

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

class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
}

class Dog extends Animal{
    public Dog(String name) {
        super(name);
    }
}

class Food {
    private String foodName;

    public Food() {
    }

    public Food(String foodName) {
        this.foodName = foodName;
    }

    public String getFoodName() {
        return foodName;
    }

    public void setFoodName(String foodName) {
        this.foodName = foodName;
    }
}

class Fish extends Food{
    public Fish(String foodName) {
        super(foodName);
    }
}

class Bone extends Food{
    public Bone(String foodName) {
        super(foodName);
    }
}

2)应用示例:

  1. 定义员工类Employee,包含姓名和月工资(private),计算年工资getAnnual();
  2. 普通员工和经理继承员工类,普通员工类有work(),经理类有奖金bonus属性和管理manage();
  3. 普通员工和经理类要求分别重写getAnnual();
  4. 测试类中添加方法①showEmployeeAnnual(Employee e)来获取任何员工对象的年工资,②testWork():如果是普通员工,则调用work(),如果是经理,则调用manage()
java 复制代码
package test;

public class Test {
    public static void main(String[] args) {
        Staff staff = new Staff("kira", 10000);
        Manager manager = new Manager("aroma", 20000, 2000);
        Test t = new Test();
        t.showEmployeeAnnual(staff);
        t.showEmployeeAnnual(manager);
        t.testWork(staff);
        t.testWork(manager);
    }

    public void showEmployeeAnnual(Employee e) {
        System.out.println("该员工年工资:" + e.getAnnual());
    }

    public void testWork(Employee e) {
        if (e instanceof Manager) {
            ((Manager) e).manage();
        }else if (e instanceof Staff) {
            ((Staff) e).work();
        }else {
            System.out.println("类型有误,请检查代码");
        }
    }
}

class Employee {
    private String name;
    private double monthSalary;

    public Employee(String name, double monthSalary) {
        this.name = name;
        this.monthSalary = monthSalary;
    }

    public String getName() {
        return name;
    }

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

    public double getMonthSalary() {
        return monthSalary;
    }

    public void setMonthSalary(double monthSalary) {
        this.monthSalary = monthSalary;
    }

    public double getAnnual() {
        return monthSalary * 12;
    }
}

class Staff extends Employee {
    public Staff(String name, double monthSalary) {
        super(name, monthSalary);
    }

    public void work() {
        System.out.println("普通员工" + getName() + "正在工作...");
    }

    @Override
    public double getAnnual() {
        return super.getAnnual();
    }
}

class Manager extends Employee {
    private double bonus;

    public Manager(String name, double monthSalary,double bonus) {
        super(name, monthSalary);
        this.bonus = bonus;
    }

    public void manage() {
        System.out.println("经理" + getName() + "正在管理...");
    }

    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
}
相关推荐
Tanecious.1 小时前
机器视觉--python基础语法
开发语言·python
叠叠乐1 小时前
rust Send Sync 以及对象安全和对象不安全
开发语言·安全·rust
战族狼魂1 小时前
CSGO 皮肤交易平台后端 (Spring Boot) 代码结构与示例
java·spring boot·后端
Tttian6222 小时前
Python办公自动化(3)对Excel的操作
开发语言·python·excel
xyliiiiiL2 小时前
ZGC初步了解
java·jvm·算法
杉之3 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
hycccccch3 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
独好紫罗兰4 小时前
洛谷题单2-P5713 【深基3.例5】洛谷团队系统-python-流程图重构
开发语言·python·算法
天天向上杰4 小时前
面基JavaEE银行金融业务逻辑层处理金融数据类型BigDecimal
java·bigdecimal
闪电麦坤955 小时前
C#:base 关键字
开发语言·c#