36.Java对象的特征之一_继承_super_instanceof

继承

1.1    类和类之间的常见关系。

   1:既然继承是描述类和类之间的关系,就需要先来了解类和类之间的常见关系

1.1.1  现实生活的整体与部分

举例说明

1:现实生活

   1:学生   是人 

   2:狗     是动物

   3:球队 包含 球员 整体与部分的关系,部分可以删除和增加

   4:笔记本包含 cpu 整体与部分的关系,部分不可以删除和增加

   5:航母编队 包含(航母 护卫舰 驱逐舰 舰载机 核潜艇)

1.1.2   java中的类与类关系

java中的类关系

1:is a 关系 (学生是人)

2:has a 整体与部分

class Person{
    String name;
    int age;
    Address add;
    
    Person(){
        
    }
    Person(String name,int age,Address add){
        
        this.name=name;
        this.age=age;
        this.add=add;
        
    }
    
    void speak(){
        System.out.println("姓名:"+name+" 年龄:"+age+" "+add.print());
    }
}
class Address{
    String country;
    String city;
    String street;
    
    Address(){
    
    }
    Address(String country,String city,String street){
        this.country=country;
        this.city=city;
        this.street=street;
    }
    
    String print(){
        return "地址:"+country+" "+"城市:"+city+"  街道;"+street;
    }
}
class Demo3{

    public static void main(String[] args){
        
        Address add=new Address("中国","广州","棠东东路");
        Person p=new Person("jack",27,add);
        p.speak();
        
        
        System.out.println();
         }
}

1.2   继承

   1:描述一个学生类

      1:姓名年龄学号属性,学习的方法

   2:描述一个工人类

      1:姓名年龄工号属性,工作的方法

   3:描述一个人类

      1:姓名年龄属性,说话的方法。

4:发现学生类和人类天生有着联系,学生和工人都是人。所以人有的属性和行为学生和工人都会有。出现类代码重复

class Person {
    String name;
    int age;

    // 静态变量(类变量)对象和对象之间的代码重复使用静态变量
    static String country = "CN";

    Person() {

    }

    void speak() {
        System.out.println(name + ":哈哈,我是人!!!");
    }

}

// 让学生类和人类产生关系,发现学生is a 人,就可以使用继承
class Student {

    String name;
    int age;

    Student() {

    }

    void study() {
        System.out.println("姓名:" + name + "年纪:" + age + ":好好学习");
    }
}

class Worker {
    String name;
    int age;

    void work() {
        System.out.println(name + ":好好工作,好好挣钱。");
    }

}

class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        s.name = "jack";
        s.age = 20;
        s.study();

        Worker w = new Worker();
        w.name = "rose";

        w.work();
    }
}

5:问题:

      1:如果没有继承,出现类和类的关系无法描述

      2:如果没有继承,类和类之间有关系会出现类和类的描述代码的重复。

1.3    继承特点

   1:描述类和类之间的关系

   2:降低类和类之间的重复代码

1:降低对象和对象之间的代码重复使用静态变量

   2:降低类和类之间的代码重复使用就继承

  

1.4    extends关键字

继承使用extends关键字实现

1:发现学生是人,工人是人。显然属于is a 的关系,is a就是继承。

2:谁继承谁?

   学生继承人,发现学生里的成员变量,姓名和年龄,人里边也都进行了定义。有重   复代码将学生类的重复代码注释掉,创建学生类对象,仍然可以获取到注释的成员。这就是因为继承的关系,学生类(子类)继承了人类(父类)的部分

class Person {
    String name;
    int age;

    // 静态变量(类变量)对象和对象之间的代码重复使用静态变量
    static String country = "CN";

    Person() {

    }

    void speak() {
        System.out.println(name + ":哈哈,我是人!!!");
    }

}

// 让学生类和人类产生关系,发现学生is a 人,就可以使用继承
class Student extends Person {

    Student() {

    }

    void study() {
        System.out.println("姓名:" + name + "年纪:" + age + ":好好学习");
    }
}

class Worker extends Person {

    void work() {
        System.out.println(name + ":好好工作,好好挣钱。");
    }

}

class Demo1 {

    public static void main(String[] args) {
        Student stu = new Student();
        stu.name = "jack";
        stu.age = 20;
        stu.study();
        stu.speak();
        System.out.println(stu.country);
        System.out.println(Student.country);

        Worker worker = new Worker();
        worker.name = "rose";
        System.out.println(worker.country);
        worker.work();
        worker.speak();

        System.out.println();
    }
}

继承细节;     

   1:类名的设定,被继承的类称之为父类(基类),继承的类称之为子类

   2:子类并不能继承父类中所有的成员

1:父类定义完整的成员静态成员,非静态,构造方法。静态变量和静态方

法都可以通过子类名.父类静态成员的形式调用成功。

      2:所有的私有成员不能继承,private修饰的成员。

      3:构造函数不能被继承

 

   3:如何使用继承

1:不要为了使用继承而继承。工人和学生都有共性的成员,不要为了节省代码,让工人继承学生。

 

/*
如何使用继承:验证是否有 is  a 的关系
 例如:学生是人, 小狗是动物
 注意:不要为了使用某些功能而继承,java只支持单继承
 */
class DK {

    void Ip4S() {
        System.out.println("好玩");
    }
}

class BGir extends DK {

}

class Demo {

    public static void main(String[] args) {

        new BGir().Ip4S();

    }
}

1.5super关键字

   1:定义Father(父类)

      1:成员变量int x=1;

      2:构造方法无参的和有参的,有输出语句

   2:定义Sonextends Father

      1:成员变量int y=1;

      2:构造方法无参和有参的。有输出语句

      1this.y=y+x;

   3:创建Son类对象

      Son son=new Son(3);

 

      System.out.println(son.y); //4

class Father {
    int x = 1;

    Father() {
        System.out.println("这是父类无参构造");
    }

    Father(int x) {

        this.x = x;
        System.out.println("这是父类有参构造");
    }

    void speak() {
        System.out.println("我是父亲");
    }                  
}

class Son extends Father {
    int y = 1;

    Son() {
        System.out.println("这是子类的无参构造");
    }

    Son(int y) {

        this.y = y + x;
        System.out.println("这是子类的有参构造");
    }

    void run() {
        super.speak(); // 访问父类的函数
        System.out.println("我是儿子");
    }
}

class Demo6 {

    public static void main(String[] args) {
        Son s = new Son(3);
        System.out.println(s.y);// 4
    }
}

4:子类对象为什么可以访问父类的成员。

      1this.y=y+x;有一个隐式的super super.x

 

   5super关键字作用

      1:主要存在于子类方法中,用于指向子类对象中父类对象。

      2:访问父类的属性

      3:访问父类的函数

      4:访问父类的构造函数

   6super注意

thissuper很像,this指向的是当前对象的调用,super指向的是当前调用对象的父类。Demo类被加载,执行main方法,Son.class加载,发现有父类Father类,于是Father类也加载进内存。类加载完毕,创建对象,父类的构造方法会被调用(默认自动无参),然后执行子类相应构造创建了一个子类对象,该子类对象还包含了一个父类对象。该父类对象在子类对象内部。this super只能在有对象的前提下使用,不能在静态上下文使用。

2:子类的构造函数默认第一行会默认调用父类无参的构造函数,隐式语句

super();

 

          1:父类无参构造函数不存在,编译报错。

Son(int y) {
        //super();隐式语句
        this.y = y + x;
        System.out.println("这是子类的有参构造");
    }

3:子类显式调用父类构造函数

 

在子类构造函数第一行通过super关键字调用父类任何构造函数。如果显式调用父类构造函数,编译器自动添加的调用父类无参数的构造就消失。构造函数间的调用只能放在第一行,只能调用一次。super() this()不能同时存在构造函数第一行。

Son(int y) {
        super(y);// 子类显式调用父类构造函数
        this.y = y + x;
        System.out.println("这是子类的有参构造");
    }

Son(int y) {
        this();  //不能同时存在构造函数第一行  
        super(y);
        this.y = y + x;
        System.out.println("这是子类的有参构造");
    }

4super思考

 

如果开发者自定义了一个类,没有显示的进行类的继承,那么该类中成员函数是否可以使用super关健健字?可以使用,继承了Object类,Object类是所有类的父类。

class Demo7 {
    public  void print(){
        System.out.println(super.toString());
    }
    public static void main(String[] args){
        new Demo7().print();
        System.out.println();
         }
}

7:重写(Override

1:定义Father

   1:姓名,吃饭方法,吃窝窝头。

   2:定义Son类,继承Father

      1Son类中不定义任何成员,子类创建对象,仍然可以调用吃饭的方法。

      2:父类的吃饭的方法,Son不愿吃。Son自己定义了吃饭的方法。

1:此时父类中有一个吃饭的方法,子类中有2个吃饭的方法,一模一样,只是方法体不一样。

          2:一个类中两个函数一模一样,是不允许的。

             1:编译运行,执行了子类的方法。

 

             2:使用父类的方法,在子类方法中,使用super.父类方法名。

class Father {
    String name;

    void eat() {
        System.out.println("吃窝窝");
    }
}

class Son extends Father {

    public void eat() { // 继承可以使得子类增强父类的方法
        System.out.println("来俩小菜");
        System.out.println("来两杯");
        System.out.println("吃香喝辣");
            System.out.println("来一根");
    }
}

class Demo8 {

    public static void main(String[] args) {
        Son s = new Son();
        //执行子类的方法
        s.eat();

    }
}

3:该现象就叫做重写(覆盖 override)

1在继承中,子类可以定义和父类相同的名称且参数列表一致的函数,将这种函数

称之为函数的重写.

4:前提

   1:必须要有继承关系

5:特点

1:当子类重写了父类的函数,那么子类的对象如果调用该函数,一定调用的是重写过后的函数。

      可以通过super关键字进行父类的重写函数的调用。

   2继承可以使得子类增强父类的方法

6:细节

   1函数名必须相同

   2:参数列表必须相同

3子类重写父类的函数的时候,函数的访问权限必须大于等于父类的函数的访

问权限否则编译报错

4:子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类。不能返回比父类更大的数据类型:如子类函数返回值类型是Object

 

      1:定义 A B  C B extends A 

      2Father类中定义A getA();

      3Son 类中重写getA(); 方法,尝试将返回值修改为BC ,Object

          1B编译通过

          2C 编译失败 ,没有继承关系

 

          3Object编译失败,比父类的返回值类型更大

class A {

}

class B extends A {

}

class C {

}
class Father {
    String name;

    void eat() {
        System.out.println("吃窝窝");
    }

    // 定义一个函数,获取A类的对象,
    A getA() {
        return new A();
    }

}

class Son extends Father {

    public void eat() { // 继承可以使得子类增强父类的方法
        System.out.println("来两杯");
        System.out.println("来俩小菜");
        super.eat();
        System.out.println("来一根");
    }

    // B类是A类的子类
    B getA() {
        return new B();
    }
}

class Demo8 {

    public static void main(String[] args) {
        Son s = new Son();
        s.eat();

    }
}

7:子类对象查找属性或方法时的顺序:

   1:原则:就近原则。

如果子类的对象调用方法,默认先使用this进行查找,如果当前对象没有找到属性或方法,找当前对象中维护的super关键字指向的对象,如果还没有找到编译报错,找到直接调用。

8:重载和重写的不同

   1:重载(overload) 

      1:前提:所有的重载函数必须在同一个类中

        2:特点:

             函数名相同,参数列表不同,与其他的无关(访问控制符、返回值类型)

      3:不同:

          个数不同顺序不同、类型不同

   2:重写(override)

        1:前提:继承

      2:特点:

            函数名必须相同、参数列表必须相同。

            子类的返回值类型要等于或者小于父类的返回值

9:重写练习

      描述不同的动物不同的叫法

      1:定义动物类

          有名字,有吃和叫的方法

      2:定义狗继承动物重写父类吃和叫的方法

 

      3:定义猫继承动物重写父类吃和叫的方法

class Animal{
    int x=1;
    String name;
    
    void eat(){
        System.out.println("吃东西");
    }
    void shout(){
        System.out.println("我是动物");
    }
}

class Dog extends Animal{
    
    
    void eat(){
        System.out.println("啃骨头");
    }
    void shout(){
        System.out.println("旺旺");
    }
    void eat(String food){
        System.out.println("吃:"+food);
    }
}
class Cat extends Animal{

    void eat(){
        System.out.println("吃老鼠");
    }
    void shout(){
        System.out.println("喵喵");
    }
}

class Demo9{

    public static void main(String[] args){
        Dog d=new Dog();
        d.shout();
        d.eat();
        
        Cat c=new Cat();
        c.shout();
        c.eat();
        System.out.println();
         }
}

1.6   instanceof 关键字

   1:快速演示instanceof

Person p=new Person();

       System.out.println( p instanceof Person);

 

   2instanceof是什么?

      1:属于比较运算符:

       2instanceof关键字:该关键字用来判断一个对象是否是指定类的对象。

       3:用法:

              对象  instanceof ;  

       该表达式是一个比较运算符,返回的结果是boolea类型  true|false

   注意:使用instanceof关键字做判断时,两个类之间必须有关系。

3:案例

定义一个功能表函数,根据传递进来的对象的做不同的事情,如果是狗让其看家,如果是猫让其抓老鼠

      1:定义动物类

      2:定义狗类继承动物类

      3:定义猫类继承动物类

      4:定义功能根据传入的动物,执行具体的功能

      5instanceof好处

 

          1:可以判断对象是否是某一个类的实例

/*
 instanceof
 比较运算符
 检查是否是类的对象
     1:可以判断对象是否是某一个类的实例
     用法
     对象  instanceof 类; 
     
 案例
定义一个功能函数,根据传递进来的对象的做不同的事情
    如果是狗让其看家,如果是猫让其抓老鼠
1:定义动物类
2:定义狗类继承动物类
3:定义猫类继承动物类
4:定义功能根据传入的动物,执行具体的功能
 */

class Animal {

    String name;

    void eat() {
        System.out.println("吃东西");
    }

    void shout() {
        System.out.println("我是动物");
    }
}

class Dog extends Animal {

    void eat() {
        System.out.println("啃骨头");
    }

    void shout() {
        System.out.println("旺旺");
    }

}

class Cat extends Animal {

    void eat() {
        System.out.println("吃老鼠");
    }

    void shout() {
        System.out.println("喵喵");
    }
}

class Demo11 {

    public static void main(String[] args) {

        Demo11 d = new Demo11();

        // 对象 instanceof 类;
        System.out.println(d instanceof Demo11);

         d.doSomething(new Dog());
        d.doSomething(new Cat());
    }

    // 定义一个功能函数,根据传递进来的对象的做不同的事情
    // 如果是狗让其看家,如果是猫让其抓老鼠
    // 对象 instanceof 类;
    void doSomething(Animal a) {
        if (a instanceof Dog) {
            a.eat();
            a.shout();
            System.out.println("小狗看家");
        } else if (a instanceof Cat) {
            a.eat();
            a.shout();
            System.out.println("抓老鼠");
        }
    }
}

练习:

     byte[] bs = new byte[] { 1, 2, 3 };
        int[] is = new int[] { 1, 2, 3 };
        String[] ss = new String[] { "jack", "lucy", "lili" };
        System.out.println(bs instanceof byte[]); // true
        System.out.println(is instanceof int[]); // true
        System.out.println(ss instanceof String[]); // true
        // System.out.println(bs instanceof int[]); // 不可转换的类型

 

 

 

posted @ 2020-08-30 03:02  nohert  阅读(201)  评论(0编辑  收藏  举报