面向对象的三大特性

203 阅读7分钟

面向对象的三大特性

一.封装

//基本介绍:就是把抽象的数据[属性]和对数据的操作方法封装到一起,数据被保护在内部,
        // 程序的其他部分只有通过被授权的操作才能对数据进行处理

        //好处:
        //1.隐藏了实现细节  :例如  方法(连接数据库) <- 调用 (输入参数)
        //2.可以对数据进行验证,保证安全和理性


        //封装的实现步骤
        1.将属性进行私有化private (不能直接修改属性)
        2.提供一个公共类public set 方法 用于对属性进行判并赋值
          public void set (类型 参数名) {
          *** 表示某个属性
          加入数据验证的业务逻辑
           属性名 = 参数名
          }
//基本介绍:用于控制方法和属性(成员变量)的访问权限(范围)

            //1.公开级别:public修饰,对外公开
            //2.受保护级别:protected修饰,对子类和同一个包的类公开
            //3.默认级别:没有修饰符号,向同一个包的类公开
            //4.私有级别:private修饰,只有类本身能访问,不对外公开
            // 同类 同包 子类 不同包



            //  细节和注意事项

            //1.修饰符可以修饰类中的属性 成员方法 类
            //2.只有默认的和public 才能修饰类
            //3.成员方法的访问规则和属性完全相同
//例题讲解:
package Encapsulation;

import java.util.Scanner;

public class Encapsulation01 {
    public static void main(String [] args) {   // 首先在包中写主方法  用于测试结果


        Person p = new Person();
        p.setName("奶盖131488888");
        p.setAge(888);
        p.setSal(520);
        Person p1 = new Person("奶盖",18,1314);


        System.out.println(p.info());
        System.out.println(p1.info());

    }


}
class Person {
    public String name;
    private int age;  //私有属性需要写公共的方法获取age sal  用get set
    private double sal;

    public Person(){  // 无参构造器

    }

    public Person(String name, int age, double sal) {  //用构造器传入指定属性,不再受保护

        this.name = name;
        this.age = age;
        this.sal = sal;
        //将set方法写到构造器里面
        setName(name);
        setAge(age);
        setSal(1314);
    }

    public String getName() {  //获取值
        return name;
    }

    public void setName(String name) {  //设置值
        if(name.length() >=2 &&name.length() <=6){  // 业务逻辑(set 方法中写) 用于更好的实现代码逻辑
        this.name = name;}
        else{
            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 getSal() {
        return sal;
    }

    public void setSal(double sal) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入密码");
        int password = 1416;
        int password1 =  scanner.nextInt();
        if(password1 == password) {
            this.sal = sal;
        }
        else{
            System.out.println("密码错误,你无权查看");
        }
    }

    public String info(){ //  用于输出结果

        return "name = " + name + "  age = " + age + " sal = "  + sal;

    }

}

二.继承

//继承:解决代码的复用性  当多个类存在相同的属性 方法   可以从这些类中抽象出父类  在父类中定义这些相同的属性和方法
//     所有的子类只需要extends来声明继承父类即可

        //基本语法初始化:
        // class 子类 extents 父类{ }
        //1.子类会自动拥有父类的定义的属性 方法
        //2.父类 也叫超类
        //3.子类也叫派生类


        //好处: 1.代码的复用性提高
        //      2.代码的扩展性 维护性提高


        //细节:
        1.非私有属性和方法能在子类中直接访问,私有属性和方法不能在子类中直接访问,要通过公共方法去访问
        2.子类必须调用父类的构造器,完成父类初始化
        3.当创建子类对象时,不管子类使用哪种构造器,默认情况下总会调用父类的无参构造器,如果父类没有无参构造器,
          必须用super指定父类的构造器
        4.如果调用父类的无参构造器,可以在某一个构造器里面写 super(); 或者不写
        5.super使用只能放在第一行   所以superthis不能同时使用
        6.Java的所有类都是object的子类
        7.父类的构造器调用仅限于直接父类,可以追溯到最高级父类
        8父类的调用不限于直接父类!将可以一直追溯到object
        9.子类最多只能继承一个父类(直接继承),可以通过间接继承 继承多个父类
        10.不能滥用继承 要满足 子类与父类要满足 is-a 的关系



        //继承本质分析   ***重点7

//例题讲解:
public 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 + " 年龄 " + age + "分数 "  + score);
    }

}

public class pupil extends student{  //小学生继承父类的属性和方法
    public void test(){              // 小学生的特有方法
        System.out.println("小学生" + name +  "  " + " 正在考试中~~~");
    }

}
public class graduate extends student {//大学生继承父类的属性和方法
                                       //大学生的特有方法
    public void test(){
        System.out.println("大学生" + name +  "  " + " 正在考试中~~~");
    }
}

public class test {  // 用来测试结果
    public static void main(String [] args) {

        pupil pupil = new pupil();
        pupil.name = "奶盖";
        pupil.age = 18;
        pupil.test();
        pupil.setScore(520);
        pupil.showInfo();

        System.out.println("=================");
        graduate graduate = new graduate();
        graduate.name = "酷盖";
        graduate.age = 18;
        graduate.test();
        graduate.setScore(1314);
        graduate.showInfo();
        
        
        // 可以在子类中写无参 和 有参构造器 和print 方法  之后再测试时 直接可以在创建对象时把需要写的属性进行初始化
//继承的使用细节:

public class topBase {    // 爷爷类
    public topBase(){
        System.out.println("topBase构造器被调用");
    }
}

public class Base extends topBase {  //父类
    public int n1 = 23;
    protected int n2 = 22;
    int n3 = 45;
    private int n4 = 1;

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

    }
    public Base(){
        System.out.println("===父类的无参构造器被调用");

    }

    //细节1.非私有属性和方法能在子类中直接访问
    //私有属性和方法不能在子类中直接访问,要通过公共方法去访问
    public int getN4(){  //通过公共方法去访问  获取私有属性的值
        return n4;
    }
    public void m1() {
        System.out.println("m1.100");


    }
    protected void m2(){
        System.out.println("m2.100");

    }
    void m3(){
        System.out.println("m3.100");
    }
    private void m4(){ // 只能在本类中使用
        System.out.println("m4.100");
    }
    public void callM4(){  //和属性一样,需要通过公共的方法去调用私有的方法
        m4();

    }


}



public class sub extends Base{


    public sub(){
         //默认调用子类的无参构造器

        super("奶盖",88);

        System.out.println("=子类的构造器被调用=");

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

    public void test(){
        //非私有属性和方法能在子类中直接访问
        //私有属性和方法不能在子类中直接访问,要通过公共方法去访问

        System.out.println(n1+ " "+n2+ " "+n3 + " "+ getN4()); //不能输入n4

        m1();
        m2();
        m3();
        callM4(); //公共方法调用私有属性m4()
    }



}
sub sub = new sub(); 
//结果
topBase构造器被调用
父类的String int构造器被调用
=子类的构造器被调用=
    // 分析:
    1.先在super类中执行无参构造器,
    2.但是里面有super(String name int age )(如果没有会执行父类的无参构造器) 接着会执行父类的有参构造器
    3.但是里面有爷爷类的无参构造器,会被调用



    //继承本质分析   ***重点
   public class Theory {
    //继承本质分析
    public  static void main(String []  args){  // 测试

        son son = new son();// 内存分布
      
        System.out.println(son.name + " " + son.hobby + " " + son.getAge()); //结果:星星 打篮球 45
        //分析:1.子类有名字 年龄的属性直接在输出子类的结果,
        //     2.但是没有Hooby的属性所以接着找上一级父类直到找到为止,没有找到就报错


    }

}
class father{ //父类
    String name = "酷盖";
    String hobby = "打篮球";
    int age = 18;

    int password;

}
class

mother extends father{  //子类
    String name = "奶盖";
    int age = 18;
}
class son extends mother{ //子类
    String name = "星星";
   private int age  = 45 ;

    public int getAge() {  // 通过公共方法使用私有的属性
        return age;
    }
}
//总结:
   
        //1.首先先看子类是否有该属性
        //2.如果子类有这个属性,并且可以访问(私有的不能访问)则返回该信息
        //3.如果子类没有该属性,那么看父类有没有,有返回,没有以此类推,直到object
  //super
        //1.访问父类的属性,但是不能访问父类的private 的属性
        //2.访问父类的方法,但是不能访问父类的private 的方法
        //3.访问父类的构造器   super(参数列表) 只能放在第一行  所以只能使用一次

        //super的便捷和细节
        //1.调用父类构造器的好处(分工明确,父类属性由父类初始化,子类属性由子类初始化)
        //2.当子类和父类的成员(属性 方法)重名时,为了调用父类成员,必须要用super
        //如果没有重名使用super this 直接访问效果一样
        //3.super的访问不限于直接父类    如果有多个基类(上级类)同名的成员,使用super 采取就近原则访问,当时要符合相应的规则

        // 分析:
        // 找calo方法时用calo() 和this.calo()的查找顺序
        //1.先找本类,如果有则调用
        //2.如果没有,找父类如果有则调用
        //以此类推 ,直到object类
        //注意:如果查找的过程中不能访问则报错,    如果没有该方法则提示不存在

        // 找calo方法时用super.calo()的查找顺序
        //1.直接找父类中有无,不找本类
        //2.其他规则和上述规则一样   // 属性调用也一样




        // ***重点 动态绑定机制
        //1.
  //方法重写:  就是子类有一个方法和父类的某个方法的名称,返回类型,参数一样,那么我们就说子类的某个方法覆盖了父类的方法
        //细节
        //1.子类的方法的参数,方法名称,要和父类的方法的参数,方法名称完全一样
        //2.子类的返回类型和父类的返回类型一样,或者是父类返回类型的子类  例如父类的返回类型是object,子类的返回类型是String
        //3.子类方法不能缩小父类的访问权限  public>protected>默认>private

// 重载与重写的比较

//  名称        发生范围     方法名          形参列表            返回类型                修饰符

//   重载       本类       必须一样         类型 参数 顺序       无要求                  无要求
//                                      个数至少一个不同
//
//
//  重写        父子类      必须一样        必须都相同          子类重写的方法和父类的      子类方法不能缩小父类方法的访问权限
//                                                        返回类型一样或者是其子类
//
//



三.多态


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

        // 包Poly 养宠物引入多态
        // 缺点: 如果动物 事物很多  feed方法也很多 不利于管理和维护
        //多态: 1.代码复用性高 2.利于代码维护


        //1.方法的多态 重写和重载就是体现多态
        //对象的多态
        //1.一个对象的编译类型可以和运行类型不同
        //2.编译类型在定义对象的时候,就确定了,不能改变
        //3.但是运行类型可以改变
        //4.编译类型看定义时 = 左边   运行类型看 = 右边


        //多态的注意事项和使用细节
        //前提:两个对象存在继承关系


        //多态的向上转型:父类的引用指向子类的对象
        //用法:父类的引用名 = new 子类类型
        //1.可以调用父类的所有成员  (要遵守访问权限)
        //2.但是不能调用子类的特有成员
        //3.因为在编译阶段,能调用哪些成员时编译类型决定的
        //4.最终运行结果看子类的具体实现,即调方法是从子类开始查找


        //多态的向下转型
        //1.语法: 子类类型 + 引用名 = (子类类型) + 父类引用
        //2.只能强转父类的引用,不能强转父类的对象
        //3.要求父类的引用必须指向的是当前目标类型的成员
        //4.当向下转行后就能调用子类类型中的子类成员


        // 细节
        // 属性没有重写之说,属性的值主要看编译类型

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

//多态的引入实例讲解
public class Poly01 {
    public static void main(String [] args){  //测试
        //传统做法
        Master master = new Master("唐执兴");
        Dog dog = new Dog("张送");
        Food food = new Food("狗屎棒");
        master.feed(dog,food);// 缺点 在每一次使用不同的动物都需要重写 feed方法
        

        System.out.println("======================");

        Master master1 = new Master("唐执兴");
        Animal animal = new Dog(); // 一个对象的编译类型可以和运行类型不同
        animal = new Cat("张送");// 编译类型在定义对象的时候,就确定了,不能改变
        animal = new Dog("张送");//但是运行类型可以改变
        Food food1 = new Food("猫屎棒");
        master.feed(dog,food);
===================================================================================================================   public void feed(Animal animal, Food food){  // 多态使用  不再是传统的 写dog bone  可以直接写需要的动物 和事物
        System.out.println("主人 " + getName()+ " " + "给" + animal.getName() + " " + food.getName() +" " +"吃");
    }

===================================================================================================================
        //利用多态解决
        Master master = new Master("唐执兴");
      // Animal animal = new Dog("吉狗狗");
        Dog dog = new Dog("吉狗狗");

       // Food food = new Food("星星");
        Bone bone = new Bone("星星");
        master.feed(dog,bone);

      //  Master master1 = new Master("奶盖");  // 不能修改
        master  = new Master("奶盖"); // 可以修改
        Cat cat = new Cat("星猫");
        Fish fish = new Fish("娃娃鱼");
        master.feed(cat,fish);

        // 可以继续添加各种动物类 食物类 ......

    }
}
Animal {  //父类 动物类
    private String name;

    public Animal() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Cat extends Animal{  //子类 猫类
    public Cat() {
    }

    public Cat(String name) {
        super(name);
    }
}
public class Dog extends Animal {  //子类 狗类
    public Dog() {
    }

    public Dog(String name) {
        super(name);
    }
}
public class Food {  // 父类 食物类
    private String name;

    public Food() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class Fish extends Food{  // 子类 鱼类

    public Fish() {
    }

    public Fish(String name) {
        super(name);
    }
}
public class Bone extends Food{ // 子类 骨头类
    public Bone() {
    }

    public Bone(String name) {
        super(name);
    }
}public 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){  // 多态使用  不再是传统的 写dog bone  可以直接写需要的动物 和事物
        System.out.println("主人 " + getName()+ " " + "给" + animal.getName() + " " + food.getName() +" " +"吃");
    }



}

// 多态使用:
public class PloyTest {
    public static void main(String []args){
        Animal animal = new Dog();  // 结果取决于运行类型
        animal.cry(); //小狗汪汪叫~~~

        animal = new Cat();//小猫喵喵叫~~~
        animal.cry();
    }
}
public class Animal {
    public void cry(){
        System.out.println("动物在叫");
    }
}
public class Cat extends Animal {
    public void cry(){
        System.out.println("小猫喵喵叫~~~");
    }
}
public class Dog extends Animal{
    public void cry(){
        System.out.println("小狗汪汪叫~~~");
    }
}

public class Detail {
    public static void  main(String [] args){

        // 向上转型 :父类的引用指向子类的对象
        //语法:父类引用名 = new 子类类型

        Animal animal = new Dog();
        animal.eat();
        // 1.可以调用父类的所有成员  (要遵守访问权限
        // 2.但是不能调用子类的特有成员
        // 3.因为在编译阶段,能调用哪些成员时编译类型决定的
        // 4.最终运行结果看子类的具体实现,即调方法是从子类开始查找
        //animal.catchCat();


        animal = new Cat();
        animal.sleep();
        animal.eat();

       // animal.run();  该方法是私有的  不能调用

        Object object = new Cat();   // object也是父类 间接父类

        animal = new Cat();
        animal.drink();

        // 多态的向下转型


        //要求父类的引用必须指向的是当前目标类型的对象
        Dog dog = (Dog) animal; // 子类类型 + 引用名 = (子类类型) 父类引用
        dog.catchCat();  // 可以使用子类的特有成员





    }

}
public class Animal extends Object{
    String name = "动物";
    int age = 18;
    public void sleep(){
        System.out.println("睡~~~");
    }
    public void eat(){
        System.out.println("吃~~~");
    }
    public void drink(){
        System.out.println("喝~~~");
    }
    private void run(){
        System.out.println("跑~~~");
    }
}
public class Cat extends Animal {
    public void sleep(){
        System.out.println("猫睡u大叫");
    }
}
public class Dog extends Animal {
    public void eat(){//子类的特有方法 需要向下转型才能调用
        System.out.println("狗吃屎");
    }

    public void catchCat(){
        System.out.println("狗抓猫");
    }

}


//多态参数:public class PloyArr01 {
    public static void main(String [] args) {
        //多态数组 :数组的定义类型时父类,里面保存的实际元素是子类类型
        Person[] people = new Person[5];
        people[0] = new Person("张松",18);
        people[1] = new Student("张昊",18,100);
        people[2] = new Student("李少振",18,99.9990);
        people[3] = new Teacher("唐执兴" ,18,99999);
        people[4] = new Teacher("唐执旺",18,3000);

        for (int i = 0;i < 5; i++) {
            System.out.println(people[i].say() );   // 通过if 和instanceOf  给不同对象 用向下转型 调用子类的特有属性
            if (people[i] instanceof Teacher) {
                Teacher teacher = (Teacher) people[i];  //向下转型 调用子类特有的属性
             teacher.teach();

            } else if (people[i] instanceof Student) {
                Student student =(Student) people[i];
                student.study();
            }
            else{
                System.out.println("特别注意这人是个傻子");
            }
        }
    }
}
// 运行结果:
name = 张松 age = 18
特别注意这人是个傻子
 学生   name = 张昊 age = 18 score = 100.0
学生张昊正在挨揍
 学生   name = 李少振 age = 18 score = 99.999
学生李少振正在挨揍
 老师   name = 唐执兴 age = 18 salary = 99999.0
老师 唐执兴 教训张松
 老师   name = 唐执旺 age = 18 salary = 3000.0
老师 唐执旺 教训张松

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

    }
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String getName(){
        return name;
    }
    public void setName(){
        this.name =name;

    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    public String say(){
        return "name = " +name + " " + "age = " + age;
    }
}
public class Student extends Person {
    private double score;

    public Student() {
    }



    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 String  say(){
        return "" + " 学生 " + "  " + super.say() + " "  +"score = " +score;
    }
    public void study(){ // 特有属性 需要向下转型
        System.out.println("学生" + getName() + "正在挨揍");
    }
}
public class Teacher extends Person{
    private double salary;

    public Teacher() {
    }

    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 = " +salary;
    }
    public void teach(){  // 特有属性 需要向下转型
        System.out.println("老师" + " " + getName() + " " + "教训张松");
    }

}