封装, 继承, 多态详解

news2024/12/24 9:05:00

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

一.封装

思维导图概览:

1. 封装的概念

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

 

2. 封装的理解和优势

1)隐藏实现细节:调用方法时才能传入参数,不能直接进行对数据的改动

2)可以对数据进行验证,保证安全合理

3. 封装的实现

1)将属性进行私有化(private)【不能直接修改属性】

2)提供公共的(public)set/get方法,对数据进行判断并赋值

        a. 提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰

        b. 提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰

3)提供相应的构造器/构造方法,与set/get方法结合

 

4.案例分析

class Student {
    //成员变量
    private String name;
    private int age;

    //构造方法
    public Student() {
    }

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

    //成员方法
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        //对数据进行校验
        if(age >= 0 && age <= 150) {
            this.age = age;
        } else {
            this.age = 0;
        }
    }

    public int getAge() {
        return age;
    }

    public void show() {
        System.out.println(name + "," + age);
    }
}
/*
    创建对象并为其成员变量赋值的两种方式
        1:无参构造方法创建对象后使用setXxx()赋值
        2:使用带参构造方法直接创建带有属性值的对象
*/
public class StudentDemo {
    public static void main(String[] args) {
        //无参构造方法创建对象后使用setXxx()赋值
        Student s1 = new Student();
        s1.setName("林青霞");
        s1.setAge(30);
        s1.show();

        //使用带参构造方法直接创建带有属性值的对象
        Student s2 = new Student("林青霞",30);
        s2.show();
    }
}

  

二.继承

思维导图概览:

1. 为什么需要继承?

—— 如果两个类有很多相同的属性和方法,这个时候就可以使用继承来提高代码的复用性

 

2. 继承基本了解和继承示意图

1)继承的了解:继承可以解决代码复用,当多个类中存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。

2)继承的格式

class Dog extends Animal { }

3)继承示意图

3. 继承的基本语法

1)class 子类 extends 父类 {}

2)子类就会自动拥有父类定义的属性和方法

3)父类又叫做超类,基类

4)子类又叫派生类

4. 一个小case快递了解继承

public class Student {
    public String name;
    public int age;
    private double score;

    public void setScore(double score) {
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    public void show() {
        System.out.println("学生名:" + name + " 年龄:" + age + " 成绩:" + score);
    }
}


public class Pupil extends Student {

    public void testing() {
        System.out.println("小学生 " + name + "age = " + age + " 正在考小学数学");
    }
}


public class Graduate extends Student {
    public void testing() {
        System.out.println("大学生" + name + " 年龄为:" + age + " 正在考大学数学");
    }

    public void print() {
        System.out.println("大学生的分数为 " + getScore());
    }
}

public class Test {
    public static void main(String[] args) {
        Pupil pupil = new Pupil();
        Graduate graduate = new Graduate();
        pupil.name = "小米";
        pupil.age = 10;
        pupil.testing();

        graduate.name = "小强";
        graduate.age = 20;
        graduate.setScore(80.0);
        graduate.testing();
        graduate.print();
    }

}

 

5. 继承的优势与劣势

1)优势

        a. 代码的复用性提高了

        b. 代码的扩展性和维护性提高

2)劣势

        —— 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性

 

6. 继承的细节讨论及实现

1)子类继承了所有的属性和方法,非私有的属性和方法可以在子类中直接访问,但是私有属性和方法的访问,要通过父类提供公共的方法去访问

public class Test1 {
    public static void main(String[] args) {
        //给A中的私有属性进行赋值
        A a = new A();
        a.setA(18);
        a.setAge(20);

        //B继承A后,可访问
        B b = new B();
        b.getMethod();
        System.out.print(b.getA());
        System.out.print(b.getAge());
    }
}

class A {
    public int age;
    private int a;

    //无参构造器
    public A() {
    }

    //有参构造器

    public A(int age, int a) {
        this.age = age;
        this.a = a;
    }


    //相关的set/get方法 --> 用来访问私有属性

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }


    //私有方法
    private void method() {
        System.out.println("这是父类的私有方法~~~");
    }

    //通过公共方法去访问私有方法
    public void getMethod() {
        method();
    }
}

class B extends A {}

2)子类必须调用父类的构造器,完成父类的初始化(子类中所有的构造方法默认都会访问父类中无参的构造方法)

3)当创建子类对象时,不管使用子类的那个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的那个构造器完成对父类的初始化工作,否则,编译不会通过

4)想要指定去调用父类的某个构造器,则可以显示的调用一下:super(参数列表);

5)super在构造器中使用时,必须放在构造器的第一行

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

class A {
    public int age;
    private int a;

    //无参构造器
    public A() {
    }

    //有参构造器

    public A(int age, int a) {
        this.age = age;
        this.a = a;
    }


    //相关的set/get方法 --> 用来访问私有属性

    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }

}

class B extends A {
    //1.若是一样都没有写,则存在一个默认的无参构造器public A() {},默认的无参构造器中存在父类的无参构造器

    public B(){
        //2. 写出了子类的无参构造器,在无参构造器中默认调用了父类的无参构造器,无法对父类进行初始化,因为父类的无参构造器中也没有属性,注意:super()只能放在第一行
    }


    public B(int age , int a) {
        super(age, a);// 3.显示调用了父类的有参构造器(则不再会调用父类的默认无参构造器),对父类的属性进行初始化,注意:super()只能放在第一行
    }
}

6)super() 和 this()都只能放在构造器的第一行,因此这两个关键字不能共存于同一个构造器中

class A () {
    
}

class B extends A{
    public B() {  
        this(age);//表示到进入到下面的这个有参构造器中去了
        //使用this的使用无法使用默认是super();
    }
    public B(int age) { 
        //注意:里面默认存在一个super();         
    }
}

7)Java所有类的父类都是Object类,Object类是所有类的父类(顶级父类)

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

    }
}

class A extends Object{
}

class B extends A {
    
}

8)子类最多只能继承一个父类(指直接父类),即Java是单继承机制

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

class A {} 
class B {}

class C extends B extends A {}//错误代码,Java是单继承模式

注:不能滥用继承,子类和父类之间必须满足is - a的逻辑关系

意思是如果有一个动物类(父类),你创建了一个猫类,继承动物类, 这是满足 is - a的形式,但是如果你创建了一个树木类,继承了动物类, 则不满足is - a 的形式

 

7. 继承的本质分析

public class ExtendsTheory {
    public static void main(String[] args) {
        Son son = new Son();//内存的布局
        //?-> 这时请大家注意,要按照查找关系来返回信息
        //(1) 首先看子类是否有该属性
        //(2) 如果子类有这个属性,并且可以访问,则返回信息
        //(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
        //(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到 Object... 
        System.out.println(son.name);//返回就是大头儿子
        System.out.println(son.age);//返回的就是 39
        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 = "大头儿子";
}

三.super关键字

1. super介绍

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

2. super语法

1)访问父类的属性,但不能访问父类的private属性 ---> super.属性名

2)访问父类的方法,但不能访问父类的private方法 ----> super.方法名(参数列表)

3)访问父类的构造器 ----> super(参数列表);只能放在构造器的第一句,也只能出现一句

3. 一个小case快速了解super

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

    }
}

class A {
    public int num1;//公共
    protected  int num2;//受保护
    int num3;//默认
    private int num4;//私有

    //构造器
    public A() {
    }

    public A(int num1, int num2) {
        this.num1 = num1;
        this.num2 = num2;
    }

    public A(int num1, int num2, int num3, int num4) {
        this.num1 = num1;
        this.num2 = num2;
        this.num3 = num3;
        this.num4 = num4;
    }

    //set/get方法
    public int getNum1() {
        return num1;
    }

    public void setNum1(int num1) {
        this.num1 = num1;
    }

    public int getNum2() {
        return num2;
    }

    public void setNum2(int num2) {
        this.num2 = num2;
    }

    public int getNum3() {
        return num3;
    }

    public void setNum3(int num3) {
        this.num3 = num3;
    }

    public int getNum4() {
        return num4;
    }

    public void setNum4(int num4) {
        this.num4 = num4;
    }

    //私有方法
    private void print() {
        System.out.println("这是A类中的私有方法");
    }
}

class B extends A {
    public B(int num1, int num2 ,int num3 ,int num4) {
        //super();//访问父类的无参构造器,不写也默认有
        //super(num1,num2); 访问父类中的有有两个参数的构造器,使用这个构造器时,默认构造器不执行
        super(num1, num2, num3, num4);
    }

    public void pout() {
        super.num1 = 10;
        super.num2 = 20;
        super.num3 = 30;

        //super.num4 = 40; 错误,私有成员变量不能访问

        //super.print(); 错误,私有方法不能访问
    }
}

4. super的细节讨论及实现

1)调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类属性由子类初始化)

2)当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super和this直接访问是一样的效果

3)super的访问不限于直接父类,如果爷爷类和本类中有相同的成员,也可以使用super去访问爷爷类中的成员;如果有多个基类(上级类)中都有同名的成员,使用super访问时遵循就近原则。

5. this和super的比较

区别点

this

super

访问属性

访问本类中的属性,如果本类没有此属性则从父类中继续查找

从父类开始查找

调用方法

访问本类中的方法,如果本类中没有此方法,则从父类中继续查找

从父类中开始查找

调用构造器

调用本类的构造器,必须放在构造器首行

调用父类的构造器,必须放在子类的首行

特殊

表示当前对象

子类中访问父类的对象

 

 

四.方法重写

1. 方法重写概念

—— 方法重写就是子类有一个方法和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法重写了父类的方法

2. 一个小case快速了解方法重写

public class Test {
    public static void main(String[] args) {
        B b = new B();
        b.print();//?输出什么? ---》 父类中的print()方法被子类中的print()方法重写了~
        //注意:重写的权限修饰,父类中的一定不能是private,不然不能重写,且子类重写的方法不能降低父类方法的访问权限,但可以提高
    }
}

class A {
    private String name;
    private int age;

    void print() {
        System.out.println("name = " + name + " age = " + age);
    }

    public A() {
    }
    public A(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;
    }
}

class B extends A {
    public void print() {
        System.out.println("父类中的print()方法被子类中的print()方法重写了~");
    }
}

注:重写的权限修饰符,父类方法中的一定不能是private,不然不能重写,且子类重写的方法不能降低父类方法的访问权限,但可以提高【public > protected > 默认 > private】

 

3. 方法重写的细节讨论及实现

1)子类的方法的形参列表,方法名称,要和父类方法的形参列表,方法名称完全一样

2)子类方法中的返回类型和父类方法中的返回类型一样,或者是父类返回类型的子类

//如:父类返回类型是 Object,子类方法返回类型是String,String是Object的子类
//父类方法:
public Object getInfo() {}
//子类方法
public String getInfo() {}

3)子类方法不能缩小父类方法的访问权限,但能提高【public > protected > 默认 > private】

4. 方法重写与方法重载的比较

名称

发生范围

方法名

形参列表

返回类型

修饰符

方法重载(overload)

本类

必须一样

类型,个数或者顺序至少有一个不同

无要求

无要求

方法重写(override)

父子类

必须一样

相同

子类重写的方法,返回的类型和父类返回的类型一致,或者是父类的子类

子类不能缩小父类方法的访问范围

 

 

五.多态

思维导图概览:

1. 多态的介绍

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

 

2. 多态的具体体现

1)方法的重写和方法的重载就体现多态

2)对象的多态

 

3. 如何判断编译类型和运行类型

1)编译类型看 = 号的左边,运行类型看 = 号的右边

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

3)运行类型是可以改变的

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

//编译类型为animal,运行类型为Tiger
Animal animal = new Tiger();
//编译类型为animal,运行类型为Cat
animal = new Cat();

 

4. 一个小case快速了解对象的多态

public class TestOne {
    public static void main(String[] args) {
        //编译类型是Animal, 运行类型是Tiger
        Animal tiger = new Tiger();

        tiger.print();//打印什么? 老虎会咆哮~~~
        //为什么会打印老虎会咆哮? ---> 我们使用多态的时候,先看看子类中里面是否有重写父类的方法,如果有,那就使用,
        //如果没有,在父类中查看有没有该方法,如果有则使用
    }
}


public class Animal {
    public String name;
    public int age;

    public void print() {
        System.out.println("动物会睡觉~~");
    }

    //构造器
    public Animal() {
    }

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

    //提供成套的set/get方法

    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 class Tiger extends Animal{
    public void print() {
        System.out.println("老虎会咆哮~~");
    }
}

 

5. 多态的细节讨论及实现

1)多态的向上转型

        a. 本质:父类的引用指向子类的对象

//父类
class Animal{}
//子类
class Cat() extends Animal {}
//父类的引用指向了子类的对象
Animal cat = new Cat(); //编译类型:Animal,运行类型:Cat

        b. 语法:父类类型 引用名 = new 子类类型();

        c. 特点:编译类型看左边,运行类型看右边。可以调用父类中的所有成员变量(需遵守访问权限),不能调用子类中的特有成员,可以调用方法重写,注意,在访问的时候,从运行类型开始访问。

public class TestOne {
    public static void main(String[] args) {
        //编译类型是Animal, 运行类型是Tiger
        Animal tiger = new Tiger();

        tiger.print();//打印什么? 老虎会咆哮~~~
        //为什么会打印老虎会咆哮?
        // ---》 我们使用多态的时候,先判断编译类型中是否有该方法,如果没有,则报错,运行类型从子类开始查找,查找与访问相匹配的方法或属性,如果父类中的方法被重写了,则调用重写的方法

        //看看访问特有方法是否报错
        //tiger.output(); --> 错误,不能访问子类中特有的方法
    }
}


public class Animal {
    public String name;
    public int age;

    public void print() {
        System.out.println("动物会睡觉~~");
    }

    //构造器
    public Animal() {
    }

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

    //提供成套的set/get方法

    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 class Tiger extends Animal {
    public void print() {
        System.out.println("老虎会咆哮~~~");
    }

    //特有的方法
    public void output() {
        System.out.println("老虎在打滚~~");
    }
}

2)多态的向下转型(在向上转型的基础上)

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

/*
    怎么理解?
        1.因为向上转型无法访问子类中的特有方法,但是,向下转型则帮助我们解决了此问题
        2.怎么理解 子类类型  引用名    =  (子类类型) 父类引用?
        //一段代码搞定:
            //编译类型:Animal,运行类型:Tiger
            Aniaml animal = new Tiger();
            //向下转型之后,编译类型Tiger,运行类型:Tiger
            Tiger tiger = (Tiger)animal;
            //子类类型 引用名 = (子类类型)父类引用
        //解决!!!
        3.思考以下代码能不能向下转型?
            Animal animal = new Cat();
            Dog dog = (Dog)animal;
            //错误,为什么?因为我们没有使用父类的引用类型指向子类的对象,前面说过了,向下转型是基于向上转型的,所以想要向下转型的前提是要使父类的引用指向子类对象,也就是向上转型
            //代码改正
            Animal animal = new Dog();
            Dog dog = (Dog)animal;
*/

        b. 只能强转父类的引用,不能强转父类的类型

//代码解释
Person p = new Xh();
Xh xh = (Xh)Person;//错误,这样是强转父类的类型

        c. 要求父类的引用必须指向的是当前目标类型的对象(看a.的解释)

        d. 向下转型后,可以调用子类类型中的所有成员(属性和方法)

public class TestOne {
    public static void main(String[] args) {
        //编译类型是Animal, 运行类型是Tiger
        Animal animal = new Tiger();

        animal.print();//打印什么? 老虎会咆哮~~~
        //看看访问特有方法是否报错
        //tiger.run(); --> 错误,不能访问子类中特有的方法

        //对父类的引用进行强转
        Tiger tiger = (Tiger)animal;
        tiger.run();//可以使用特有方法了
    }
}


public class Animal {
    public String name;
    public int age;

    public void print() {
        System.out.println("动物会睡觉~~");
    }

    //构造器
    public Animal() {
    }

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

    //提供成套的set/get方法

    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 class Tiger extends Animal{
    //重写的方法
    public void print() {
        System.out.println("老虎爱睡懒觉~~~");
    }

    //特有方法
    public void run() {
        System.out.println("老虎跑得快~~~");
    }
}

        3)属性没有重写的说法,属性的值看编译类型

public class Test {
    public static void main(String[] args) {
        Person person = new Smith("jack",18,"smith",20);
        Smith smith = new Smith();
        Person p = new Person();

        System.out.println(person.name); //jack
        System.out.println(person.age);//18


        System.out.println(smith.name);//null ? --> 因为Smith是我们新开的对象,所有里面的值是默认值
        System.out.println(smith.age); //0
        
        Smith s = (Smith)person; //向下转型
        System.out.println(s.name); //smith
        System.out.println(s.age);20
    }
}


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

    public Person() {
    }

    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 class Smith extends Person{
    public String name;
    public int age;

    public Smith() {
    }

    public Smith(String name, int age, String name1,int age1) {
        super(name, age);
        this.name = name1;
        this.age = age1;
    }
}

        4)instanceof 比较操作符,用于判断对象的运行类型是否是XX类型或XX类型的子类型

public class Test {
        public static void main(String[] args) {
            BB bb = new BB();
            System.out.println(bb instanceof BB);//true
            System.out.println(bb instanceof AA);//true

            //编译类型:AA 运行类型:BB
            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 AA); //编译器报错,因为两者是不相同的类型
            System.out.println(str instanceof Object); //true
        }
}

class AA {}

class BB extends AA {}

 

 

六.Java的动态绑定机制

1. Java重要特性:动态绑定机制

 

2. Java动态绑定机制的特点

1)当调用对象方法的时候,该方法会和对象的内存地址/运行类型进行绑定

2)当调用对象属性的时,没有动态绑定机制,哪里声明,哪里使用

public class Test {
        public static void main(String[] args) {
            AA aa = new BB();

            System.out.println(aa.sum());  //40
            System.out.println(aa.sum1()); //30
            //为什么会是以上答案?因为运行类型从子类开始执行,查找当中的方法,执行了父类中发方法重写

            //去掉子类中的sum()方法
            System.out.println(aa.sum());  //30 --> Java的动态绑定机制:父类中的sum()方法调用子类中重写的getI()方法
        }
}

class AA {
    public int i = 10;

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

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

    public int getI() {
        return i;
    }
}


class BB extends AA {
    public int i = 20;

    //注意:以下方法全部为重写方法
   /* public int sum() {
        return i + 20;
    }*/

    public int getI() {
        return i;
    }

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

3.多态数组

—— 数组的定义类型为父类类型,里面保存的对象类型为子类类型或父类类型

public class Test {
    public static void main(String[] args) {
        Person[] person = new Person[2];

        person[0] = new Person("jack",19);
        person[1] = new Student("小红",10,100);

        //调用say()方法
        for (int i = 0; i < person.length; i++) {
            System.out.println(person[i].say());

            //调用子类的特有方法
            if(person[i] instanceof Student) {
                //向下转型,调用子类中特有的方法
                ((Student) person[i]).study();
            }
        }
    }
}

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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String say() {//返回名字和年龄
        return name + "\t" + age;
    }
}

public 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...");
    }
}

 

2. 多态参数

—— 方法定义的形参类型为父类类型,实参类型为父类类型或子类类型

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        Person[] person = new Person[2];

        person[0] = new Person("jack",19);
        person[1] = new Student("小红",10,100);

        test.printSay(person[0]);
        test.printSay(person[1]);
    }

    public void printSay(Person p) {
        System.out.println(p.say());
    }
}

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 int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String say() {//返回名字和年龄
        return name + "\t" + age;
    }
}



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

 

七.问题思考?

1.  一个类可以有几个直接父类?一个父类可有多少个子类?子类能获取直接父类的父类中的结构吗?子类能否获取父类中private权限的属性或方法?

2. 方法的重写(override/overwrite)的具体规则有哪些,两者的区别?

3. super调用构造器,有哪些具体的注意点?

4. 如何实现向下转型?需要注意什么问题?如何解决此问题?

5. == 和equals()有何区别?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1139287.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux系统 too many open files解决方法

1.遇到的问题 too many open files是Linux系统中常见的错误&#xff0c;从字面意思上看就是说程序打开的文件数过多&#xff0c;不过这里的files不单是文件的意思&#xff0c;也包括打开的通讯链接(比如socket)&#xff0c;正在监听的端口等等&#xff0c;所以有时候也可以叫做…

Python 中的邻接矩阵

Python 中使用图数据结构来表示各种现实生活中的对象,例如网络和地图。 我们可以使用邻接矩阵来表示图。 本文将讨论在 Python 中实现邻接矩阵的不同方法。 创建邻接矩阵 考虑下图。 图中,有 6 个节点,编号为 1 到 6。图中连接节点的边有 7 条; 边 eij 连接节点 i 和节点…

2023年中国儿童滑板车优点、市场规模及发展前景分析[图]

儿童滑板车行业是指专门生产、销售和服务于儿童滑板车的行业。儿童滑板车是一种两轮滑行车&#xff0c;通常由车架、轮子、刹车和把手等部件组成。儿童滑板车是一种受欢迎的户外运动和娱乐工具&#xff0c;可以帮助儿童锻炼身体、提高平衡和协调能力&#xff0c;同时也是一种时…

无人机真机搭建问题记录文档(待续)

搭建问题 问题1 高飞课程中的飞控停产&#xff0c;更换飞控&#xff08;pixhawx 6c&#xff09;出现如下问题 1、飞控太大造成安装机载电脑的碳板上的孔被挡住。 2、课程提供的飞控固件&#xff0c;与更换的飞控不匹配 解决办法 1、现在的无人机碳板上只安装三个螺纹孔&…

如何平衡需求变更与项目进度冲突问题?

需求变更往往会对项目进度产生影响&#xff0c;可能会导致项目进度的重新评估、调整和重新开发已有功能&#xff0c;从而延长交付时间。如果忽视拒绝需求变更&#xff0c;会导致客户的不满和冲突。 因此如何更好地平衡两者间的冲突问题&#xff0c;迫在眉睫。一般来说&#xff…

【Unity ShaderGraph】| 制作一个 高级流体水球效果

前言 【Unity ShaderGraph】| 快速制作一个 流体水球效果一、效果展示二、简易流体水球效果三、进阶流体水球效果四、应用实例 前言 本文将使用ShaderGraph制作一个 高级流体水球 &#xff0c;可以直接拿到项目中使用。对ShaderGraph还不了解的小伙伴可以参考这篇文章&#xf…

8.MySQL内外连接

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 表的内连和外连 内连接 外连接 左外连接 右外连接 我们进行演示的表结构是这样的&#xff1a; 表的内连和外连 内连接 内连接实际上就是利用where子句对两种表形成的笛卡儿积进行筛选&#xff0c;我们前面学习的…

Vue3项目创建+组合式API使用+组件通信+渲染微博热搜+打包上线

摘要 Vue3的组合式API大大减少了代码量&#xff0c;以及使用也方便了很多&#xff0c;本案例使用Vite创建一个Vue3示例&#xff0c;简单介绍Vue3的组合式API使用以及父传子组件传参示例。 创建Vue3项目 1、首先要安装 Node.js 下载地址&#xff1a;https://nodejs.org/en/do…

css-物联网管理界面

效果图&#xff1a; 分享链接&#xff1a; monitor https://www.aliyundrive.com/s/CkLVqXcnJFc 点击链接保存&#xff0c;或者复制本段内容&#xff0c;打开「阿里云盘」APP &#xff0c;无需下载极速在线查看&#xff0c;视频原画倍速播放。

qt 双击可执行文件提示没有平台插件Qt platform plugin

准备打包可执行文件时&#xff0c;双击可执行文件 报错提示&#xff1a; 解决办法&#xff1a; 从qt安装目录下拷贝platforms文件夹&#xff0c;放在你要执行的可执行目录里。

App在哪里可以免费内测分发?

当ios开发者开发完成ios App后&#xff0c;往往要进入内测或公测阶段&#xff0c;需要进行分发&#xff0c;测试用户才能下载应用。 App分发平台是许多app开发类企业经常使用的平台&#xff0c;将主要开发的app上传到app分发平台上进行内测下载。很多开发者服务平台其实是提供…

SDRAM学习笔记(MT48LC16M16A2,w9812g6kh)

一、基本知识 SDRAM : 即同步动态随机存储器&#xff08;Synchronous Dynamic Random Access Memory&#xff09;, 同步是指其时钟频率与对应控制器&#xff08;CPU/FPGA&#xff09;的系统时钟频率相同&#xff0c;并且内部命令 的发送与数据传输都是以该时钟为基准&#xff…

Python中if __name__ == ‘__main__‘,__init__和self 的解析

一、 if __name__ __main__ if __name__ __main__的意思是&#xff1a; 当.py文件被直接运行时&#xff0c;if __name__ __main__之下的代码块将被运行&#xff1b; 当.py文件以模块形式被导入时&#xff0c;if __name__ __main__之下的代码块不被运行。 1.1、一个 xxx.p…

面试题复盘-2023/10/20

目录 笔试题面试题&#xff08;未完待续&#xff09; 笔试题 一.多选题 A:map的key是const,不可更改 B:STL中的快速排序比一般的快速排序速度更快&#xff0c;是因为中值排序法 C:list的插入效率是O(1) D:vector的容量只能增大不能减小 解析&#xff1a; B: STL中的sort函数的…

Python教程总结版

目录 1. chr()和ord()的用法 2. input()——读取数据的转换 2.1 int(),float(),list() 数据转换 2.2 split()函数处理多个输入值 2.3 map()强制转换 1. chr()和ord()的用法 for i in range(65, 91): print(chr(i), end) # 控制台输出&#xff1a;ABCDEFGHIJKLMNOPQRSTUV…

关于高并发你必须知道的几个概念

&#x1f388;个人公众号:&#x1f388; :✨✨✨ 可为编程✨ &#x1f35f;&#x1f35f; &#x1f511;个人信条:&#x1f511; 为与不为皆为可为&#x1f335; &#x1f349;本篇简介:&#x1f349; 本篇记录高并发必须知道的几个概念&#xff0c;如有出入还望指正。 关注公众…

墨西哥专线港口通航情况

随着全球贸易的不断发展&#xff0c;墨西哥作为拉美地区的重要国家&#xff0c;其港口通航状况对于国际贸易具有重要意义。本文将从墨西哥专线港口的通航现状、通航瓶颈以及未来发展趋势等方面进行分析&#xff0c;以期为墨西哥港口的发展提供一些参考。 一、墨西哥专线港口的通…

使用Linux JumpServer 堡垒机进行远程访问

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

有什么不起眼,却很挣钱的副业?

说两个真人真事儿&#xff1a; 1、我有一个表妹,去年生完孩子后,开始在家做视频剪辑工作。 主要是剪辑一些古装剧、家庭剧等视频,然后发布到抖音和快手等短视频平台。 她会把视频剪辑成一集一集的,先发布片段进行推广,如果用户觉得剧情吸引就提示他们可以付费购买全集。 我表妹…

JS:获取当前时间、计算2个时间的相差天数

前言 本文将介绍在js中对时间的一些操作&#xff0c;包括&#xff1a;获取当前的年、月、日&#xff1b;获取指定格式的时间&#xff1b;2个时间的相差天数等 基本操作 在js种可以使用特定的函数&#xff0c;获取当前的年、月、日等时间 date .getYear(); //获取当前年份(2…