Java继承于多态

一、继承
   1)继承的引入
     当我们需要定义一个猫类,成员变量有:名字(name)、毛色(color);成员方法:吃(eat)、睡(sleep);
               定义一个狗类,成员变量有:名字(name)、毛色(color);成员方法:吃(eat)、睡(sleep);
           定义一个老鼠类,成员变量有:名字(name)、毛色(color);成员方法:吃(eat)、睡(sleep);
               ......
     当我们用代码去实现以上类时会发现代码的重复了好几遍,这是我们就引入一个动物类,成员变量有:名字(name)、毛色(color);成员方法:吃(eat)、睡(sleep);
  然后让以上类去继承,这样继承动物类的子类就拥有了动物类里的所有成员变量和成员方法。
   2)继承的实现
       继承:把多个类中重复的变量和方法抽取出来,创建一个父类,然后让着多个类去继承这个父类。继承所使用的关键字extends
       继承的格式:
              
              class 子类名 extends 父类名{
                  类体...
              }
      子类又称为派生类,父类又称为超类。
  
   class Animal{
    String name;
    String color;
    public void eat(String name,String color) {
        System.out.println(color+"的"+name+"在吃东西");
        }
    public void sleep() {
        System.out.println("在睡觉");
        }
    }
      class Cat extends Animal{
    
    }
      class Dog extends Animal{
    
    }
      class Mouse extends Animal{
    
    }

    public class AnimalDemo {
    public static void main(String[] args) {
        Cat c=new Cat();
        c.name="猫";
        c.color="橘色";
        c.eat(c.name, c.color);
        c.sleep();
        Dog d=new Dog();
        d.name="狗";
        d.color="黄色";
        d.eat(d.name, d.color);
        d.sleep();
        Mouse m=new Mouse();
        m.name="老鼠";
        m.color="灰色";
        m.eat(m.name,m. color);
        m.sleep();
    }

 }
显示:
    橘色的猫在吃东西
    在睡觉
    黄色的狗在吃东西
    在睡觉
    灰色的老鼠在吃东西
    在睡觉


  继承的优点:提高了代码的复用性,解决了代码的臃肿。提供了多态的前提。
    3)继承的特点
     (1)子类可以直接继承父类所有非private修饰的成员变量和成员方法,但可以通过公共的访问方法间接访问private修饰的成员变量和成员方法。
    
class Father{
    public int x;//公共的
    static int y;//静态的
    private int p;//私有的
    public void show() {
        System.out.println("公共的方法");
    }
    private void show2() {
        System.out.println("私有的方法");
    }
    public int getP() {
        return p;
    }
    public void setP(int p) {//提供公共访问方法
        this.p = p;
        show2();
    }

}
class Son extends Father {
    int f;
    public void use() {
        x=10;
        y=15;
//        p=20;   私有的不可直接访问
        show();
//        show2();私有的不可直接访问
        System.out.println(x+","+y);
        setP(20);//使用公共访问方法间接访问
        System.out.println("私有变量:"+getP());
    }
}
public class ExtendsDemo {
 public static void main(String[] args) {
    Son s=new Son();
    s.use();
}
 }
显示:
    10,15
    私有的方法
    私有变量:20


   (2)子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  
 class Animal{
    String name;
    String color;
    public void eat() {
        System.out.println(this.color+"的"+this.name+"在吃东西");
    }

}
class Cat extends Animal{
     private String style="卷毛";
     public void show(){  
         System.out.println(this.style+"的"+this.name+"喜欢抓老鼠");
     }
}


public class AnimalDemo {
    public static void main(String[] args) {
        Cat c=new Cat();
        c.name="猫";
        c.color="橘色";
        c.eat();
        c.show();
    }
}
显示:
橘色的猫在吃东西
卷毛的猫喜欢抓老鼠


    (3)在Java中,继承只支持单继承(一个子类只能继承一个父类),不支持多继承(如:子类名 extends 父类名1,父类名2,...),
  但是Java是可以支持多层继承(子类可以继承父类,父类又继承爷爷类。子类就相当于继承了爷爷类)
  
class GrandFather{//爷爷类
    public void function() {
        System.out.println("爷爷");
    }
}
class Monther{
    public void method() {
        System.out.println("母亲");
    }
}
class Father1 extends GrandFather{//父类继承于爷爷类
    public void show() {
        System.out.println("父亲");
    }
}

//class Son extends Father,Monther{}不支持多继承
class Son1 extends Father1{ //只支持单继承
    public void demo() {
        System.out.println("儿子");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        
        //测试Son类
        Son1 s = new Son1();
        s.function();
        s.show();
        //访问自己的功能
        s.demo();
    }
}
显示:
爷爷
父亲
儿子


   (4)构造方法无法被继承
   class Father{
    int x;
    public Father() {
    }
    public Father(int x) {
        this.x = x;
    }
    
 }
 class Son{
    int y;
    public Son extends Father() {
        super();//super关键字,如果不写系统默认给出。
    }
    public Son(int y) {
        this.y = y;
    }

 }
 class Demo {
 public static void main(String[] args) {
    Son s=new Son();
    Son s2=new Son(9);
 //    Son s3=new Father();子类没有继承父类的无参构造
 //    Son s4=new Father(7);子类没有继承父类的有参构造
    Father f=new Father();
 }
 }
    子类继承父类,都会默认的访问父类的无参构造方法。
    构造方法不能被继承,但是通过super关键字去访问。
   super关键字:
    super:代表的父类的空间标识(父类的引用或父类的对象)
 
  this和super关键字的用法:
               成员变量:
                  this:
                        this.成员变量; (访问当前类)
                  super:
                            super.成员变量; (访问父类)
                      
              构造方法:
                  this(); //访问当前类的无参构造
                  this(参数列) ;//访问当前类的有参构造
                  super()://访问的父类的无参构造
                 super(参数列)://访问的是父类的有参构造
              成员方法:
                  this.xx()//访问当前类的成员方法
                  super.xx()//访问的是父类的成员方法
  若父类只提供了有参构造,而没有提供无参构造,系统会报错。

     这时我们需要:      (1)给父类提供无参构造使父类初始化。
            (2)用super关键字去访问父类的有参构造从而使父类初始化。
 
  class Father{
    int x;
  //     public Father() {}(1)给父类提供无参。
    public Father(int x) {
        this.x = x;
     }
    
 }
 class Son extends Father {
    int y;
    public Son() {
        super(5);//(2)用super关键字去访问父类的有参构造。
    }
    public Son(int y) {
        super(5);
        this.y = y;
    }
 }
 class Demo {
 public static void main(String[] args) {
    Son s=new Son();
    Son s1=new Son(7);


   3)继承中出现的局部变量,成员变量,成员方法重名问题。
    若不存在重名很简单,分别调用。
   (1)局部变量和成员变量重名。
       就近原则。
   
class Father{
    int  x=10;//父类成员变量
    public void aaa() {
        System.out.println(x);
    }
}
class Son extends Father{
    int x=20;//子类成员变量
    public void bbb() {
        int x=30;//子类局部变量
        System.out.println(x);
    }
    
}

public class RepetitionDemo {
   public static void main(String[] args) {
    Son s=new Son();
    System.out.println(s.x);//先到子类成员变量中找,没有在去父类成变量中找,还没有就报错。
    s.aaa();//先到方法内部找变量,没有再到父类成员变量中找,还没有就报错。
    s.bbb();//先到方法内部找变量,没有再到子类成员变量中找,没有再到父类成员变量中找,还没有就报错。
}
}
显示:
20
10
30

   (2)成员方法名重名
        方法重写:
          由于子类继承父类的时候,提供一摸一样的方法声明,然后会将父类该方法覆盖掉(重写,复写)
 
 class Father{
   public void show() {
       System.out.println("这是父类的方法");
   }

}
 class Son extends Father{
    public void show() {
        System.out.println("这是子类的方法");//子类的方法将父类的覆盖
    }
}

 public class RepetitionDemo {
   public static void main(String[] args) {
    Son s=new Son();
   s.show();
}
}
显示:
这是子类的方法  

 
   重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。!
   重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
   若父类的方法不希望被子类重写时则需要用到final关键字。
 final关键字:
    final:表示最终,终态(不能被更改的)
      它可以修饰类,那么该类不能被继承
      它可以修饰成员方法,成员方法不能被重写
     它可以修饰变量,此时这个变量是一个常量  
            如 final int a=10;//a为一个长量,无法在被赋值。
   final不仅可以修饰基本数据类型还可以引用类型:
     如果final修饰的是一个基本数据类型:基本数据类型的值不能再改变了...
    如果final习俗的是一个引用类型数据:引用类型的地址值不能再改变了,但是堆内存中的成员变量的值可以变得
方法重写和方法重载的区别?
     方法重写(override):返回值类型、方法名、形式参数都必须一样。

     方法重载(overload):方法名必须相同,形式参数(参数类型和参数个数)需不同,与返回值类型无关。
   4)什么时候使用继承
    
 class Dog{
    String name;
    public void eat() {
        System.out.println(this.name+"吃东西");
    }
    public void watchdoor() {
        System.out.println("看门");//狗类特有的行为方法
    }
}
class Cat extends Dog{
    
}
public class Demo {
    public static void main(String[] args) {        
   Cat a=new Cat();
   a.name="猫";
    a.eat();
   a.watchdoor();//猫类继承了狗类特有行为方法
    }
}


  以上代码为例,当一个类继承了该类不需要的属性或方法,这种情况就不要使用继承关系。
  只有当父类体现为子类的一种,或子类包含父类。体现出is a的关系时就适合使用继承。
二、多态
  多态就是同一事物具有多种状态。
   多态的一个前提:1)必须要有继承关系
                   2)必须要有方法重写
                   3)必须要有父类的引用来指向对象(也叫向上转型)
  多态中访问特点 :
  成员变量: 编译看左运行看左
  成员方法: 编译看左运行看右
  构造方法: 无论是子类还是父类都对方法进行初始化
  静态方法: 编译看左运行看左
 
 class Father2{
    
    public void show() {
    System.out.println("show father2...");
    }
}

class Son2  extends Father2{
    public void show() {
        System.out.println("show son2...");
    }
    
    public void method() {
        System.out.println("method son2...");
    }
}


public class DuoTaiDemo3 {

    public static void main(String[] args) {
        
        Father2 f  = new Son2() ;//父类引用子类对象
        f.show();//编译看左边,运行看右边(子类将重写父类的方法)

    }
}
显示:show son2...


 通过父类对象的创建是通过子类在堆内存新建了了一个对象,由于子类又继承了父类,
  父类的引用(初始化)是通过子类新建对象进行的。
 多态的优点:
    可以提供代码的复用性:继承保证;
    可以提高的代码的扩展性:由多态保证;
 多态的缺点:通过父类的引用创建的子类对象无法访问子类的特有功能。
      如何解决:将父类的引用强制转换子类的引用(向下转型)。
 
 class Father2{
    
    public void show() {
    System.out.println("show father2...");
    }
}

class Son2  extends Father2{
    public void show() {
        System.out.println("show son2...");
    }
    
    //子类的特有关功能
    public void method() {
        System.out.println("method son2...");
    }
}


public class DuoTaiDemo3 {

    public static void main(String[] args) {
        
        Father2 f  = new Son2() ;//父类引用子类对象(向上转型)
        f.show();
              //f.method();无法访问子类的特有功能
            Son s=(Son)f;//将父类的引用强制转换子类的引用(向下转型),前提是必须有向上转型
                s.method;
    }
显示:show son2...
      method son2..


三、抽象类
  抽象类的概念:
    把抽象的事物定义成的类,比如动物类,无法指出具体的是什么动物,不能像猫类,狗类这么具体。
       Java中,如果一个类中有一个方法声明(抽象方法)抽象功能,那么这个类定义为抽象类。
  使用关键字:abstract对类进行抽象化
   如:class adstract Animal{}
  抽象类的特点:抽象类不能直接实例化!(不能创建对象)
  抽象类的成员特点:
      成员变量:可以是变量,也是一个常量;
      构造方法:可以有无参,可以有有参,作用:给对象进行初始化的;
      成员方法:可以有抽象方法,还可以有非抽象方法;
abstract和private、final、static 关键字是冲突的,不能共同修饰类。
抽象方法:
如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
Abstract关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。

//定义一个抽象动物类
abstract class Animal{
    
    //提供一个抽象方法(只是一个声明)
    public abstract void eat() ;  //抽象功能,没有方法体,需要子类实现抽象类的这个功能
    //非抽象功能
    public void method() {
        
    }
}


//具体的动物类
class Cat extends Animal{

    public void eat() {
        System.out.println("猫吃鱼....");//子类重写抽象方法
    }
    
}

class Dog extends Animal{

    public void eat() {
        System.out.println("狗吃骨头....");
    }
    
}
 
public class AbstractDemo {
    public static void main(String[] args) {
                
    //多态,父类引用指向子类对象
        Animal a = new Cat() ;
        Animal a2 = new Dog() ;
               a.eat();
               a2.eat();
        
        
    }
}
显示:
 猫吃鱼....
 狗吃骨头....


注意:
1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法。
5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类(子类为抽象类没有实际意义,因为抽象父类无法被实例化)。
四、接口
  接口:体现的是事务的扩展性功能(额外动作,后天经过学习等等)
 
  接口格式:
          interface  接口名{
              //抽象功能
              public abstract void jump() ;
              }
 接口的特点:不能实例化
 接口的子实现类:实现类 (具体的实现类)
         class 类名+impl implements 接口名{
             
         }
接口成员的特点:
          成员变量:是一个常量,不能更改,并且默认的修饰符public static final;
          构造方法:接口不存在构造方法;
          成员方法:都是抽象方法默认的修饰符:public abstract;
interface Inter{
    public int num = 10 ;
    int num2 = 20 ;//默认的修饰符public static final
    //无参构造
    public Inter() {
        
    }
    
    void method(); //默认的修饰符 public abstract
    
    public static final int num3 = 200 ;
    
    public abstract void eat();
}

//子实现类
class InterImpl implements Inter{
    
    public void show() {
        System.out.println("show interimpl....");
    }

    public void eat() {
        
    }

    public void method() {
        
    }
}

//测试类
public class InterfaceDemo {

    public static void main(String[] args) {
        //创建实现类对象
        //接口多态
        Inter i = new InterImpl() ;
//        i.num = 100 ; //不能赋值:说明当前这个变量是一个常量:被final修饰
        System.out.println(Inter.num2); //这句话能调用,说明当前变量默认的修饰 static
        System.out.println(Inter.num);
    }
}
显示:20
      10


接口和抽象类的区别:
    
    A) 成员的区别
        成员变量:
                抽象类:既可以常量,也可以是变量
                接口:只能是常量,默认的修饰符:public static final
        构造方法:
                抽象类:有构造方法,无参/有参 (给对象进行初始化的)
                接口:没有构造方法
        成员方法:
                抽象类:可以有抽象方法,也可以有非抽象方法
                接口:只能是抽象方法 :默认的修饰符:public abstract
    
    
    B)类与类/类与接口关系的区别
        类与类之间的关系:
                    继承关系,只支持单继承,不支持多继承,但是可以多层继承
        类与接口的关系:
                    实现关系,一个类继承另一个类的同时,还可以实现多个接口...
        接口与接口的关系:
                    是一种继承关系,既可以单继承,也可以多继承...
                    
    C)设计原则的 区别
        1)抽象类: 是有继承关系---->体现的是一种"is a"的关系  
        2)接口:类和接口:实现关系--->体现的是一种" like a"的关系(扩展功能)
接口与抽象类综合练习:
interface Smoke{//创建一个接口
    public abstract void somking();//提供一个抽象功能
}
class Teacher extends People{//创建一个老师类

    public void eat() {
        System.out.println("老师会吃饭");
    }

    public void sleep() {
        System.out.println("老师会睡觉");
    }
    
}

 class Student extends People{//创建一个学生类


    public void eat() {
        System.out.println("学生会吃饭");
    }

    public void sleep() {
        System.out.println("学生会睡觉");
    }
    
 }
 class SmokeTeacher extends Teacher  implements Smoke{//创建一个抽烟老师类

    public void somking() {
        System.out.println("老师会抽烟");
    }
    
 }
public class PersonDemo {//测试类
public static void main(String[] args) {
    SmokeTeacher t=new SmokeTeacher();
    t.eat();
    t.sleep();
    t.somking();
}
}
显示:老师会吃饭
      老师会睡觉
      老师会抽烟


注意:  一个类可以同时实现多个接口。
    一个类只能继承一个类,但是能实现多个接口。
    一个接口能继承另一个接口,这和类之间的继承比较相似。
五、内部类
   内部类:
    在B类内部定义A类,A类就属于B的内部类
  内部类访问外部类的特点:
      它可以直接访问外部了的成员,包括私有,静态成员内部类访问外部类的数据,该数据必须static修饰。
      外部类通过创建内部类对象的方式间接访问内部类的成员。
 内部类的分类:
      成员内部类:在外部类的成员位置
      局部内部类:在外部类的局部位置
   
  class Outer2{
    
    //在成员位置:成员内部类
    class Inner2{
        
    }
    
    public  void method() {
        //在局部位置:局部内部类
        class Inner{
            
        }
    }
}
public class OuterDemo2 {

    public static void main(String[] args) {
        
    }
}
    
外部类要访问内部类(非静态的内部类)的成员方法:
  格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
  class Outer3{
    //外部类的成员变量
    private int num = 10 ;
    
    //成员内部类
    class Inner3{
        //show()
        public void show() {
            System.out.println(num);
        }
    }
       //成员方法
        public void method{
        int num2=20;
         //局部内部类
        class Inner4{
        private num3=30;
        public void show2(){
        System.out.println(num3);
        }
    }
    
}
}

//测试类
public class OuterDemo3 {
    
    public static void main(String[] args) {
        //    格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象
        Outer3.Inner3 oi = new Outer3().new Inner3();
        oi.show();
                Outer3.Inner4 oj = new Outer3().new Inner4();
        oj.show2();
    }
}
显示:  10
    30


  在外部类的局部位置去访问内部类的show(),需要在局部位置创建内部了对象,通过对象去访问

 //定义外部类
class Outer5{
    private int num = 10 ;
    
    //定义外部类的成员方法
    public void method() {
        //变量
        final int num2 = 20 ;  //jdk1.8不会有问题..
        
        //定义局部内部类
        class Inner5{
            public void show() {
                System.out.println(num);
                //注意事项:在这块改变量继续被使用...将变量变成固定值:在内存始终存在(被内部类的成员去使用)
                System.out.println(num2);
            }
        }
        
        //创建对象
        Inner5 i = new Inner5() ;
        i.show();  //调用show()
    }
 }

public class OuterDemo5 {
    public static void main(String[] args) {
        
        //创建对象
        Outer5 o = new Outer5() ;
        o.method();
 }
}
显示:
    10
    20


  匿名内部类
      前提是有一个类或者接口
      这个类可以是具体类也可以是抽象类
    格式:
          new 类名或者接口名{
 
              方法重写();
          }
 
  匿名内部类的本质:
      是继承了该类或者实现了该接口子类对象;
 
//定一个接口
interface Inter{
    public abstract void show();
    public abstract void show2() ;
    
}

//定义一个类实现这接口...
class Outer6{
    //成员方法
    public void method() {
        
        //调用接口一个方法的时候:匿名内部类的形式
        /*new Inter() {
            
            @Override
            public void show() {
                System.out.println("show...");
            }
            
        }.show();*/
        
        //两个方法调用
    /*    new Inter() {
            
            @Override
            public void show2() {
                System.out.println("show2....");
            }
            
            @Override
            public void show() {
                System.out.println("show...");
            }
        }.show();
        
        new Inter() {
            
            @Override
            public void show2() {
                System.out.println("show2....");
            }
            
            @Override
            public void show() {
                System.out.println("show...");
            }
        }.show2();*/
        
        //上述非常麻烦:直接创建对象,给它起名字
        Inter i = new Inter() {
            
            @Override
            public void show2() {
                System.out.println("show2...");
            }
            
            @Override
            public void show() {
                System.out.println("show....");
            }
        };
        i.show();
        i.show2();
    }
    
}
public class OuterDemo6 {
    
    public static void main(String[] args) {
        
        //创建Outer6类的对象
        Outer6 o = new Outer6() ;
        o.method();
    }
}
显示:
    show....
    show2...


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值