封装, 继承, 多态详解

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

一.封装

思维导图概览:

封装, 继承, 多态详解_第1张图片

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

  

二.继承

思维导图概览:

封装, 继承, 多态详解_第2张图片

1. 为什么需要继承?

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

 

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

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

2)继承的格式

class Dog extends Animal { }

3)继承示意图

封装, 继承, 多态详解_第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)

父子类

必须一样

相同

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

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

 

 

五.多态

思维导图概览:

封装, 继承, 多态详解_第4张图片

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()有何区别?

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