java面向对象编程三大特征

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

基本介绍

面向对象编程有三大特征封装继承多态

封装介绍

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

封装的理解和好处

1.隐藏实现细节方法(连接数据库)< – 调用(传入参数…)
2.可以对数据进行验证保证安全合理

封装的实现步骤(三步)

1.将属性进行私有化private 【不能直接修改属性】
2.提供一个公共的(public)set方法 用于对属性判断并赋值
public void setXxx(类型 参数名) { //Xxx表示某个属性
//加入数据验证的业务逻辑
属性 = 参数名
}
3.提供一个公共的(public)get方法用于获取属性的值
public 数据类型 getXxx() {//权限判断Xxx某个属性
return xx;
}

快速入门案例

编写一个小程序不能随便查看人的年龄工资等隐私并对设置的年龄进行合理的验证。年龄合理就设置否则给默认年龄必须在1-120年龄工资不能直接看name的长度在2-6个字符

代码

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class Encapsulation01 {
    public static void main(String[] args) {
        Person person = new Person();
        Person person02 = new Person("小明", 10000, 20000);
        System.out.println("=====小明的信息=======");
        System.out.println(person02.info());
        person.setName("李华");
        person.setAge(180);
        person.setSalary(25000);
        System.out.println(person.info());
    }
}
class Person {
    public String name; //姓名公开化
    private int age;    //名字私有化
    private double salary; //薪水私有化

    public void say(int n, String name) {

    }

    //构造器
    public Person() {

    }

    //有三个属性的构造器
    public Person(String name, int age, double salary) {
//        this.age = age;
//        this.name = name;
//        this.salary = salary;
        setAge(age);
        setSalary(salary);
        setName(name);
    }

    //get and set
    public String getName() {
        return name;
    }

    public void setName(String name) {
        //加入对数据的校验相当于增加了业务逻辑
        if (name.length() >= 2 && name.length() <= 6) {
            this.name = name;
        } else {
            System.out.println("名字的长度不对需要(2-6)个字符");
            this.name = "无名人";
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        //判断
        if (age >= 1 && age <= 120) {
            this.age = age;
        } else {
            System.out.println("你设计年龄不对需要在(1-120),给默认年龄18");
            this.age = 18; //设计一个默认年龄
        }
    }

    public double getSalary() {
        return salary;
    }

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

    //返回属性
    public String info() {
        return "信息为 name= " + name + " age= " + age + " 薪水= " + salary;
    }
}

将构造器和setXxx结合

我们在上面代码主可以注意我们就set()方法和 构造器结合了是因为这样就可以避免通过构造器破坏了封装的特性

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

继承基本介绍

继承可以解决代码的复用性让我们的编程更加接近人类思维当多个类存在相同的属性(b变量)和方法时可以从这些类中抽象出父类在父类中定义这些相同的属性和方法所有的子类不需要重新定义这些属性和方法只需要通过extends来声明继承父类即可。

继承的基本语法

class 子类extends 父类 {
}
1.子类就会自动拥有父类定义的属性和方法
2.父类又叫超类基类
3.子类又叫派生类

快速入门案例

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class Extends01 {
    public static void main(String[] args) {
        College college = new College();
        college.age = 20;
        college.name = "李华";
        college.setScore(100);
        college.showinfo();
        college.testing();
    }
}
//父类Student
class Student {
    //共有属性
    public String name;
    public int age;
    private double score;   //成绩

    //共有方法
    public void setScore(double score) {
        this.score = score;
    }

    public void showinfo() {
        System.out.println("name: " + name + " age: " + age + " score: " + score);
    }
}

class Pupil extends Student {
    public void test() {
        System.out.println("Pupil " + name + "is testing");
    }
}

class College extends Student {
    public void testing() {
        System.out.println("College " + name + " is testing");
    }
}

继承给编程带来的便利

1.代码复用性提高
2.代码的扩展性和维护性提高了

继承的深入讨论/细节问题

1.子类继承了所有的属性和方法非私有的属性和方法可以在子类直接访问但是私有的属性和方法不能在子类直接访问要通过父类提供的方法去访问
2.子类必须调用父类的构造器完成父类的初始化
3.当创建子类对象时不管使用子类的哪个构造器默认情况下总会去调用父类的无参构造器如果父类没有提供无参构造器则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作否则编译不会通过。
4.如果希望指定去调用父类的某个构造器则显示的调用一下super(参数列表)
5.super()在使用时必须放在构造器的第一行(super只能在构造器中使用)
6.super()和this()都只能放在构造器第一行因为这两个方法不能共存在一个构造器
7.java所有类都是Object的子类Object是所有类的基类
8.父类构造器的调用不限于直接父类将一直向上一直追溯到Object类(顶级父类)
9.子类只能继承一个父类(指直接继承)即java中是单继承机制。(但假设B类继承于A类C类继承于B类那么相当于C类也继承于A类)
10.不能滥用继承子类和父类之间必须满足is-a的逻辑关系

代码

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class ExtendDetail {
    public static void main(String[] args) {
        System.out.println("===第1个对象===");
        Sub sub = new Sub();
        System.out.println("===第2个对象===");
        Sub jack = new Sub("Jack");
        System.out.println("===第3个对象===");
        Sub king = new Sub("King", 10);

    }
}

class Base {    //父类
    //4个属性
    public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public Base() {//无参构造器
        System.out.println("父类Base()构造器被调用...");
    }
    public Base(String name, int age) { //有参构造器
        //默认super()
        System.out.println("父类Base(String name, int age)构造器被调用...");
    }
    public Base(String name) { //有参构造器
        //默认super()
        System.out.println("父类Base(String name)构造器被调用...");
    }

    //父类提供一个public方法返回了n4
    public int getN4() {
        return n4;
    }
    public void test100() {
        System.out.println("test100");
    }
    protected void test200() {
        System.out.println("test200");
    }
    void test300() {
        System.out.println("test300");
    }
    private void test400() {
        System.out.println("test400");
    }

    //方法call用于调用私有方法test400
    public void call() {
        this.test400();
    }
}

class Sub extends Base {    //子类
    public Sub(String name, int age) {
        //1.调用父类的无参构造器如下或则什么否不写默认就是调用super()
        //super();  //父类的无参构造器

        //2.调用父类的Base(String name)构造器
        //super("李华");

        //3.调用父类Base(String name, int age)构造器
        super("李华",20);

        /*
        1. super()在使用时必须放在构造器的第一行(super只能在构造器中使用)
        2. super()和this()都只能放在构造器第一行因为这两个方法不能共存在一个构造器
         */
        //this()不能再使用
        System.out.println("子类Sub(String name, int age)构造器被调用...");
    }

    public Sub() {
        //super();  //默认调用父类的无参构造器
        super("smith",10);
        System.out.println("子类Sub()构造器被调用...");
    }

    //当创建子类对象时不管使用子类的哪个构造器默认情况下总会去调用父类的无参构造器
    public Sub(String name) {
        super("Tom",30);
        System.out.println("子类Sub(String name)构造器被调用...");
    }

    public void sayOk() {   //子类方法
        // 非私有属性和方法可以在子类直接访问
        // 但是私有属性和方法不能在子类直接访问
        System.out.println(n1 + " " + n2 + " " + n3);

        test100();
        test200();
        test300();
        //test400() //错误
        //需要父类提供的公共方法去访问
        System.out.println("n4= " + getN4());
    }



}
//class TopBase { //父类是Object
//
//    public TopBase() {
//        //super(); Object的无参构造器
//        System.out.println("构造器TopBase()被调用...");
//    }


继承的本质分析

当子类对象创建好了之后建立查找的关系

1.首先看子类是否有该属性
2.如果子类有这个属性并且可以访问则放回信息
3.如果子类没有该属性就看父类是否有该属性若父类没有则一级级往上找直到Object…

代码案例

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class ExtendTheory {
    public static void main(String[] args) {
        Son son = new Son();
        System.out.println(son.name);   //大头儿子
        System.out.println(son.getAge());   //39
        System.out.println(son.hobby);  //钓鱼
    }
}
class Grandpa {
    String name = "大头爷爷";
    String hobby = "钓鱼";
}

class Father extends Grandpa {
    String name = "小头爸爸";
    private int age = 39;

    public int getAge() {
        return age;
    }
}

class Son extends Father {
    String name = "大头儿子";
}

继承的练习题

题目1分析下面代码输出的结果

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class ExtendExercise01 {
    public static void main(String[] args) {
        B b = new B();
    }
}
class A {
    public A() {
        System.out.println("a");
    }
    public A(String name) {
        System.out.println("a name");
    }
}
class B extends A {
    public B() {
        this("hahaha");
        System.out.println("b");
    }
    public B(String name) {
        System.out.println("b name");   //默认有super()会调用父类无参构造器
    }
}

结果输出a b name b。 解释如下

使用无参构造器创建B类对象时再B类无参构造器中先执行this【这会调用本类的对应带参构造器】然后执行到B类的带参构造器但是B类继承于A类所以再带参数构造器之前会默认初始化A类的无参构造器。

题目2分析下面代码输出的结果

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class ExtendExercise02 {
    public static void main(String[] args) {
        C c = new C();  //输出什么
    }
}
class A {
    public A() {
        System.out.println("我是A类");
    }
}

class B extends A {
    public B() {
        System.out.println("我是B类的无参构造器");
    }

    public B(String name) {
        System.out.println(name + "我是B类的有参构造器");
    }
}

class C extends B {
    public C() {
        this("hello");
        System.out.println("我是c类的无参构造器");
    }

    public C(String name) {
        super("hahaha");
        System.out.println("我是C类的有参构造器");
    }
}

题目3按要求编写下面程序

1.编写Computer类包含CPU、内存、硬盘等属性getDetails方法用于返回Computer的详细信息
2.编写PC子类继承Computer类添加特有属性【品牌brand】
3.编写NotePad子类继承Computer类添加特有属性【color】
4.编写Test类在main方法中创建PC和NotePad对象分别给对象特有的属性赋值以及从Computer类继承的属性赋值并使用方法并打印输出信息

代码

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class Test {
    public static void main(String[] args) {
        PC pc = new PC("intel", 16, 500, "IBM");
        pc.printInfo();
    }
}
class Computer {
    private String cpu;
    private int memory;
    private int disk;

    public Computer(String cpu, int memory, int disk) {
        this.cpu = cpu;
        this.memory = memory;
        this.disk = disk;
    }

    public String getCpu() {
        return cpu;
    }

    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public int getMemory() {
        return memory;
    }

    public void setMemory(int memory) {
        this.memory = memory;
    }

    public int getDisk() {
        return disk;
    }

    public void setDisk(int disk) {
        this.disk = disk;
    }

    //返回Computer
    public String getDetail() {
        return "cpu= " + cpu + " memory= " + memory + " disk= " + disk;
    }

}

//编写子类PC继承Computer
class PC extends Computer {
    private String brand;

    public PC(String cpu, int memory, int disk, String brand) {
        super(cpu, memory, disk);
        this.brand = brand;
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public void printInfo() {
        System.out.println("PC的信息为:");
        //System.out.println(getCpu() + getMemory() + getDisk()); //子类使用父类提供的公有方法
        System.out.println(getDetail() + " brand= " + this.brand);   //利用继承特性使用父类方法
    }

}

//编写NotePad继承Computer类
class NotePad extends Computer {
    private String color;

    public NotePad(String cpu, int memory, int disk, String color) {
        super(cpu, memory, disk);
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public void printInfo() {
        System.out.println("NotePad的信息为:");
        System.out.println(getDetail() + " brand= " + this.color);   //利用继承特性使用父类方法

    }
}

super关键字

基本介绍

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

基本语法

1.访问父类的属性但不能访问父类的private属性【super.属性名
2.访问父类的方法但不能访问父类的private方法【super.方法名(形参列表)
3.访问父类的构造器【super(参数列表)只能放在构造器的第一句只能出现一句】

代码案例

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class Super {
    public static void main(String[] args) {
        B b = new B();
        b.test();
    }
}

class Base {
    public int n1 = 999;
    public int age = 111;

    public void cal() {
        System.out.println("Base类的cal()方法...");
    }

    public void eat() {
        System.out.println("Base类的eat()方法...");
    }

}

class A extends Base {
    //public int n1 = 100;
    protected int n2 = 200;
    int n3 = 300;
    private int n4 = 400;

    public A() {}
    public A(String name) {}
    public A(String name, int age) {}

    public void cal() {
        System.out.println("A类的cal()方法...");
    }

    public void teat100() {

    }
    protected void teat200() {

    }
    void teat300() {

    }
    private void teat400() {

    }
}

class B extends A {
    public int n1 = 888;
    //编写测试方法
    public void test() {
        // super的访问不限于直接父类如果爷爷类和本类中有同名的成员也可以
        //使用super去访问爷爷类的成员
        //如果多个基类(上级类)中都有同名的成员使用super访问遵循就近原则 A -> B -> C
        System.out.println("super.n1= " + super.n1);
        super.cal();
    }

    //访问父类的属性但不能访问父类的private属性
    public void hi() {
        System.out.println(super.n1 + " " + super.n2 + " " + super.n3);
    }

    public void cal() {
        System.out.println("B类的cal()方法...");
    }
    public void sum() {
        System.out.println("B类的sum()");
        //希望调用父类A的cal方法
        //这时因为子类B没有cal方法因此我们可以使用下面三种方式

        //找cal方法时(cal() 和this.cal()),顺序是
        //1.先找本类若有则返回
        //2.如果没有则找父类(如果有并可以调用则调用)
        //3.如果父类没有这接着往上一级父类找下去直到找到Object类
        //提示   如果查找方法的过程中找到了但是不能访问则报错cannot access
        //        如果查找方法过程中没有找到则提示方法不存在
        this.cal();//等价cal()

        //找cal方法(super.cal())的顺序是直接查找父类其他的规则一样
        //super.cal();

        //演示访问属性的规则
        //n1和this.n1查找的规则是
        //1.先找本类如果有则调用
        //2.如果没有则找父类(如果有并可以调用则调用)
        //3.如果父类没有这接着往上一级父类找下去直到找到Object类
        //提示   如果查找属性的过程中找到了但是不能访问则报错cannot access
        //        如果查找属性过程中没有找到则提示属性不存在
        System.out.println(n1);
        System.out.println(this.n1);

        //找n1(super.n1)的顺序是直接查找父类其他的规则一样
        System.out.println(super.n1);
    }

    //访问父类的方法不能访问父类的private方法
    public void ok() {
        super.teat100();
        super.teat200();
        super.teat300();
        //super.test400();  //不能访问父类private方法
    }

    //访问父类的构造器super(参数列表);只能放在构造器的第一句稚嫩出现一句
    public B() {
        super("jack");
    }

}

super给编程带来的遍历/细节

1.调用父类的构造器的好处(分工明确父类属性由父类初始化子类的属性由子类初始化)
2.当子类中有父类中的成员(属性和方法)重名时为了访问父类的成员必须通过super。如果没有没有重名使用super、this、直接访问是一样的效果
3.super的访问不限于直接父类如果爷爷类和本类中有同名的成员也可以使用super去访问爷爷类的成员如果多个基类(上级类)中都有同名的成员使用super访问遵循就近原则当然也需要尊守相关的访问权限。

super和this地比较

NO.区别点thissuper
1访问属性访问本类地属性如果本类没有此属性则从父类中继续查找从父类开始查找属性
2调用方法访问本类中地方法如果本类没有此方法则从父类继续查找从父类开始
3调用构造器调用本类构造器必须放在构造器的首行调用父类构造器必须放在子类构造器的首行
4特殊表示当前对象子类中访问父类对象

方法重写/覆盖(override)

基本介绍

简单来说 方法重写/覆盖(override)就是子类有一个方法和父类的某个方法的名称、返回类型、参数一样那么我们就说子类的这个方法覆盖了父类的方法。

注意事项和使用细节

方法重写也叫方法覆盖需要满足下面的条件

1.子类的方法的形参列表方法名称要和父类的形参列表方法名称完全一样。
2.子类方法的返回类型和父类方法返回类型一样或者是父类返回类型的子类
3.子类方法不能缩小父类方法的访问权限【public > protected > 默认 > private】

快速入门代码案例

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class Override01 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.cry();
    }
}
class Animal {
    public void cry() {
        System.out.println("动物叫唤...");
    }

    public Object m1() {
        return null;
    }

    public String m2() {
        return null;
    }

    public AAA m3() {
        return null;
    }

    protected void eat() {

    }

}

class Dog extends Animal {
    //因为Dog事Animal的子类
    //Dog的cry方法和Animal的cry定义形式一样(名称、返回类型、参数)
    //这时我们说Dog的cry重写了Animal的cry方法

    @Override
    public void cry() {
        System.out.println("小狗汪汪叫...");
    }

    //细节:子类方法的返回类型和父类方法返回类型一样
    //      或者是父类返回类型的子类


    //比如父类是Object子类方法返回类型是String
    @Override
    public String m1() {
        return null;
    }

    //这里Object不是String的子类因此编译错误

//    @Override
//    public Object m2() {
//        return null;
//    }

    @Override
    public BBB m3() {
        return null;
    }

    //细节子类方法不能缩小父类方法的访问权限
    // public > protected > 默认 > private

    @Override
    public void eat() {

    }
}
class AAA {}

class BBB extends AAA {}

方法重载和重写的比较

名称发生范围方法名形参列表返回类型修饰符
重载(overload)本类必须一样类型个数或者顺序至少有一个不同无要求无要求
重写父子类必须一样相同子类重写的方法返回的类型和父类返回的类型一致或者是其子类子类方法不能缩小父类方法的访问范围

多[多种]态[状态]基本介绍

方法或对象具有多种形态。是面向对象的第三大特征多态是建立在封装和继承的基础之上的。

多态的具体体现

方法的多态

重载和重写就体现多态

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class PloyMethod {
    public static void main(String[] args) {
        A a = new A();
        //方法重载体现多态
        //这里传入不同的参数就会调用不同的sum方法就体现多态
        System.out.println(a.sum(1,2));
        System.out.println(a.sum(1,2,3));

        //方法重写体现多态
        B b = new B();
        a.say();
        b.say();
    }
}
class B {
     public void say() {
         System.out.println("B say()方法被调用...");
     }
}
class A extends B {
    public int sum(int n1, int n2, int n3) {
        return n1 + n2 + n3;
    }

    //方法的重载体现多态
    public int sum(int n1, int n2) {
        return n1 + n2;
    }

    @Override
    public void say() {
        System.out.println("A say()方法被调用...");
    }
}

对象的多态(核心难点)

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

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class PloyObject {
    public static void main(String[] args) {
        //animal编译类型是Animal运行类型是Dog
        Animal animal = new Dog();
        //因为运行时执行到改行时animal运行类型时Dog所以cry就是Dog的cry
        animal.cry();   //小狗汪汪叫

        //animal 编译类型Animal运行类型时Cat
        animal = new cat();
        animal.cry();   //小猫喵喵叫
    }
}
class Animal {
    public void cry() {
        System.out.println("Animal cry(),动物在叫唤....");
    }
}
class cat extends Animal {
    @Override
    public void cry() {
        System.out.println("Cat cry() 小猫在喵喵叫.....");
    }
}
class Dog extends Animal {
    @Override
    public void cry() {
        System.out.println("Dog cry()小狗在汪汪叫....");
    }
}

多态注意事项和细节讨论

多态的前提是两个对象(类)存在继承关系
多态的向上转型:

1.本质父类的引用指向子类的对象
2.语法父类类型 引用名 = new 子类类型();
3.特点编译类型看左边运行类型看右边。可以调用父类中的所有成员(需要遵守访问权限),不能调用子类中的特有成员最终运行结果看子类的具体实现

多态的向下转型

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

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class PloyDetail {
    public static void main(String[] args) {
        // 父类的引用指向子类的对象
        // 语法父类类型	引用名	= new 子类类型();
        Animal animal = new Cat();
        //Object obi = new Cat(); //也可以Object也是Cat的父类

        //多态的向上转型规则如下
        //1.可以调用父类中的所有成员(需要遵守访问权限),
        //2.不能调用子类中的特有成员
        //*因为在编译阶段能调用那些成员是由编译类型来决定的
        //animal.catchMouse(); 错误
        //4.最终运行效果看子类(运行类型)的具体实现即调用方法时按照从子类(运行类型)开始查找的方法
        //然后调用规则和继承中讲到的调用方法一致
        animal.eat();   //猫吃鱼
        animal.run();   //跑
        animal.show();  //hello 你好
        animal.sleep(); //睡

        //多态的向下转型
        //1.子类类型 引用名 = (子类类型) 父类引用;.当向下转型后可以调用子类类型中所有的成员
        Cat cat = (Cat) animal;
        cat.catchMouse();   //猫抓老鼠
        //2.要求父类的引用必须指向的是当前目标类型的对象
        //Dog dog = (Dog) animal;   //在运行时候会出错因为在29行已经将animal
                                    //强制转换为Cat对象(目标对象)此时不可再将Cat对象转换
                                    //为同为Animal子类的狗类

    }
}
class Animal {
    String name = "动物";
    int age = 10;
    public void sleep() {
        System.out.println("睡");
    }
    public void run() {
        System.out.println("跑");
    }
    public void eat() {
        System.out.println("吃");
    }
    public void show() {
        System.out.println("hello,你好");
    }
}

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

    //猫类特有方法子类特有方法不能被调用
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

class Dog extends Animal {

}

属性没有重写之说属性的值看编译类型

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class PloyDetail02 {
    public static void main(String[] args) {
        //属性没有重写之说属性的值看编译类型
        Base base = new Sub();
        System.out.println(base.count); //看编译类型10
        Sub sub = new Sub();
        System.out.println(sub.count);  //20
    }
}
class Base {
    int count = 10;
}
class Sub extends Base {
    int count = 20;
}

instanceOf比较操作符用于判断对象运行类型是否为XX类型或者XX类型的子类型

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class PloyDetail03 {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb instanceof BB);   //trueBB类型
        System.out.println(bb instanceof AA);   //true;AA类的子类

        //aa编译类型AA运行类型是BB
        //BB是AA子类
        AA aa = new BB();
        System.out.println(aa instanceof AA);   //true
        System.out.println(aa instanceof BB);   //true
        
        Object obj = new Object();
        System.out.println(obj instanceof AA);  //false
        String str = "hello";
        System.out.println(str instanceof  Object); //true
    }
}
class AA {

}
class BB extends AA {}

动态绑定机制

1.当调用对像方法的时候该方法会和对象的内存地址/运行类型绑定
2.当调用对象属性时没有动态绑定机制哪里声明哪里使用。

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class DynamicBinding {
    public static void main(String[] args) {
        //a的编译类型A运行类型B
        A a = new B();
        System.out.println(a.sum());    //30
    }
}
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;
    }
}

改代码会输出“30”原因是由于动态绑定先看运行类型B调用B类的sum方法但是此时已经注销B类的sum()方法则又会触发继承机制调用A类的sum()方法但是由于A类sum()方法中getI()方法还是要看运行类型B的则会调用B类的gatI()方法但又由于属性没有动态绑定机制则B类中的getI()方法会返回20最后20+10得到30

多态的引用

1.多态数组

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

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:创建一个Person对象2个Student对象和2个Teacher对象
 *              并调用每个对象say方法
 */
public class PloyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("jack",20);
        persons[1] = new Student("mary",18,100);
        persons[2] = new Student("smith",19,30.2);
        persons[3] = new Teacher("scott",30,20000);
        persons[4] = new Teacher("king",50,25000);

        //循环遍历多态数组调用say
        for (int i = 0; i < persons.length; i++) {
            //persons[i]编译类型是Person运行类型是根据实际情况由JVM来判断
            System.out.println(persons[i].say());
            if (persons[i] instanceof Student) {
                Student student = (Student) persons[i];
                student.study();
            } else if (persons[i] instanceof Teacher) {
                Teacher teacher = (Teacher) persons[i];
                teacher.teach();
            } else if (persons[i] instanceof 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(double score) {
        this.score = score;
    }
    //重写父类say()方法

    @Override
    public String say() {
        return "学生" + super.say() + " score= " + score;
    }
    //特有方法
    public void study() {
        System.out.println("学生 " + getName() + " 正在学习java...");
    }
}

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;
    }

    //重写父类的say()方法

    @Override
    public String say() {
        return "老师 " + super.say() + " salary= " + salary;
    }

    //特有方法
    public void teach() {
        System.out.println("老师 " + getName() + "正在讲java课程...");
    }
}

多态参数

方法定义的形参类型为父类实参类型允许为子类类型

案例

定义员工类Employee包含姓名和越工资[private]以及计算年工资getAnnual的方法。普通员工和经理继承员工经理多了奖金bonus属性和管理manage方法普通员工类多了work方法普通员工和经理要求重写getAnnual方法
测试类中添加一个方法showEmpAnnual(Employee e), 实现获取任何员工对象的年工资并在main方法中调用该方法[e.getAnnual()]
测试类中添加一个方法testWork如果是普通员工则调用work方法如果是经理则调用manage方法。

package review.javaSE_.oop_;

/**
 * @author: ln
 * @data:
 * @description:
 */
public class PloyParameter {
    public static void main(String[] args) {
        PloyParameter ployParameter = new PloyParameter();
        Worker tom = new Worker("tom", 25000);
        Manager milan = new Manager("milan", 5000, 200000);
        ployParameter.showEmpAnnual(tom);
        ployParameter.showEmpAnnual(milan);
        ployParameter.testWork(tom);
        ployParameter.testWork(milan);
    }

    public void showEmpAnnual(Employee e) {
        System.out.println(e.getAnnual());  //动态绑定机制
    }

    //添加一个方法testWork,如果是普通员工则调用work方法如果是经理则调用manage方法。
    public void testWork(Employee e) {
        if (e instanceof Worker) {
            Worker worker = (Worker) e;
            worker.work();
        } else if (e instanceof Manager) {
            Manager manager = (Manager) e;
            manager.manage();
        } else {
            System.out.println("不做处理...");
        }
    }
}

class Employee {
    private String name;
    private double salary;

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

    public String getName() {
        return name;
    }

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

    public double getSalary() {
        return salary;
    }

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

    //计算年工资
    public double getAnnual() {
        return this.salary * 12;
    }
}

class Manager extends Employee {
    private double bonus;

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

    public double getBonus() {
        return bonus;
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }

    //重写获取年薪的方法
    @Override
    public double getAnnual() {
        return super.getAnnual() + this.bonus;
    }

    //特有方法manage
    public void manage() {
        System.out.println("经理 " + getName() + " is managing");
    }
}

class Worker extends Employee {
    public Worker(String name, double salary) {
        super(name, salary);
    }

    @Override
    public double getAnnual() {//普通员工没有其他收入直接调用父类方法
        return super.getAnnual();
    }

    //特有work方法
    public void work() {
        System.out.println("员工 " + getName() + " is working");
    }
}

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: Java