第十二课 Java基础篇——面向对象进阶(三)

五、抽象类

#抽象方法

抽象方法:将共性的行为(方法)抽取到父类之后。

由于每一个子类执行的内容是不一样

所以,在父类中不能确定具体的方法体

该方法就可以定义为抽象方法

抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类

#抽象类和抽象方法的定义格式

抽象方法的定义格式:

public abstract 返回值类型 方法名(参数列表);

抽象类的定义格式:

public abstract class 类名{}

#抽象类和抽象方法的意义

强制子类必须按照这种格式进行重写

#抽象类和抽象方法的注意事项

抽象类不能实例化

抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

可以有构造方法

抽象类的子类

要么重写抽象类中的所有抽象方法

要么是抽象类

练习、编写带有抽象类的标准Javabean类

青蛙frog 属性:名字,年龄 行为:吃虫子,喝水

狗Dog 属性:名字,年龄 行为:吃骨头,喝水

山羊Sheep 属性:名字,年龄 行为:吃草,喝水

Animal.Java

package cn.nwafu.abstractdemo2;

public 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 void drink(){
        System.out.println("动物在喝水");
    }
    public abstract void eat();
}

frog.Java

package cn.nwafu.abstractdemo2;

public class frog extends Animal{
    public frog() {
    }

    public frog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("青蛙在吃虫子");
    }
}

Dog.Java

package cn.nwafu.abstractdemo2;

public class Dog extends Animal{
    public Dog() {
    }

    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("狗在吃骨头");
    }
}

Sheep.Java

package cn.nwafu.abstractdemo2;

public class Sheep extends Animal{
    public Sheep() {
    }

    public Sheep(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("山羊在吃草");
    }
}

Test.Java

package cn.nwafu.abstractdemo2;

import java.sql.SQLOutput;

public class Test {
    public static void main(String[] args) {
        frog f = new frog("qingwa",2);
        System.out.println(f.getName()+","+f.getAge());
        f.drink();
        f.eat();

        Dog d = new Dog("taidi",1);
        System.out.println(d.getName()+","+d.getAge());
        d.drink();
        d.eat();

        Sheep s = new Sheep("shanyang",3);
        System.out.println(s.getName()+","+s.getAge());
        s.drink();
        s.eat();
    }
}

六、接口

#为什么有接口?

接口 :就是一种规则,是对行为的抽象

#接口的定义和使用

接口用关键字interface来定义

public interface 接口名{}

接口不能实例化

接口和类之间是实现关系,通过implements关键字表示

public class 类名 implements 接口名{}

接口的子类(实现类)

要么重写接口中的所有抽象方法

要么是抽象类

注意1:接口和类的实现关系,可以单实现,也可以多实现。

public class 类名 implements 接口名1,接口名2{}

注意2:实现类还可以在继承一个类的同时实现多个接口。

public class类名 extends 父类 implements 接口名1,接口名2{}

#接口中成员的特点

成员变量

只能是常量

默认修饰符:public static final

构造方法 没有

成员方法

只能是抽象方法

默认修饰符:public abstract

JDK7以前:接口中只能定义抽象方法。

JDK8的新特性:接口中可以定义有方法体的方法。

JDK9的新特性:接口中可以定义私有方法。

#接口和类之间的关系

1.类和类的关系

继承关系,只能单继承,不能多继承,但是可以多层继承

2.类和接口的关系

实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口

3.接口和接口的关系

继承关系,可以单继承,也可以多继承

练习、编写带有接口和抽象类的标准Javabean类

我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。

为了出国交流,跟乒乓球相关的人员都需要学习英语。

请用所有知识分析,在这个案例中,哪些是具体类,哪些是抽象类,哪些是接口?

乒乓球运动员:姓名,年龄,学打乒乓球,说英语

篮球运动员:姓名,年龄,学打篮球

乒乓球教练:姓名,年龄,教打乒乓球,说英语

篮球教练:姓名,年龄,教打篮球

思路一

思路二、

BasketballSporter.Java

package cn.nwafu.a01demo5;

public class BasketballSporter extends Sporter{
    public BasketballSporter() {
    }

    public BasketballSporter(String name, int age) {
        super(name, age);
    }

    @Override
    public void study() {
        System.out.println("篮球运动员在学习");
    }
}

BasketCoach.Java

package cn.nwafu.a01demo5;

public class BasketCoach extends Coach{
    public BasketCoach() {
    }

    public BasketCoach(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("篮球教练在教学");
    }
}

Coach.Java

package cn.nwafu.a01demo5;

public abstract class Coach extends Person{
    public Coach() {
    }

    public Coach(String name, int age) {
        super(name, age);
    }

    public abstract void teach();
}

English.Java

package cn.nwafu.a01demo5;

public interface English {
    public abstract void speakEnglish();
}

Person.Java

package cn.nwafu.a01demo5;
//因为现在我不想让外界去直接创建人的对象
//因为直接创建顶层父类人的对象此时是没有意义的
//所以我就把他写为抽象的。
public abstract class Person {
    private String name;
    private 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;
    }
}

PingPangCoach.Java

package cn.nwafu.a01demo5;

public class PingPangCoach extends Coach
implements English{
    public PingPangCoach() {
    }

    public PingPangCoach(String name, int age) {
        super(name, age);
    }

    @Override
    public void teach() {
        System.out.println("乒乓球教练在教学");
    }

    @Override
    public void speakEnglish() {
        System.out.println("乒乓球教练在说英语");
    }
}

PingPangSporter.Java

package cn.nwafu.a01demo5;

public class PingPangSporter extends Sporter implements English{
    public PingPangSporter() {
    }

    public PingPangSporter(String name, int age) {
        super(name, age);
    }

    @Override
    public void study() {
        System.out.println("乒乓球运动员在学习");
    }

    @Override
    public void speakEnglish() {
        System.out.println("乒乓球运动员在说英语");
    }
}

Sporter.Java

package cn.nwafu.a01demo5;

public abstract class Sporter extends Person{


    public Sporter() {
    }

    public Sporter(String name, int age) {
        super(name, age);
    }

    public abstract void study();

}

Test.Java

package cn.nwafu.a01demo5;

public class Test {
    public static void main(String[] args) {
//        练习、编写带有接口和抽象类的标准Javabean类
//        我们现在有乒乓球运动员和篮球运动员,乒乓球教练和篮球教练。
//        为了出国交流,跟乒乓球相关的人员都需要学习英语。
//        请用所有知识分析,在这个案例中,哪些是具体类,哪些是抽象类,哪些是接口?
//                乒乓球运动员:姓名,年龄,学打乒乓球,说英语
//        篮球运动员:姓名,年龄,学打篮球
//        乒乓球教练:姓名,年龄,教打乒乓球,说英语
//        篮球教练:姓名,年龄,教打篮球

        PingPangSporter pps = new PingPangSporter("xuxin",27);
        System.out.println(pps.getName()+","+pps.getAge());
        pps.study();
        pps.speakEnglish();
    }
}

#补充知识点

一、JDK8与JDK9新增的方法

●JDK7以前:接口中只能定义抽象方法。

●JDK8的新特性:接口中可以定义有方法体的方法。(默认、静态)

●JDK9的新特性:接口中可以定义私有方法。

私有方法分为两种:普通的私有方法,静态的私有方法

1、JDK8开始接口中新增的方法

a.允许在接口中定义默认方法,需要使用关键字default修饰

作用:解决接口升级的问题

接口中默认方法的定义格式:

格式: public default 返回值类型 方法名(参数列表){}

范例: public default void show(){ }

接口中默认方法的注意事项:

默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字

public可以省略,default不能省略

如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写

Test.Java

package cn.nwafu.a01demo6;

public class Test {
    public static void main(String[] args) {
//接口中默认方法的定义格式:
//格式: public default 返回值类型 方法名(参数列表){}
//范例: public default void show(){ }
//接口中默认方法的注意事项:
//默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字
//public可以省略,default不能省略
//如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写
        InterImpl ii = new InterImpl();
        ii.method1();
        ii.show();
    }
}

InterA.Java

package cn.nwafu.a01demo6;

public interface InterA {
//    接口中默认方法的定义格式:
//    格式: public default 返回值类型 方法名(参数列表){}
//    范例: public default void show(){ }
//    接口中默认方法的注意事项:
//    默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字
//    public可以省略,default不能省略
//    如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写

public default void show(){
    System.out.println("InterA接口中的默认方法-----show");
}
public abstract void method1();
}

InterB.Java

package cn.nwafu.a01demo6;

public interface InterB {

    public default void show(){
        System.out.println("InterB接口中的默认方法-----show");
    }
}

InterImpl.Java

package cn.nwafu.a01demo6;

public class InterImpl implements InterA ,InterB{
    @Override
    public void show() {
        System.out.println("重写接口中的show方法");
    }

    @Override
    public void method1() {
        System.out.println("实现类重写的抽象方法");
    }
}

b.允许在接口中定义定义静态方法,需要用static修饰

接口中静态方法的定义格式:

格式: public static 返回值类型 方法名(参数列表){ }

范例: public static void show(){ }

接口中静态方法的注意事项:

●静态方法只能通过接口名调用,不能通过实现类名或者对象名调用

public可以省略,static不能省略

Test.Java

package cn.nwafu.a01demo7;

public class Test {
    public static void main(String[] args) {
//  接口中静态方法的定义格式:
//格式: public static 返回值类型 方法名(参数列表){ }
//范例: public static void show(){ }
//接口中静态方法的注意事项:
//静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
//public可以省略,static不能省略

        //调用接口中的静态方法
        Inter.show();
        //调用实现类中的静态方法

        //注意:静态发方法不是重写,只是刚好方法名一样而已
        //子类把从父类继承下来的虚方法表里面的方法进行覆盖了,这才叫重写。
        InterImpl.show();
    }
}

InterImpl.Java

package cn.nwafu.a01demo7;

public class InterImpl implements Inter{

    @Override
    public void method() {
        System.out.println("InterImpl重写的抽象方法");
    }

    public static void show(){
        System.out.println("实现类中的静态方法");
    }
}

Inter.Java

package cn.nwafu.a01demo7;

public interface Inter {
    public abstract void method();
    public static void show(){
        System.out.println("接口中的静态方法");
    }
}

2.JDK9新增的方法

私有方法分为两种:普通的私有方法,静态的私有方法

接口中私有方法的定义格式:

格式1: private返回值类型方法名(参数列表){}

范例1: private void show(){ }

格式2: private static返回值类型方法名(参数列表){ }

范例2: private static void method(){ }

InterA.Java

package cn.nwafu.a01demo8;

public interface InterA {
    public default void show1(){
        System.out.println("show1开始执行了");
        //System.out.println("记录在运行过程中的各种细节,这里有100行代码");
        show3();
    }
     public static void show2(){
        System.out.println("show2开始执行了");
        //System.out.println("记录在运行过程中的各种细节,这里有100行代码");
        show4();
    }
    //普通的私有方法,给默认方法服务的
    //注意:删掉default
    private /* default */ void show3(){
        System.out.println("记录在运行过程中的各种细节,这里有100行代码");
    }
    //静态的的私有方法,给静态方法服务的
    private static void show4(){
        System.out.println("记录在运行过程中的各种细节,这里有100行代码");
    }
}

二、接口的应用

1.接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就可以了。

2. 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。

三、适配器设计模式

设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

简单理解:设计模式就是各种套路。

适配器设计模式:解决接口与接口实现类之间的矛盾问题

1.当一个接口中抽象方法过多,但是我只要使用其中一部分的时候,就可以适配器设计模式

2.书写步骤:

编写中间类XXXAdapter,实现对应的接口对接口中的抽象方法进行空实现

让真正的实现类继承中间类,并重写需要用的方法。

为了避免其他类创建适配器类的对象,中间的适配器类用abstract进行修饰

Inter.Java

package cn.nwafu.a01demo9;

public interface Inter {
    //需求,只想用method5()
    void menthod1();
    void menthod2();
    void menthod3();
    void menthod4();
    void menthod5();
    void menthod6();
    void menthod7();
    void menthod8();
    void menthod9();
    void menthod10();
}

InterAdapter.Java

package cn.nwafu.a01demo9;
//设置成abstract是为了不让外界创建对象,没有意义
public abstract class InterAdapter implements Inter{
    @Override
    public void menthod1() {

    }

    @Override
    public void menthod2() {

    }

    @Override
    public void menthod3() {

    }

    @Override
    public void menthod4() {

    }

    @Override
    public void menthod5() {

    }

    @Override
    public void menthod6() {

    }

    @Override
    public void menthod7() {

    }

    @Override
    public void menthod8() {

    }

    @Override
    public void menthod9() {

    }

    @Override
    public void menthod10() {

    }
}

InterImpl.Java

package cn.nwafu.a01demo9;

public class InterImpl extends InterAdapter{
//我需要用到哪个方法,就重写哪个方法就可以了
    @Override
    public void menthod5() {
        System.out.println("只用第五个方法");
    }

}

七、内部类

#类的五大成员:

属性、方法、构造方法、代码块、内部类

#什么是内部类?

在一个类的里面,再定义一个类。

举例:在A类的内部定义B类,B类就被称为内部类

#为什么要学习内部类?

B类表示的事物是A类的一部分,且B单独存在没有意义。

#内部类的分类

成员内部类

静态内部类

局部内部类

匿名内部类

1.成员内部类

写在成员位置的,属于外部类的成员

*成员内部类的代码如何书写

成员内部类可以被一些修饰符所修饰,比如: private, 默认,protected, public, static等

在成员内部类里面,JDK16之前不能定义静态变量,JDK 16开始才可以定义静态变量。

*如何创建成员内部类的对象

方式一:

在外部类中编写方法,对外提供内部类的对象。

方式二:

直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;

范例: Outer.Inner oi = new Outer( ).new Inner( );

*成员内部类如何获取外部类的成员变量

练习、

Test.Java

package cn.nwafu.a01innerclassdemo3;

public class Test {
    public static void main(String[] args) {
//创建内部类的对象并且调用show方法
        Outer.inner oi = new Outer().new inner();
        oi.show();
    }
}

Outer.Java

package cn.nwafu.a01innerclassdemo3;

public class Outer {
    private int a = 10;
    class inner{
        private int a =20;
        public void show(){
            int a =30;
            // Other.this 获取了外部类对象的地址值(见笔记)
            System.out.println(Outer.this.a);//10
            System.out.println(this.a);//20
            System.out.println(a);//30
        }
    }
}

2.静态内部类

#什么是静态内部类?

一种特殊的成员内部类

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。

#创建静态内部类对象的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();

#调用非静态方法的格式:先创建对象,用对象调用

#调用静态方法的格式:外部类名.内部类名.方法名();

Outer.Java

package cn.nwafu.a01innerclassdemo4;

import java.io.OutputStream;

public class Outer {
    int a =10;
    static int b = 20;
    //内部静态类
    static class Inter{
        public void show1(){
            //System.out.println(a);报错!因为a为非静态
            System.out.println(b);
            Outer o =new Outer();
            System.out.println(o.a);//调用需要创建对象
            System.out.println("非静态类的方法被调用了");
        }
        public static void show2(){
            //System.out.println(a);报错!因为a为非静态
            System.out.println(b);
            System.out.println("静态类的方法被调用了");
        }
    }
}

Test.Java

package cn.nwafu.a01innerclassdemo4;

public class Test {
    public static void main(String[] args) {
//注意事项:
        //1.静态内部类也是成员内部类中的一种
        //2.静态内部类只能访问外部类中的静态变量和静态方法,
        //如果想要访问非静态的需要创建外部类的对象。
        //创建静态内部类对象的格式:
        //外部类名.内部类名 对象名= new 外部类名.内部类名();
        //调用静态方法的格式:外部类名.内部类名.方法名();

        //创建静态内部类的对象
        //只要是静态的东西,都可以用类名点直接获取
        Outer.Inter oi = new Outer.Inter();
        oi.show1();

        //静态方法
        Outer.Inter.show2();
    }
}

3.局部内部类(了解)

1.将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量。

2.外界是无法直接使用,需要在方法内部创建对象并使用

3.该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

4.匿名内部类(重要)

本质上是隐藏了名字的内部类,可以写在成员位置,也可局部位置

#格式:new 类名或者接口名(){

重写方法;

};

#格式的细节

包含了继承或实现,方法重写,创建对象。

整体就是一个类的子类对象或者接口的实现类对象

#使用场景

当方法的参数是接口或者类时,

以接口为例,可以传递这个接口的实现类对象,

如果实现类只要使用一次,就可以用匿名内部类简化代码。

Test.Java

package cn.nwafu.a01innerclassdemo6;

public class Test {
    public static void main(String[] args) {
//匿名内部类(重要)
//本质上是隐藏了名字的内部类
//#格式:new 类名或者接口名(){
//    重写方法;
//};

        new Swim() {
            @Override
            public void swim() {
                System.out.println("重写swim方法");
            }

            public void method() {
                System.out.println("method");
            }
        };
        method1(
                new Animal(){

                    @Override
                    public void eat() {
                        System.out.println("gouchigutou");
                    }
                }
        );
        //在测试类中调用下面的method方法?
        //以前的方式如何调用?
        //要自己写一个子类继承Animal类
        //再创建子类的对象,传递给method方法

//        Dog d = new Dog();
//        method1(d);
        //如果Dog类我只要用一次,那么还需要单独定义一个类太麻烦了。
    }
        public static void method1(Animal d){// Animal a = 子类对象 多态
            d.eat();//编译看左边,运行看右边
        }


}

Animal.Java

package cn.nwafu.a01innerclassdemo6;

public abstract class Animal {
    public abstract void eat();
}

Dog.Java

package cn.nwafu.a01innerclassdemo6;

public class Dog extends Animal{

    @Override
    public void eat() {
        System.out.println("狗吃骨头2");
    }
}

Test2.Java

package cn.nwafu.a01innerclassdemo6;

public class Test2 {
    public static void main(String[] args) {
        //接口的实现类对象
        //接口多态
        Swim s = new Swim(){

            @Override
            public void swim() {
                System.out.println("swim重写");
            }
        };
        s.swim();

        new Swim(){

            @Override
            public void swim() {
                System.out.println("swim重写");
            }
        }.swim();//调用方法
    }
}

Swim.Java

package cn.nwafu.a01innerclassdemo6;

public interface Swim {
    public abstract void swim();
}

最后结尾附上我的源码,BiYing/Java学习12 - 码云 - 开源中国 (gitee.com)感兴趣的可以看看哈!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值