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;
    }
}
相关推荐
lsx2024068 分钟前
Perl 面向对象编程指南
开发语言
Allen Bright29 分钟前
【Java基础-46.3】Java泛型通配符详解:解锁类型安全的灵活编程
java·开发语言
柃歌32 分钟前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
柃歌42 分钟前
【UCB CS 61B SP24】Lecture 4 - Lists 2: SLLists学习笔记
java·数据结构·笔记·学习·算法
画个逗号给明天"42 分钟前
C++STL容器之list
开发语言·c++
是姜姜啊!1 小时前
redis的应用,缓存,分布式锁
java·redis·spring
梨落秋溪、1 小时前
输入框元素覆盖冲突
java·服务器·前端
hrrrrb1 小时前
【Java】Java 常用核心类篇 —— 时间-日期API(上)
java·开发语言
小突突突1 小时前
模拟实现Java中的计时器
java·开发语言·后端·java-ee
七禾页话1 小时前
垃圾回收知识点
java·开发语言·jvm