java面向对象(二):继承,方法重写,final关键字,抽象类,接口

1、继承

       在java中,所有的类都直接或间接继承Object类,Object类称为所有Java类的祖先。java中的继承是通过extends关键字操作的。通常说被继承的类叫作父类,派生的类叫做子类,通过继承后,子类可以使用父类的成员变量和成员方法。由此特点,通常在生产中把父类设计为拥有所有子类的共同属性和行为的类,即多个类中相同的内容给提取出来定义到一个类。比如人会吃饭和睡觉,那么学生和老师也会吃饭和睡觉,如下

class Person {
    public void sleep() {
        System.out.println("人会睡觉的!");
    }
    public void eat() {
        System.out.println("人会吃饭的!");
    }
}

//继承格式:class 子类名 extends 父类名 {}

class Student extends Person{}  //Student类继承了Person类

class Teacher extends Person{} //Teacher类继承了Person类

class test {
    public static void main(String[] args) {
       Student s1 = new Student();
       s1.sleep();   //Student类对象s1调用父类的sleep()成员方法
       s1.eat();
       System.out.println("---------");
       Teacher t1 = new Teacher();
       t1.sleep();  //Teacher类对象t1调用父类的sleep()成员方法
       t1.eat();  
    }
}

//执行结果如下:

人会睡觉的!
人会吃饭的!
---------
人会睡觉的!
人会吃饭的!

  1.1、 Java中继承的特点:

        A:Java只支持单继承,不支持多继承。

            //class Son extends Father,Mother {}  // java这样的多继承是错误的
            但有些语言是支持多继承,格式:extends 类1,类2,...
        B:Java支持多层继承(继承体系)

              class GrandFather(){}

              class Father extends GrandFather(){}

              class Son extends Father(){}

java多层继承的案例

class GrandFather {
    public void show() {
        System.out.println("我是爷爷");
    }
}

class Father extends GrandFather {
    public void method(){
        System.out.println("我是老子");
    }
}

class Son extends Father {}

class ExtendsDemo2 {
    public static void main(String[] args) {
        Son s = new Son();
        s.method(); //使用父亲的
        s.show(); //使用爷爷的
    }
}

  1.2、继承注意事项

        A:子类只能继承父类所有非私有的成员(即成员方法和成员变量)
        B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法。(子类通过super访问父类的成员方法
        C:不要为了部分功能而去继承。只要A和B两者关系是"A is B"或"B is A"才去继承。
继承的案例2:

/*    

    继承其实体现的是一种关系:"is a"。
            Person
                Student
                Teacher
            水果
                苹果
                香蕉
                橘子
                
        采用假设法。
            如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。
*/
class Father {
    private int num = 10;
    public int num2 = 20;
    
    //私有方法,子类不能继承
    private void method() {
        System.out.println(num);
        System.out.println(num2);
    }
    
    public void show() {
        System.out.println(num);
        System.out.println(num2);
    }
}

class Son extends Father {
    public void function() {
        //num可以在Father中访问private
        //System.out.println(num); //子类不能继承父类的私有成员变量
        System.out.println(num2);
    }
}

class ExtendsDemo3 {
    public static void main(String[] args) {
        // 创建对象
        Son s = new Son();
        //s.method(); //子类不能继承父类的私有成员方法
        s.show();
        s.function();
    }
}

  1.3、继承中成员变量和成员方法的调用

继承中成员变量的调用规则

/*

    继承中成员变量的关系:
            在子类方法中访问一个变量的查找顺序:
                a:在子类方法的局部范围找,有就使用
                b:在子类的成员范围找,有就使用
                c:在父类的成员范围找,有就使用
                d:如果还找不到,就报错。
*/
class Father {
    public int num = 10;
    
    public void method() {
        int num = 50;
    }
}

class Son extends Father {
    public int num2 = 20;
    public int num = 30;
    
    public void show() {
        int num = 40;
        System.out.println(num);
        System.out.println(num2);
        // 找不到符号,报错
        //System.out.println(num3);
    }
}

class ExtendsDemo4 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        s.show();
    }
}

继承中成员方法的调用规则

/*
    继承中成员方法的关系:
            通过子类对象调用方法:
                a:先找子类中,看有没有这个方法,有就使用
                b:再看父类中,有没有这个方法,有就使用
                c:如果没有就报错。
*/
class Father {
    public void show() {
        System.out.println("show Father");
    }
}

class Son extends Father {
    public void method() {
        System.out.println("method Son");
    }
    
    public void show() {
        System.out.println("show Son");
    }
}

class ExtendsDemo8 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        s.show();
        s.method();
        //s.fucntion(); //找不到符号
    }
}

由以上两个案例可知,在继承中,无论是成员变量还是成员方法,调用顺序都遵守“就近原则”:

成员变量:子类方法局部变量-->子类成员变量-->父类成员变量
成员方法:子类成员方法-->父类成员方法

  1.4、继承中this和super关键字的作用

this和super的区别?

            this代表本类对应的引用
            super代表父类存储空间的标识(可以理解为父类的引用,可以操作父类的成员)     

   怎么用呢?
            A:调用成员变量
                this.成员变量 调用本类的成员变量
                super.成员变量 调用父类的成员变量
            B:调用构造方法
                this(...)    调用本类的构造方法
                super(...)    调用父类的构造方法
            C:调用成员方法
                this.成员方法 调用本类的成员方法
                super.成员方法 调用父类的成员方法
继承中用this和super区分父类(成员变量)、子类(成员变量)和子类方法中(局部变量)同名num的值

class Father {
    public int num = 10;
}

class Son extends Father {
    public int num = 20;
    
    public void show() {
        int num = 30;
        System.out.println(num);   //局部变量优先级最高,num=30
        System.out.println(this.num);  //本类成员变量num=20
        System.out.println(super.num);  //父类成员变量num=30
    }
}

class ExtendsDemo5 {
    public static void main(String[] args) {
        Son s = new Son();
        s.show();
    }
}

  1.5、继承的构造方法

       在继承中,子类中所有的构造方法默认都会访问父类中无参构造方法(因为子类会继承父类中的数据,可能还会使用父类的数据。)所以,子类初始化之前,一定要先完成父类数据的初始化。

 注意:子类每一个构造方法的第一条语句默认都是:super(); 

 如下案例:

class Father {
    int age;

    public Father() {
        System.out.println("Father的无参构造方法");
    }
    
    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}

class Son extends Father {
    public Son() {
        //super();
        System.out.println("Son的无参构造方法");
    }
    
    public Son(String name) {
        //super();
        System.out.println("Son的带参构造方法");
    }
}    

class ExtendsDemo6 {
    public static void main(String[] args) {
        //创建对象
        Son s = new Son();
        System.out.println("------------");
        Son s2 = new Son("林青霞");
    }
}

//执行结果如下:

Father的无参构造方法
Son的无参构造方法
------------
Father的无参构造方法
Son的带参构造方法

特别地,如果父类没有无参构造方法的话,那么子类的构造方法就会出现报错。解决方式如下:

解决父类没有无参构造方法的措施:

        A:在父类中加一个无参构造方法
        B:通过使用super关键字去显示的调用父类的带参构造方法 
        C:子类通过this去调用本类的其他构造方法
            子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。

 注意事项:
        this(...)或者super(...)必须出现在第一条语句上。
        如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。

class Father {
    /*
    public Father() {
        System.out.println("Father的无参构造方法");
    }
    */
    
    public Father(String name) {
        System.out.println("Father的带参构造方法");
    }
}

class Son extends Father {
    public Son() {
        super("随便给");  //super调用父类的带参构造方法
        System.out.println("Son的无参构造方法");
        //super("随便给");
    }
    
    public Son(String name) {
        //super("随便给");
        this();  //通过this调用本类的无参son()构造方法中的super("随便给");调用父类的带参构造方法初始化数据  
        System.out.println("Son的带参构造方法");
    }
}

class ExtendsDemo7 {
    public static void main(String[] args) {
        Son s = new Son();
        System.out.println("----------------");
        Son ss = new Son("林青霞");
    }
}

//执行结果如下:

Father的带参构造方法
Son的无参构造方法
----------------
Father的带参构造方法
Son的无参构造方法
Son的带参构造方法

1.6、三道经典的继承案例

看程序写结果案例1:

/*
    看程序写结果:
        A:一个类的静态代码块,构造代码块,构造方法的执行流程
            静态代码块 > 构造代码块 > 构造方法
        B:静态的内容是随着类的加载而加载
            静态代码块的内容会优先执行
        C:子类初始化之前先会进行父类的初始化
  
*/
class Fu {
    static {
        System.out.println("静态代码块Fu");
    }

    {
        System.out.println("构造代码块Fu");
    }

    public Fu() {
        System.out.println("构造方法Fu");
    }
}

class Zi extends Fu {
    static {
        System.out.println("静态代码块Zi");
    }

    {
        System.out.println("构造代码块Zi");
    }

    public Zi() {
        System.out.println("构造方法Zi");
    }
}

class ExtendsTest2 {
    public static void main(String[] args) {
        Zi z = new Zi();
    }
}


//执行的结果是:
        静态代码块Fu
        静态代码块Zi
        构造代码块Fu
        构造方法Fu
        构造代码块Zi
        构造方法Zi

super的秒用:案例2

class Person {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Person() {
    }

    public Person(String name,int age) { //"林青霞",27
        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 Student extends Person {
    public Student() {}
    
    public Student(String name,int age) { //"林青霞",27
        //this.name = name;
        //this.age = age;
        super(name,age);  //super调用父类的this.name = name和this.age = age;
    }
}

//定义老师类
class Teacher extends Person {

}

class ExtendsTest4 {
    public static void main(String[] args) {
        //创建学生对象并测试
        //方式1
        Student s1 = new Student();
        s1.setName("林青霞");
        s1.setAge(27);
        System.out.println(s1.getName()+"---"+s1.getAge());
        
        //方式2
        Student s2 = new Student("林青霞",27);
        System.out.println(s2.getName()+"---"+s2.getAge());
        
        //补齐老师类中的代码并进行测试。
    }
}

继承面试题:案例3

//看程序写结果

class X {
    {
        System.out.print("Father");
    }
    Y b = new Y();
    X() {
        System.out.print("X");
    }
}

class Y {
    Y() {
        System.out.print("Y");
    }
}

public class test extends X {
    {
        System.out.print("Son");
    }
    Y y = new Y();
    test() {
        //super
        System.out.print("Z");
    }
    public static void main(String[] args) {
        new test(); 
    }
}

//执行结果如下

FatherYXSonYZ

//由上结果可知,继承中,子类new对象初始化时,是直接去父类中进行数据初始化后,再进子类的进行数据初始化的

2、方法重写

方法重写Override方法重载Overload
方法重写:子类中出现了和父类中方法声明一模一样的方法。方法重载:
        本类中出现的方法名一样,但参数列表和返回值类型都不同。

class Phone {
    public void call(String name) {
        System.out.println("给"+name+"打电话");
    }
}

class NewPhone extends Phone {
    public void call(String name) {
       
        super.call(name);
        System.out.println("可以听天气预报了");

    }
}

class ExtendsDemo9 {
    public static void main(String[] args) {
        NewPhone np = new NewPhone();
        np.call("苏炳添");
    }
}

public class test {
    public static void main(String[] args){
        System.out.println(sum('a','b'));
        System.out.println(sum(3,3,3));
        System.out.println(sum(3,3,3,3));
    }

    //two char
    public static char sum(char a,char b) {
        return (char) (a+b);
    }
    //three number
    public static int sum(int a, int b, int c) {
        return a + b + c ;
    }
    //four number
    public static int sum(int a, int b, int c,int d) {
        return a + b + c + d;
    }
}

  2.1、方法重写的特点

    (1)子类对象调用方法的时候
                    先找子类本身,再找父类。
        
    (2)方法重写的应用
             当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
             这样,即沿袭了父类的功能,又定义了子类特有的内容。

    (3)方法重写的注意事项
        A:父类中私有方法不能被重写
            因为父类私有方法子类根本就无法继承
        B:子类重写父类方法时,访问权限不能更低
            最好就一致
        C:父类静态方法,子类也必须通过静态方法进行重写
            其实这个算不上方法重写,但是现象确实如此,至于为什么算不上方法重写,多态中我会讲解
            
        //子类重写父类方法的时候,最好声明一模一样。

3、final关键字

       final字面意思表“最终的”,它可以修饰类,方法,变量。

  3.1、final的特点

final的特点:
        final可以修饰类,该类不能被继承。
        final可以修饰方法,该方法不能被重写。(覆盖,复写)
        final可以修饰变量,该变量不能被重新赋值。因为这个变量其实常量。

  3.2、final修饰局部变量

final修饰局部变量的问题?
        基本类型:基本类型的值不能发生改变。
        引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。

class Student {
    int age = 10;
}
class FinalTest {
    public static void main(String[] args) {
        //局部变量是基本数据类型
        int x = 10;
        x = 100;
        System.out.println(x);
        final int y = 10;
        //无法为最终变量y分配值
        //y = 100;
        System.out.println(y);
        System.out.println("--------------");
        
        //局部变量是引用数据类型
        Student s = new Student();
        System.out.println(s.age);
        s.age = 100;
        System.out.println(s.age);
        System.out.println("--------------");
        
        final Student ss = new Student();
        System.out.println(ss.age);
        ss.age = 100;
        System.out.println(ss.age);
        
        //重新分配内存空间
        //无法为最终变量ss分配值
        ss = new Student();
    }
}

  3.3、final修饰变量的初始化时机

final修饰变量的初始化时机
        A:被final修饰的变量只能赋值一次。
        B:在构造方法完毕前。(非静态的常量)

             //就是说final的变量赋值的时机要在代码块里赋值,或在构造方法中赋值,又或者在声明final变量时直接赋值才行

            赋值的顺序:成员方法声明>代码块>成员方法

class Demo {
    //int num = 10;
    //final int num2 = 20;
    
    int num;
    final int num2;  //final变量赋值点1
    
    {
        //num2 = 10;  //final变量赋值点2 
    }
    
    public Demo() {
        num = 100;
        //无法为最终变量num2分配值
        num2 = 200;   //final变量赋值点2 
    }
}

class FinalTest2 {
    public static void main(String[] args) {
        Demo d = new Demo();
        System.out.println(d.num);
        System.out.println(d.num2);
    }
}

  3.4、final保护父类的机密性

final保护父类的机密性

class Fu {
    public final void show() {
        System.out.println("这里是绝密资源,任何人都不能修改");
    }
}

class Zi extends Fu {
    // Zi中的show()无法覆盖Fu中的show()
    public void show() {
        System.out.println("这是一堆垃圾");
    }
}

class ZiDemo {
    public static void main(String[] args) {
        Zi z = new Zi();
        z.show();
    }
}

4、多态

       多态:同一个对象(事物),在不同时刻体现出来的不同状态。比如水在不同的条件下可以有液体、气体和固体三个状态。

  4.1、多态的条件

多态的前提:
        A:要有继承关系
        B:要有方法重写
            其实没有也是可以的,但是如果没有这个就没有意义。
                动物 d = new 猫();
                d.show();
                动物 d = new 狗();
                d.show();
        C:要有父类引用指向子类对象
            父 f =  new 子();

  4.2、 多态中的成员访问特点:

 多态中的成员访问特点:
        A:成员变量
            编译看左边(父类),运行看左边(父类)。
        B:构造方法
            创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
        C:成员方法
            编译看左边(父类),运行看右边(子类)。
        D:静态方法
            编译看左边(父类),运行看左边(父类)。
            (静态和类相关,算不上重写,所以,访问还是左边的)
            
        由于成员方法存在方法重写,所以它运行看右边。

class Fu {
    public int num = 100;

    public void show() {
        System.out.println("show Fu");
    }
    
    public static void function() {
        System.out.println("function Fu");
    }
}

class Zi extends Fu {
    public int num = 1000;
    public int num2 = 200;

    public void show() {
        System.out.println("show Zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }
    
    public static void function() {
        System.out.println("function Zi");
    }
}

class DuoTaiDemo {
    public static void main(String[] args) {
        //要有父类引用指向子类对象。
        //父 f =  new 子();
        Fu f = new Zi();
        System.out.println(f.num);
        //找不到符号
        //System.out.println(f.num2);
        
        f.show();
        //找不到符号
        //f.method();
        f.function();
    }
}

  4.3、多态的向上转型和向下转型:

多态的向上转型和向下转型:

    多态的弊端:
        不能使用子类的特有功能。  
 

   我就想使用子类的特有功能?行不行?
        行。
        
    怎么用呢?
        A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
        B:把父类的引用强制转换为子类的引用。(向下转型)
        
    对象间的转型问题:
        向上转型:
            Fu f = new Zi();
        向下转型:
            Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。

//案例代码如下:

class Fu {
    public void show() {
        System.out.println("show fu");
    }
}

class Zi extends Fu {
    public void show() {
        System.out.println("show zi");
    }
    
    public void method() {
        System.out.println("method zi");
    }

}

class DuoTaiDemo4 {
    public static void main(String[] args) {
        //测试
        Fu f = new Zi();
        f.show();
        //f.method();
        
        //创建子类对象
        //Zi z = new Zi();
        //z.show();
        //z.method();
        
        //你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢?
        //如果可以,但是如下
        Zi z = (Zi)f;
        z.show();
        z.method();
    }
}

  4.4、多态的内存图

多态的内存图:

//内存图1

//内存图2

    4.5、多态的经典案例

多态的经典案例:

/*
    看程序写结果:先判断有没有问题,如果没有,写出结果
    
    多态的成员访问特点:
        方法:编译看左边,运行看右边。
        
    继承的时候:
        子类中有和父类中一样的方法,叫重写。
        子类中没有父亲中出现过的方法,方法就被继承过来了。
*/
class A {
    public void show() {
        show2();
    }
    public void show2() {
        System.out.println("我");
    }
}
class B extends A {
    /*
    public void show() {
        show2();
    }
    */

    public void show2() {
        System.out.println("爱");
    }
}
class C extends B {
    public void show() {
        super.show();
    }
    public void show2() {
        System.out.println("你");
    }
}
public class DuoTaiTest4 {
    public static void main(String[] args) {
        A a = new B();
        a.show();
        
        B b = new C();
        b.show();
    }
}

//执行结果如下:

5、抽象类

       在java中用abstract关键字来声明抽象类,抽象类是不能实例化的类,是泛指的概念,需要子类去实例化。比如动物可以设计成一个抽象的类,要用猫类和狗类去实例化。吃饭和睡觉也可以设置成抽象类中抽象的方法,再通过不同的子类(猫类或狗类)去实现各自具体不同的动作。这样通过一个抽象类,由子类去实现具体的功能,提高了代码的扩展性(子类保证)和易维护(抽象的父类保护)。

  5.1、抽象类的基本特点

抽象类的基本特点

        A:抽象类和抽象方法必须用abstract关键字修饰
        B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
        C:抽象类不能实例化
            因为它不是具体的。
            抽象类有构造方法,但是不能实例化(即不能new抽象类)?构造方法的作用是什么呢?用于子类访问父类数据的初始化。
        D:抽象的子类
            a:如果不想重写抽象方法,该子类是一个抽象类。
            b:重写所有的抽象方法,这个时候子类是一个具体的类。
            
        抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
            Animal a = new Cat();

       同时 abstract不能与private、final和static关键字共存。

//abstract class Animal //抽象类的声明格式
abstract class Animal {
    //抽象方法
    //public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体
    public abstract void eat();
    
    public Animal(){}
}

//子类是抽象类
abstract class Dog extends Animal {}

//子类是具体类,重写抽象方法
class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

class AbstractDemo {
    public static void main(String[] args) {
        //创建对象
        //Animal是抽象的; 无法实例化
        //Animal a = new Animal();
        //通过多态的方式
        Animal a = new Cat();
        a.eat();
    }
}

  5.2、抽象类的成员特征

    抽象类的成员特点:
        成员变量:既可以是变量,也可以是常量。
        构造方法:有。
                    用于子类访问父类数据的初始化。
        成员方法:既可以是抽象的,也可以是非抽象的。
        
    抽象类的成员方法特性:
        A:抽象方法 强制要求子类做的事情。
        B:非抽象方法 子类继承的事情,提高代码复用性。

abstract class Animal {
    public int num = 10;
    public final int num2 = 20;

    public Animal() {}
    
    public Animal(String name,int age){}
    
    public abstract void show();
    
    public void method() {
        System.out.println("method");
    }
}

class Dog extends Animal {
    public void show() {
        System.out.println("show Dog");
    }
}

class AbstractDemo2 {
    public static void main(String[] args) {
        //创建对象
        Animal a = new Dog();
        a.num = 100;
        System.out.println(a.num);
        //a.num2 = 200;
        System.out.println(a.num2);
        System.out.println("--------------");
        a.show();
        a.method();
    }
}

  5.3、经典抽象类(猫狗案例)

//定义抽象的动物类
abstract class Animal {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Animal() {}
    
    public Animal(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 abstract void eat();
}

//定义具体的狗类
class Dog extends Animal {
    public Dog() {}
    
    public Dog(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("狗吃肉");
    }
}

//定义具体的猫类
class Cat extends Animal {
    public Cat() {}
    
    public Cat(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//测试类
class AbstractTest {
    public static void main(String[] args) {
        //测试狗类
        //具体类用法
        //方式1:
        Dog d = new Dog();
        d.setName("旺财");
        d.setAge(3);
        System.out.println(d.getName()+"---"+d.getAge());
        d.eat();
        //方式2:
        Dog d2 = new Dog("旺财",3);
        System.out.println(d2.getName()+"---"+d2.getAge());
        d2.eat();
        System.out.println("---------------------------");
        
        Animal a = new Dog();
        a.setName("旺财");
        a.setAge(3);
        System.out.println(a.getName()+"---"+a.getAge());
        a.eat();
        
        Animal a2 = new Dog("旺财",3);
        System.out.println(a2.getName()+"---"+a2.getAge());
        a2.eat();
        
        //练习:测试猫类
    }
}

6、接口

       由于java中的继承只能是单继承,不支持多继承。所有引入了接口(interface)支持多继承。接口是一组常量和抽象方法的集合。也可以说接口是一个扩展通用的模板,比抽象类更能体现java程序的灵活性。

       比如抽象的动物类中的抽象方法eat(),猫类和狗类重写各自eat()方法(猫狗吃的食物不一样),同时人也有eat()方法,让人继承抽象动物类就不合适了。所以就可以通过接口写一个吃的接口,那么人和动物都可以通过吃接口实现吃各自的食物了。又比如一个房间有一个制冷的管口(相当java的接口),但是通向房间制冷管口的空调的制冷功能坏了,那么我可以用能制热制冷的热力泵通过房间的制冷管口实现制冷的功能效果了。

       接口实现的是“is-like-a(像是一个)”的功能,而继承实现的是"is a(是一个)"的功能。

  6.1、接口的特点

接口的特点:
        A:接口用关键字interface表示    
            interface 接口名 {}
        B:类实现接口用implements表示
            class 类名 implements 接口名 {}
        C:接口不能实例化
            但是接口可以跟抽象类一样,靠具体的子类实现的。是多态的方式

            AnimalTrain at = new Cat();
        D:接口的子类
            a:可以是抽象类。但是意义不大。
            b:可以是具体类。要重写接口中的所有抽象方法。(推荐方案)
    

//在生产环境中,接口多态比抽象类多态更常用,具体类多态几乎不用

//接口案例1:

//定义动物培训接口
interface AnimalTrain {
    public abstract void jump();
}

//抽象类实现接口
abstract class Dog implements AnimalTrain {
}

//具体类实现接口
class Cat implements AnimalTrain {
    public void jump() {
        System.out.println("猫可以跳高了");
    }
}

class InterfaceDemo {
    public static void main(String[] args) {
        //AnimalTrain是抽象的; 无法实例化
        //AnimalTrain at = new AnimalTrain();
        //at.jump();
        
        AnimalTrain at = new Cat();
        at.jump();
    }
}

//执行结果如下:

 猫可以跳高了

  6.2、接口的成员特点

接口成员特点
        成员变量;只能是常量,并且是静态的。
                默认修饰符:public static final
                建议:自己手动给出。
        构造方法:接口没有构造方法。
        成员方法:只能是抽象方法。
                默认修饰符:public abstract
                建议:自己手动给出。
        
    所有的类都默认继承自一个类:Object。
    类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。

//接口案例2:

interface Inter {
    public int num = 10;
    public final int num2 = 20;
    public static final int num3 = 30;
    
    //错误: 需要<标识符>
    //public Inter() {}
    
    //接口方法不能带有主体
    //public void show() {}

    //abstract void show(); //默认public
    public void show(); //默认abstract
}

//接口名+Impl这种格式是接口的实现类格式
/*
class InterImpl implements Inter {
    public InterImpl() {
        super();
    }
}
*/

class InterImpl extends Object implements Inter {
    public InterImpl() {
        super();
    }
    
    public void show() {}
}

//测试类
class InterfaceDemo2 {
    public static void main(String[] args) {
        //创建对象
        Inter i = new InterImpl();
        System.out.println(i.num);
        System.out.println(i.num2);
        //i.num = 100;
        //i.num2 = 200;
        //System.out.println(i.num); //无法为最终变量num分配值
        //System.out.println(i.num2);//无法为最终变量num2分配值
        System.out.println(Inter.num);
        System.out.println(Inter.num2);
        System.out.println("--------------");
    }
}

  6.3、类与类,类与接口,接口与接口的关系

类与类,类与接口,接口与接口的关系 :

   类与类:
        继承关系,只能单继承,可以多层继承。
    类与接口:
        实现关系,可以单实现,也可以多实现。
        并且还可以在继承一个类的同时实现多个接口。
    接口与接口:
        继承关系,可以单继承,也可以多继承。

//接口案例2:

interface Father {
    public abstract void show();
}

interface Mother {
    public abstract void show2();
}

interface Sister extends Father,Mother {

}

//class Son implements Father,Mother //多实现
class Son extends Object implements Father,Mother {
    public void show() {
        System.out.println("show son");
    }
    
    public void show2() {
        System.out.println("show2 son");
    }
}

class InterfaceDemo3 {
    public static void main(String[] args) {
        //创建对象
        Father f = new Son();
        f.show();
        //f.show2(); //报错
    
        Mother m = new Son();
        //m.show(); //报错
        m.show2();
    }
}

  6.4、经典猫狗接口案例

/*
    猫狗案例,加入跳高的额外功能
    
    分析:从具体到抽象
        猫:
            姓名,年龄
            吃饭,睡觉
        狗:
            姓名,年龄
            吃饭,睡觉
            
        由于有共性功能,所以,我们抽取出一个父类:
        动物:
            姓名,年龄
            吃饭();
            睡觉(){}
            
        猫:继承自动物
        狗:继承自动物
        
        跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口
        接口:
            跳高
            
        部分猫:实现跳高
        部分狗:实现跳高
    实现;
        从抽象到具体
        
    使用:
        使用具体类
*/
//定义跳高接口
interface Jumpping {
    //跳高功能
    public abstract void jump();
}

//定义抽象类
abstract class Animal {
    //姓名
    private String name;
    //年龄
    private int age;
    
    public Animal() {}
    
    public Animal(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 abstract void eat();
    
    //睡觉(){}
    public void sleep() {
        System.out.println("睡觉觉了");
    }
}

//具体猫类
class Cat extends Animal {
    public Cat(){}
    
    public Cat(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//具体狗类
class Dog extends Animal {
    public Dog(){}
    
    public Dog(String name,int age) {
        super(name,age);
    }
    
    public void eat() {
        System.out.println("狗吃肉");
    }
}

//有跳高功能的猫
class JumpCat extends Cat implements Jumpping {
    public JumpCat() {}
    
    public JumpCat(String name,int age) {
        super(name,age);
    }

    public void jump() {
        System.out.println("跳高猫");
    }
}

//有跳高功能的狗
class JumpDog extends Dog implements Jumpping {
    public JumpDog() {}
    
    public JumpDog(String name,int age) {
        super(name,age);
    }

    public void jump() {
        System.out.println("跳高狗");
    }
}

class InterfaceTest {
    public static void main(String[] args) {
        //定义跳高猫并测试
        JumpCat jc = new JumpCat();
        jc.setName("哆啦A梦");
        jc.setAge(3);
        System.out.println(jc.getName()+"---"+jc.getAge());
        jc.eat();
        jc.sleep();
        jc.jump();
        System.out.println("-----------------");
        
        JumpCat jc2 = new JumpCat("加菲猫",2);
        System.out.println(jc2.getName()+"---"+jc2.getAge());
        jc2.eat();
        jc2.sleep();
        jc2.jump();
        
        //定义跳高狗并进行测试的事情自己完成。
    }
}

7、抽象类和接口的区别

抽象类接口
描述“is a”的关系,体现共同性“is like a”的关系,体现扩展性
成员变量变量、常量 只为静态常量,默认public static final
构造方法
成员方法可抽象或非抽象只为抽象方法,默认public abstract

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值