zoukankan      html  css  js  c++  java
  • day6 面向对象(3)

    继承

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

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

    1.1.1   现实生活的整体与部分

    举例说明

    1:现实生活

        1:学生   是人 

        2:狗     是动物

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

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

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

    1.1.2   java中的类与类关系

    java中的类关系

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

    2:has a 整体与部分

     1 class Person{
     2     String name;
     3     int age;
     4     Address add;
     5     
     6     Person(){
     7         
     8     }
     9     Person(String name,int age,Address add){
    10         
    11         this.name=name;
    12         this.age=age;
    13         this.add=add;
    14         
    15     }
    16     
    17     void speak(){
    18         System.out.println("姓名:"+name+" 年龄:"+age+" "+add.print());
    19     }
    20 }
    21 class Address{
    22     String country;
    23     String city;
    24     String street;
    25     
    26     Address(){
    27     
    28     }
    29     Address(String country,String city,String street){
    30         this.country=country;
    31         this.city=city;
    32         this.street=street;
    33     }
    34     
    35     String print(){
    36         return "地址:"+country+" "+"城市:"+city+"  街道;"+street;
    37     }
    38 }
    39 class Demo3{
    40 
    41     public static void main(String[] args){
    42         
    43         Address add=new Address("中国","广州","棠东东路");
    44         Person p=new Person("jack",27,add);
    45         p.speak();
    46         
    47         
    48         System.out.println();
    49          }
    50 }
    51     
    View Code

    继承

        1:描述一个学生类

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

        2:描述一个工人类

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

        3:描述一个人类

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

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

     1 class Person {
     2     String name;
     3     int age;
     4 
     5     // 静态变量(类变量)对象和对象之间的代码重复使用静态变量
     6     static String country = "CN";
     7 
     8     Person() {
     9 
    10     }
    11 
    12     void speak() {
    13         System.out.println(name + ":哈哈,我是人!!!");
    14     }
    15 
    16 }
    17 
    18 // 让学生类和人类产生关系,发现学生is a 人,就可以使用继承
    19 class Student {
    20 
    21     String name;
    22     int age;
    23 
    24     Student() {
    25 
    26     }
    27 
    28     void study() {
    29         System.out.println("姓名:" + name + "年纪:" + age + ":好好学习");
    30     }
    31 }
    32 
    33 class Worker {
    34     String name;
    35     int age;
    36 
    37     void work() {
    38         System.out.println(name + ":好好工作,好好挣钱。");
    39     }
    40 
    41 }
    42 
    43 class Demo1 {
    44 
    45     public static void main(String[] args) {
    46         Student s = new Student();
    47         s.name = "jack";
    48         s.age = 20;
    49         s.study();
    50 
    51         Worker w = new Worker();
    52         w.name = "rose";
    53 
    54         w.work();
    55     }
    56 }
    View Code

        5:问题:

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

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

    继承特点

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

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

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

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

    extends关键字

    继承使用extends关键字实现

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

    2:谁继承谁?

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

     1 class Person {
     2     String name;
     3     int age;
     4 
     5     // 静态变量(类变量)对象和对象之间的代码重复使用静态变量
     6     static String country = "CN";
     7 
     8     Person() {
     9 
    10     }
    11 
    12     void speak() {
    13         System.out.println(name + ":哈哈,我是人!!!");
    14     }
    15 
    16 }
    17 
    18 // 让学生类和人类产生关系,发现学生is a 人,就可以使用继承
    19 class Student extends Person {
    20 
    21     Student() {
    22 
    23     }
    24 
    25     void study() {
    26         System.out.println("姓名:" + name + "年纪:" + age + ":好好学习");
    27     }
    28 }
    29 
    30 class Worker extends Person {
    31 
    32     void work() {
    33         System.out.println(name + ":好好工作,好好挣钱。");
    34     }
    35 
    36 }
    37 
    38 class Demo1 {
    39 
    40     public static void main(String[] args) {
    41         Student stu = new Student();
    42         stu.name = "jack";
    43         stu.age = 20;
    44         stu.study();
    45         stu.speak();
    46         System.out.println(stu.country);
    47         System.out.println(Student.country);
    48 
    49         Worker worker = new Worker();
    50         worker.name = "rose";
    51         System.out.println(worker.country);
    52         worker.work();
    53         worker.speak();
    54 
    55         System.out.println();
    56     }
    57 }
    View Code

    继承细节;      

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

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

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

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

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

           3:构造函数不能被继承

        3:如何使用继承

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

    码,让工人继承学生。

     1 /*
     2 如何使用继承:验证是否有 is  a 的关系
     3  例如:学生是人, 小狗是动物
     4  注意:不要为了使用某些功能而继承,java只支持单继承
     5  */
     6 class DK {
     7 
     8     void Ip4S() {
     9         System.out.println("好玩");
    10     }
    11 }
    12 
    13 class BGir extends DK {
    14 
    15 }
    16 
    17 class Demo {
    18 
    19     public static void main(String[] args) {
    20 
    21         new BGir().Ip4S();
    22 
    23     }
    24 }
    View Code

    super关键字

        1:定义Father(父类)类

           1:成员变量int x=1;

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

        2:定义Son类extends Father类

           1:成员变量int y=1;

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

           1:this.y=y+x;

        3:创建Son类对象

           Son son=new Son(3);

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

     1 class Father {
     2     int x = 1;
     3 
     4     Father() {
     5         System.out.println("这是父类无参构造");
     6     }
     7 
     8     Father(int x) {
     9 
    10         this.x = x;
    11         System.out.println("这是父类有参构造");
    12     }
    13 
    14     void speak() {
    15         System.out.println("我是父亲");
    16     }                  
    17 }
    18 
    19 class Son extends Father {
    20     int y = 1;
    21 
    22     Son() {
    23         System.out.println("这是子类的无参构造");
    24     }
    25 
    26     Son(int y) {
    27 
    28         this.y = y + x;
    29         System.out.println("这是子类的有参构造");
    30     }
    31 
    32     void run() {
    33         super.speak(); // 访问父类的函数
    34         System.out.println("我是儿子");
    35     }
    36 }
    37 
    38 class Demo6 {
    39 
    40     public static void main(String[] args) {
    41         Son s = new Son(3);
    42         System.out.println(s.y);// 4
    43     }
    44 }
    View Code

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

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

      5:super关键字作用

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

           2:访问父类的属性

           3:访问父类的函数

           4:访问父类的构造函数

      6:super注意

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

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

        super();

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

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

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

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

      

     1 Son(int y) {
     2         super(y);// 子类显式调用父类构造函数
     3         this.y = y + x;
     4         System.out.println("这是子类的有参构造");
     5     }
     6 
     7 Son(int y) {
     8         this();  //不能同时存在构造函数第一行  
     9         super(y);
    10         this.y = y + x;
    11         System.out.println("这是子类的有参构造");
    12     }
    View Code

    super思考

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

    1 class Demo7 {
    2     public  void print(){
    3         System.out.println(super.toString());
    4     }
    5     public static void main(String[] args){
    6         new Demo7().print();
    7         System.out.println();
    8          }
    9 }
    View Code

    7:重写(Override)

    1:定义Father类

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

        2:定义Son类,继承Father

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

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

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

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

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

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

     1 class Father {
     2     String name;
     3 
     4     void eat() {
     5         System.out.println("吃窝窝");
     6     }
     7 }
     8 
     9 class Son extends Father {
    10 
    11     public void eat() { // 继承可以使得子类增强父类的方法
    12         System.out.println("来俩小菜");
    13         System.out.println("来两杯");
    14         System.out.println("吃香喝辣");
    15             System.out.println("来一根");
    16     }
    17 }
    18 
    19 class Demo8 {
    20 
    21     public static void main(String[] args) {
    22         Son s = new Son();
    23         //执行子类的方法
    24         s.eat();
    25 
    26     }
    27 }
    View Code

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

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

    称之为函数的重写.

    4:前提

        1:必须要有继承关系

    5:特点

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

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

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

    6:细节

        1: 函数名必须相同

        2:参数列表必须相同

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

    问权限否则编译报错

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

    1:定义 A B  C 类 B extends A 

           2:Father类中定义A getA();

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

               1:B编译通过

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

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

           1:定义 A B  C 类 B extends A 

           2:Father类中定义A getA();

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

               1:B编译通过

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

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

     1 class A {
     2 
     3 }
     4 
     5 class B extends A {
     6 
     7 }
     8 
     9 class C {
    10 
    11 }
    12 class Father {
    13     String name;
    14 
    15     void eat() {
    16         System.out.println("吃窝窝");
    17     }
    18 
    19     // 定义一个函数,获取A类的对象,
    20     A getA() {
    21         return new A();
    22     }
    23 
    24 }
    25 
    26 class Son extends Father {
    27 
    28     public void eat() { // 继承可以使得子类增强父类的方法
    29         System.out.println("来两杯");
    30         System.out.println("来俩小菜");
    31         super.eat();
    32         System.out.println("来一根");
    33     }
    34 
    35     // B类是A类的子类
    36     B getA() {
    37         return new B();
    38     }
    39 }
    40 
    41 class Demo8 {
    42 
    43     public static void main(String[] args) {
    44         Son s = new Son();
    45         s.eat();
    46 
    47     }
    48 }
    View Code

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

        1:原则:就近原则。

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

    8:重载和重写的不同

        1:重载(overload): 

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

            2:特点:

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

           3:不同:

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

        2:重写(override):

             1:前提: 继承

            2:特点:

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

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

    9:重写练习

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

           1:定义动物类

               有名字,有吃和叫的方法

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

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

     1 class Animal{
     2     int x=1;
     3     String name;
     4     
     5     void eat(){
     6         System.out.println("吃东西");
     7     }
     8     void shout(){
     9         System.out.println("我是动物");
    10     }
    11 }
    12 
    13 class Dog extends Animal{
    14     
    15     
    16     void eat(){
    17         System.out.println("啃骨头");
    18     }
    19     void shout(){
    20         System.out.println("旺旺");
    21     }
    22     void eat(String food){
    23         System.out.println("吃:"+food);
    24     }
    25 }
    26 class Cat extends Animal{
    27 
    28     void eat(){
    29         System.out.println("吃老鼠");
    30     }
    31     void shout(){
    32         System.out.println("喵喵");
    33     }
    34 }
    35 
    36 class Demo9{
    37 
    38     public static void main(String[] args){
    39         Dog d=new Dog();
    40         d.shout();
    41         d.eat();
    42         
    43         Cat c=new Cat();
    44         c.shout();
    45         c.eat();
    46         System.out.println();
    47          }
    48 }
    View Code

    instanceof 关键字

    1:快速演示instanceof 

    1 Person p=new Person();
    2         System.out.println( p instanceof Person);
    View Code

    2:instanceof是什么?

           1:属于比较运算符:

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

           3:用法:

                   对象  instanceof 类;  

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

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

    3:案例

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

           1:定义动物类

           2:定义狗类继承动物类

           3:定义猫类继承动物类

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

           5:instanceof好处

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

     1 package oop01;
     2 
     3 /*
     4  instanceof
     5  比较运算符
     6  检查是否是类的对象
     7      1:可以判断对象是否是某一个类的实例
     8      用法
     9      对象  instanceof 类; 
    10      
    11  案例
    12 定义一个功能函数,根据传递进来的对象的做不同的事情
    13     如果是狗让其看家,如果是猫让其抓老鼠
    14 1:定义动物类
    15 2:定义狗类继承动物类
    16 3:定义猫类继承动物类
    17 4:定义功能根据传入的动物,执行具体的功能
    18  */
    19 
    20 class Animal {
    21 
    22     String name;
    23 
    24     void eat() {
    25         System.out.println("吃东西");
    26     }
    27 
    28     void shout() {
    29         System.out.println("我是动物");
    30     }
    31 }
    32 
    33 class Dog extends Animal {
    34 
    35     void eat() {
    36         System.out.println("啃骨头");
    37     }
    38 
    39     void shout() {
    40         System.out.println("旺旺");
    41     }
    42 
    43 }
    44 
    45 class Cat extends Animal {
    46 
    47     void eat() {
    48         System.out.println("吃老鼠");
    49     }
    50 
    51     void shout() {
    52         System.out.println("喵喵");
    53     }
    54 }
    55 
    56 class Demo11 {
    57 
    58     public static void main(String[] args) {
    59 
    60         Demo11 d = new Demo11();
    61 
    62         // 对象 instanceof 类;
    63         System.out.println(d instanceof Demo11);
    64 
    65          d.doSomething(new Dog());
    66         d.doSomething(new Cat());
    67     }
    68 
    69     // 定义一个功能函数,根据传递进来的对象的做不同的事情
    70     // 如果是狗让其看家,如果是猫让其抓老鼠
    71     // 对象 instanceof 类;
    72     void doSomething(Animal a) {
    73         if (a instanceof Dog) {
    74             a.eat();
    75             a.shout();
    76             System.out.println("小狗看家");
    77         } else if (a instanceof Cat) {
    78             a.eat();
    79             a.shout();
    80             System.out.println("抓老鼠");
    81         }
    82     }
    83 }
    View Code
    1 byte[] bs = new byte[] { 1, 2, 3 };
    2         int[] is = new int[] { 1, 2, 3 };
    3         String[] ss = new String[] { "jack", "lucy", "lili" };
    4         System.out.println(bs instanceof byte[]); // true
    5         System.out.println(is instanceof int[]); // true
    6         System.out.println(ss instanceof String[]); // true
    7         // System.out.println(bs instanceof int[]); // 不可转换的类型
    View Code

    final关键字

     1:定义静态方法求圆的面积

        2:定义静态方法求圆的周长

        3:发现方法中有重复的代码,就是PI,圆周率。

           1:如果需要提高计算精度,就需要修改每个方法中圆周率。

        4:描述一个变量

           1:方法都是静态的,静态只能访问静态,所以变量也定义为静态的。

    public static double PI=3.14;

               1:如果定义为public后,新的问题,类名.PI=300; 改变了PI的值。

        2:修改为private,修改为private后进行了封装,需要getset公共访问方法。

               3:现有的知识不能解决这样的问题了。可以使用final

     1 class Demo12 {
     2 
     3     public static final double PI = 3.14; // 静态常量
     4 
     5     public static double getArea(double r) {
     6         return PI * r * r;
     7     }
     8 
     9     public static double getLength(double r) {
    10         return PI * r * 2;
    11     }
    12 
    13     public static void main(String[] args) {
    14 
    15         // Demo12.PI=300; 无法为最终变量 PI 指定值
    16         System.out.println(Demo12.PI);
    17 
    18     }
    19 
    20 }
    View Code

        5:使用final

           1:final关键字主要用于修饰类、类成员、方法、以及方法的形参。

           2:final修饰成员属性:

               1:说明该成员属性是常量,不能被修改。

                  public static final double PI=3.14;

                  1:public :访问权限最大

                  2:static :内存中只有一份

                  3:final  :是一个常量

                  4:常量名大写

                  5:必须初赋值。

               2:使用类名.成员。修改该成员的值,报错。--常量不能被修改

                  1:基本数据类型,final使值不变

    2:对象引用,final使其引用恒定不变,无法让其指向一个新的对象,但是对象自身却可以被修改。

                  3:该关键字一般和static关键字结合使用

                      1:常量可以优先加载,不必等到创建对象的时候再初始化。

                  4:final和static可以互换位置

                  5:常量一般被修饰为final

               3:fianl修饰类:

                  1:该类是最终类,不能被继承。

                      1:将父类加final修饰,子类继承,就会报错。

            2:查看api文档发现String类是final的。Integer类也是final的

                      1:为了防止代码功能被重写

                      2:该类没有必要进行扩展

               4:final修饰方法:

                  1:该方法是最终方法,不能被重写

          2:当一个类被继承,那么所有的非私有函数都将被继承,如果函数不想被子类继承并重写可以将该函数final修饰 

                  3:当一个类中的函数都被修饰为final时,可以将类定义为final的。

     1 class Father2{
     2     final void eat(){
     3         System.out.println("eating....");
     4     }
     5 }
     6 
     7 class Son2 extends Father2{
     8     //该方法是最终方法,不能被重写
     9     void eat(){
    10         System.out.println("eating....");
    11     }
    12 }
    13 class Demo12 {
    14 
    15     
    16     public static void main(String[] args) {
    17 
    18         // Demo12.PI=300; 无法为最终变量 PI 指定值
    19         System.out.println(Demo12.PI);
    20         Son2 s=new Son2();
    21         s.eat();
    22 
    23     }
    View Code

    5:final关键字修饰形参

                  1:当形参被修饰为final,那么该形参所属的方法中不能被篡改。

    2: 项目中主要用于一些只用来遍历未知数据的函数。将未知变量声明为final的。增强数据的安全性。

     1 class Demo14 {
     2 
     3     public static void main(String[] args) {
     4 
     5         System.out.println();
     6         String[] arr = { "think in java", "java就业教程", "java核心技术" };
     7 
     8         print(arr);
     9 
    10     }
    11 
    12     // 该方法,打印书名。
    13     public static void print(final String[] arr) {
    14         //arr = null; ,无法重新赋值
    15 
    16         for (int x = 0; x < arr.length; x++) {
    17             System.out.println(arr[x]);
    18         }
    19     }
    20 
    21 }
    View Code

    10:思考

           为什么子类一定要访问父类的构造函数呢

    1:子类继承了父类的属性,如果要使用父类的属性必须初始化,创建子类对象,必须先初始化父类属性

                  必须调用父类的构造方法。

               2:为什么调用父类无参的构造函数

    设计java语言之时,只知道编译器会默认添加无参的构造函数,有参的无法确定。

                  但是可以通过super关键字显式调用父类指定构造函数。

               3:为什么super()this()语句要放在构造函数的第一行

                  子类可能会用到父类的属性,所以必须先初始化父类。

     
  • 相关阅读:
    linux修改hostname
    ssh免密登录
    Linux添加用户到sudoers组
    nginx.conf
    linux ( CentOS 7)下Tengine(nginx)的安装与配置
    jacoco + ant远程统计(tomcat/spring boot)服务的代码覆盖率
    我只为一瓶啤酒
    iptables学习笔记
    离开了南京,从此没有人说话
    AutoConf自动生成Makefile(基于helloworld简单例子)
  • 原文地址:https://www.cnblogs.com/Michael2397/p/5951004.html
Copyright © 2011-2022 走看看