JAVA面向对象三大特征

1.面向对象的三大特征包括封装、继承和多态。

  1. 封装:封装是指将数据和操作数据的方法绑定起来,外界对数据的访问只能通过已定义的接口。这种特性有两层含义,一层是将属性和行为看成一个密不可分的整体,将这两者封装在一个对象中;另一层含义是信息隐藏,把不需要让外界知道的信息隐藏起来。这种特性可以保护对象内部的结构和数据,使得对成员变量的访问只能通过已定义的接口实现。
  2. 继承:继承指从已有的类(也称为父类、基类、超类)得到继承信息创建新类(也称为子类、派生类)的过程。子类继承父类的特征和行为,使得子类对象实例具有父类的实例和方法,子类从父类继承方法,使得子类具有父类相同的行为。继承可以减少代码的重复性,提高代码的可维护性和可重用性。
  3. 多态:多态指允许不同的对象对同一消息(发送消息即函数调用)作出不同的响应。多态的实现条件包括继承和重写。子类可以重写父类的方法,使得子类可以根据自己的需要实现特定的行为。多态可以增强代码的可读性和可维护性,同时也可以提高代码的灵活性和扩展性。

总之,封装、继承和多态是面向对象编程的三大基本特征,它们使得程序更加模块化、可维护性和可重用性更高。

2.封装

好处:

1.隐藏实现细节,只管调用

2.可以对数据进行验证,保证安全合理 (private 在同类可改)

封装入门

package com.hspedu;

public class Encapsulation01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("jack8080");
        person.setAge(300);
        person.setSalary(30000);
        System.out.println(person.info());
    }
}
/*
* 要求:年龄,工资为隐私
* 数据验证:年龄(1-120) 不合理给默认年龄
* name 2-6个字符
* */
class Person {
    public String name;
    private int age;
    private double salary;
    //使用快捷键 
    public String getName() {
        return name;
    }

    public void setName(String name) {
        if(name.length() >= 2 && name.length() <= 6){
            this.name = name;
        }else {
            System.out.println("name 需要在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");
            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;
    }

}

封装与构造器 

package com.hspedu;

public class Encapsulation01 {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("jack8080");
        person.setAge(300);
        person.setSalary(30000);
        System.out.println(person.info());
        //使用构造器指定属性
        Person smith = new Person("smith", 80, 50000);
        System.out.println("===smith的信息===");
        System.out.println(smith.info());
    }
}
/*
* 要求:年龄,工资为隐私
* 数据验证:年龄(1-120) 不合理给默认年龄
* name 2-6个字符
* */
class Person {
    public String name;
    private int age;
    private double salary;
    public Person(){

    }

    public Person(String name, int age, double salary) {
        //用构造器会被破解,要在构造器中使用方法
//        this.name = name;
//        this.age = age;
//        this.salary = salary;
        setName(name);
        setAge(age);
        setSalary(salary);
    }

    //使用快捷键
    public String getName() {
        return name;
    }

    public void setName(String name) {
        if(name.length() >= 2 && name.length() <= 6){
            this.name = name;
        }else {
            System.out.println("name 需要在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");
            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;
    }

}

3.继承 

好处:

1.代码复用,在父类中定义相同的属性和方法

2.拓展性,维护性提高了

细节:

1.可以用父类的公共方法将私有属性,方法返回数据给子类

访问级别 访问控制修饰符 同类 同包 子类 不同包
公开 public
受保护 protected ×
默认 没有修饰符 × ×
私有 private × × ×

2.子类必须调用父类的构造器,完成父类初始划 默认子类有super();调用父类无参构造器。若父类没有无参构造器,得用super(参数列表)去指定。

3.子类调用父类的构造器,要将super放在第一行

4.super()和this()都只能放在构造器第一行,因此两个方法不能共存在一个构造器

5.Object是所有类的基类 ctrl + H 可以看到类的继承关系(IDEA) 

6.子类最多只能继承一个父类,且与父类要有逻辑关系



public class ExtendsExercise {
    public static void main(String[] args) {
        B b = new B();
    }
}

class A {
    A() {
        System.out.println("a");
    }
    A(String name) {
        System.out.println("a name");
    }
}

class B extends A {
    B(){
        this("abc");
        System.out.println("b");
    }
    B(String name) {
        System.out.println("b name");
    }
}

结果:

JAVA面向对象三大特征_第1张图片

方法重写(覆盖)

方法重写是指在子类中重新定义(或覆盖)其父类中已有的方法,使其具有不同的实现。方法重写是面向对象编程中实现多态性的重要手段之一。

方法重写需要满足以下条件:

  1. 方法名、参数列表必须与父类中被重写的方法相同。
  2. 访问修饰符不能降低(可以提升)。
  3. 返回类型必须与父类中被重写方法的返回类型相同或是其子类。
  4. 抛出的异常类型必须是父类中被重写方法所抛出异常类型的子集,或者子类方法不抛出异常。

方法重写使得子类可以根据自己的需要实现特定的行为,增强了代码的可读性和可维护性,同时提高了代码的灵活性和扩展性。

方法重载和方法重写

是面向对象编程中的两个重要概念,它们都可以实现多态性,但它们之间存在明显的区别。下面是一个表格,总结了方法重载和方法重写的主要区别:

特征 方法重载 方法重写
定义 在同一类中定义多个同名方法,参数列表不同 在子类中重新定义父类中的方法
目的 实现多态性,提供不同的实现方式 实现多态性,子类根据需要实现特定行为
参数列表 不同方法名,参数列表不同 相同方法名,参数列表相同
返回类型 可以不同,但通常是相同或子类关系 相同或子类关系
访问修饰符 可以不同,但通常是相同或更宽松的限制 可以不同,但通常是相同或更宽松的限制
异常类型 可以不同,但通常是相同或更宽松的限制 相同或子类关系
执行时间 编译时多态性,在编译时确定实际调用的方法 运行时多态性,在运行时确定实际调用的方法
使用场景 方法重载通常用于操作类别的不同对象 方法重写通常用于子类扩展父类的行为或接口的实现

这个表格总结了方法重载和方法重写的主要区别。通过理解这些区别,开发人员可以更好地运用这两个概念来设计和实现面向对象的程序。

着重注意super调用构造器和方法 

package com.hspedu.extend_.exercise;

public class OverrideExercise {
    public static void main(String[] args) {
        Person jack = new Person("jack", 10);
        System.out.println(jack.say());
        student smith = new student("smith", 20, 123456, 99.8);
        System.out.println(smith.say());
    }
}



package com.hspedu.extend_.exercise;

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

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String say() {
        return "name=" + name + " 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;
//    }
}



package com.hspedu.extend_.exercise;

public class student extends Person {
    private int id;
    private double score;

    public student(String name, int age, int id, double score) {
        super(name, age);
        this.id = id;
        this.score = score;
    }

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

//    public int getId() {
//        return id;
//    }
//
//    public void setId(int id) {
//        this.id = id;
//    }
//
//    public double getScore() {
//        return score;
//    }
//
//    public void setScore(double score) {
//        this.score = score;
//    }
}

结果: 

4.多态

多态是建立在封装和继承的基础上的。两个对象(类)要存在继承关系

1.方法的多态:

        重写和重载就体现多态。

 2.对象的多态:

(1)一个对象的编译类型和运行类型可以不一致

(2) 编译类型在定义对象时,就确定了,不能改变

(3)运行类型是可以变化的.
(4)编译类型看定义时=号 的左边,运行类型看=号的右边

eg:父类的引用指向子类的对象

Animal animal = new Dog(); [animal编译类型是Anima,运行类型是Dog]

animal = new Cat();[animal 运行类型变为Cat, 编译类型仍为Animal]

ps:找的是运行类型的方法 ,在编译阶段,调用由编译类型决定

3.多态的向上转型

1) 本质:父类的引用指向了子类的对象  Animal animal = new Dog();  //运行类型为编译类型的子类
2) 语法:父类类型引用名 = new 子类类型();

3) 特点:编译类型看左边,运行类型看右边。
可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员,下方不能写animal.catchMouse;预知如何解局,请看向下转型。
最终运行效果看子类的具体实现!

package com.hspedu.extend_.exercise;

public class poly {
    public static void main(String[] args) {
        //多态的向上本质:父类的引用指向了子类的对象
        //语法: 父类类型引用名 = new 子类类型()//object obj = new Cat();
        Animal animal = new Cat();
        System.out.println("ok");
        //最终效果看子类的具体实现
        animal.eat();
        animal.run();
        animal.show();
        animal.sleep();
    }
}



//-------------------------------

package com.hspedu.extend_.exercise;

public 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,你好");
    }
}


//----------------------------------

package com.hspedu.extend_.exercise;

public class Cat extends Animal{
    public void eat(){ //方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

JAVA面向对象三大特征_第2张图片

4.多态的向下转型 

1) 语法:子类类型引用名=(子类类型)父类引用;

2)只能强转父类的引用,不能强转父类的对象
3)要求父类的引用必须指向的是当前目标类型的对象

4)当向下转型后,可以调用子类类型中所有的成员

        //希望可写cat.catchMouse;
        //向下转型
        //语法:子类类型引用名=(子类类型)父类引用;
        Cat cat = (Cat) animal;//此时,编译类型和运行类型皆为Cat
        cat.catchMouse();

5.多态细节 

1.属性没有重写之说!属性的值看编译类型 //方法从运行类型开始查找

package com.hspedu.extend_.exercise;

public class PolyDetail {
    public static void main(String[] args) {
        Base base = new Sub();
        System.out.println(base.count);
    }
}

class Base {
    int count = 10;
}

class Sub extends Base {
    int count = 20;
}

结果为 :10

2.在Java中,instanceof是一个关键字,用于判断一个对象是否属于某个类(子类)或接口。返回值为boolean类型。

eg:System.out.println(base instanceof Base);反映对象(运行类型)与类的关系。

6.动态绑定机制 

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

 7.多态数组(多态的应用)

package com.hspedu.extend_.exercise.polyarr;

public class PloyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("jack", 20);
        persons[1] = new Student("jack", 18, 100);
        persons[2] = new Student("smith", 19, 30.1);
        persons[3] = new Teacher("scott", 30, 20000);
        persons[4] = new Teacher("king", 50, 25000);

        //循环遍历多态数组,调用say
        for (int i = 0; i < persons.length; i++) {
            //person[i] 编译类型是 Person,运行类型根据实际情况由JVM来判定
            System.out.println(persons[i].say());//动态绑定机制
        }
    }
}



------------------分割线-------------------
package com.hspedu.extend_.exercise.polyarr;

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

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

    public String say() {
        return name + "\t" + age;
    }
}


------------------分割线-------------------
package com.hspedu.extend_.exercise.polyarr;

public class Student extends Person{
    private double score;

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

    //重写父类的say方法

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


------------------分割线-------------------
package com.hspedu.extend_.exercise.polyarr;

public class Teacher extends Person{
    private double salary;

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

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


结果: 

JAVA面向对象三大特征_第3张图片

综合进阶:

package com.hspedu.extend_.exercise.polyarr;

public class PloyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("jack", 20);
        persons[1] = new Student("jack", 18, 100);
        persons[2] = new Student("smith", 19, 30.1);
        persons[3] = new Teacher("scott", 30, 20000);
        persons[4] = new Teacher("king", 50, 25000);

        //循环遍历多态数组,调用say
        for (int i = 0; i < persons.length; i++) {
            //person[i] 编译类型是 Person,运行类型根据实际情况由JVM来判定
            System.out.println(persons[i].say());//动态绑定机制
            //调用特有方法 --> 向下转型
            //只能强转父类的引用,不能强转父类的对象
            if(persons[i] instanceof Student) {
                ((Student)persons[i]).study(); //向下转型
            } else if (persons[i] instanceof Teacher) {
                ((Teacher)persons[i]).teach(); //向下转型
            } else {
                System.out.println("类型有误");
            }
        }



    }
}




------------------分割线-------------------
package com.hspedu.extend_.exercise.polyarr;

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



------------------分割线-------------------
package com.hspedu.extend_.exercise.polyarr;

public class Student extends Person{
    private double score;

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

    //重写父类的say方法

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

    //特有方法
    public void study() {
        System.out.println("学生 " + getName() + " 在学java");
    }
}




------------------分割线-------------------
package com.hspedu.extend_.exercise.polyarr;

public class Teacher extends Person{
    private double salary;

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

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


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




结果:

jack    20
类型有误
jack    18 score=100.0
学生 jack 在学java
smith    19 score=30.1
学生 smith 在学java
scott    30 salary20000.0
老师 scott 在讲课
king    50 salary25000.0
老师 king 在讲课

Process finished with exit code 0

8.多态参数(多态的应用)

形参类型为父类类型,实参类型允许为子类类型

你可能感兴趣的:(Java,java,开发语言)