Java面向对象(3) —— 抽象类、接口、内部类、匿名内部类

抽象类(abstract)

java中可以定义没有方法体(只有方法头)的方法,该方法由子类来具体实现。该没有方法体的方法我们称之为抽象方法,含有抽象方法的类我们称之为抽象类。

有抽象方法的类,一定是抽象类。即抽象方法只能放在抽象类中。
但是抽象类中可以有具体方法,可以没有抽象方法。

特点

(1)抽象方法不能被调用

抽象方法代表一种不确定的操作或行为

(2)抽象类不能被实例化

虽然按照提示也能完成方法体实例化,但这是不靠谱的使用方式(这种不靠谱的方式也是后面提及的匿名的内部类)

(3)抽象方法用abstract来修饰

不可以被实例化,那怎么使用这个抽象类呢?

抽象类的使用方法

做一个类来继承这个抽象类,继承的时候把方法体实现了,如下:

//抽象方法只能放到抽象类里面,因此前面也要加abstract
abstract class Test1
{
    abstract void printInfo(); //在抽象类里面的方法,要么完善方法体,要么作为抽象方法
}                              //没有方法体的方法,该方法由子类来具体实现
                               //类似C语言中对函数的声明
                            
class Test2 extends Test1  //继承抽象类,从而使用抽象类
{
    @Override
    public void printInfo() {
        System.out.println("来自:test2");
    }
}

public class Demo1 {
    public static void main(String[] args){

        Test2 t2 = new Test2();
        t2.printInfo();
    }
}

抽象类的应用:模板方法模式

模板方法模式定义:

父类抽象(abstract)化定义一系列方法作为模板(不具体),把一些步骤推迟到子类去实现,子类将重写这些方法以提供具体行为。

之前做的智能家居可以运行在多个平台上,比如51,32,树莓派,现在就定义在每个平台上完成这个项目的通用模板,然后再在具体平台实现,以51为例子(当然这只是一个类比,java在51单片机上不能运行):

abstract class Control
{
    abstract void getCommand(); //是概括了在不同平台上完成智能家居项目的模板
    abstract void socketCommand(); //抽象化这些方法,在子类(类比于具体平台)
    abstract void lightControl();  //中再进行具体化
    abstract void cameraControl();

    public void work(){ //控制的基本流程
        getCommand();   //接收指令
        socketCommand(); //来自socket的指令
        lightControl();  //灯的控制
        cameraControl(); //相机的控制
    }
}

class C51platform extends Control //当这个地方出现红色波浪线的时候
{                                 //光标放上去,可以看到解决方法的快捷键
    @Override                     //把抽象方法重写,全部具体实现
    void getCommand() {
        System.out.println("getcommand in 51");
    }

    @Override
    void socketCommand() {
        System.out.println("socketcommand in 51");
    }

    @Override
    void lightControl() {
        System.out.println("lightcontrol in 51");
    }

    @Override
    void cameraControl() {
        System.out.println("cameracontrol in 51");
    }
}

public class Test {
    public static void main(String[] args) {
        C51platform c51 = new C51platform();  //实例化出一个对象
        c51.work(); //执行具体流程
    }
}

运行结果:

getcommand in 51
socketcommand in 51
lightcontrol in 51
cameracontrol in 51

接口

接口的概念

接口(Interface),在JAVA中是一个抽象类型,是抽象方法的集合(重点强调的是方法、是行为,而不是属性、特征)。

interface 接口名{
	//公有静态常量、抽象方法(抽象方法用的比较多)
} 

class 类名{

}

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法

接口与类的区别:————————

(1) 接口不能用于实例化对象

(2) 接口没有构造方法

而类是默认都有构造方法的(系统默认的参数为空的构造方法)

(3)接口中所有的方法必须是抽象方法

可以不指定修饰符,就默认为隐式抽象

(4)接口不能包含成员变量,除了 static 和 final 变量

接口中也一般不适用成员变量,以方法为主。

(5)接口不是被类继承了,而是要被类实现。而接口可以继承接口。

说法上的东西罢了,不用太纠结,具体看编程

接口的特点

接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。

就像下图,只要你不写修饰符,那就默认为隐式抽象为public abstract,可以编译通过。但凡你使用别的修饰符,马上报错。
在这里插入图片描述

接口的使用

一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法(包括接口继承过来的方法),否则就必须声明为抽象类。

继承是有亲属关系的,is的关系;而接口是双方都有的行为,比如人和狗都要吃东西。

下面的例子是以一些人和狗子都具有的行为作为接口,用Man类和Dog类具体实现:

interface Behavior  //接口,更注重方法
{
    void eat();   //在接口中,不写修饰符,默认为隐式抽象
    abstract void drink(); //当然写也无问题
}

class Man implements Behavior  //一个类实现了这个接口
{                              //从而来继承接口的抽象方法
    @Override
    public void eat() {
        System.out.println("人吃米");
    }

    @Override
    public void drink() {
        System.out.println("人喝饮料");
    }
}

class Dog implements Behavior //一个类实现了这个接口
{                             //从而继承接口的抽象方法

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

    @Override
    public void drink() {
        System.out.println("狗喝水");
    }
}

public class Test {

    public static void main(String[] args) {
        new Man().eat(); //new就是实例化一个对象,所以new Man()已经是一个对象了
        new Man().drink();
        new Dog().eat();
        new Dog().drink();
    }
}

接口实现与抽象类继承的区别

1)抽象类和具体实现之间是一个继承关系,也就是如果采用抽象类的方式,则父类和子类在概念上应该是相同的 ,是is -a的关系。

比如父类为老师,子类为语文老师,那么可以说语文老师是(is)一个(a)老师

(2)接口和实现类之间在概念上不要求相同,接口不去关注类之间的关系,它可以使没有层次关系的类具有相同的行为

抽象类是对一组具有相同属性和行为的逻辑上有关系的事物的一种抽象。
而接口则重点对一组具有相同行为的事物的一种抽象。

(3)抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。

(4)抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。(但接口强调行为,少用变量)

(5)接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。

(6)一个类只能继承一个抽象类,而一个类却可以实现多个接口

class People implements Survival,EnjoyLife //people这个类实现了多个接口

 
 
  • 1

其实到后面你可以发现,一个类实现多个接口接口的多继承再被类实现很像。

接口的多继承

在Java中,类的多继承是不合法,但接口允许多继承。

在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。 如下:(足球这一接口继承了其他接口)

public interface Sport extends Basketball, Football,Ping_pong

 
 
  • 1

继承过来后,类依旧要完成所有接口的抽象方法

举个简单的小例子:

interface Survival  //人关于生存的行为
{
    void eat();
    void drink();
}

interface EnjoyLife  //人享受生活的行为
{
    void seeMovie();
}

interface HowPeopleLive extends Survival,EnjoyLife //这个接口继承了上面两个接口
{
    void happy();
    /*void life(){ 接口中不允许有方法体

    }*/
    void life(); //只能在类的实现中赋予方法体
}

class People implements HowPeopleLive
{
    //当一个类实现接口时,就要把接口里所有的抽象方法实现,具体化
    @Override
    public void eat() {
        System.out.println("主要吃大米饭");
    }

    @Override
    public void drink() {
        System.out.println("主要喝白开水");
    }

    @Override
    public void seeMovie() {
        System.out.println("看电影感悟生活");
    }

    @Override
    public void happy() {
        System.out.println("你开心就好");
    }

    @Override
    public void life() {   //实现接口的方法体
        eat();
        drink();
        seeMovie();
        happy();
    }
}

public class Demo1 {
    public static void main(String[] args) {
        People man = new People();
        man.life();
    }
}

运行结果:

主要吃大米饭
主要喝白开水
看电影感悟生活
你开心就好

内部类

概念

所谓内部类(Inner Class),就是讲一个类定义在另一个类的内部,内部的类就称为内部类。

public class Outer{
	class Inner{
    
	}
}

内部类可以很好地实现隐藏,成员内部类属于外部类的实例成员,成员内部类可以有权限修饰符。

可以使用protected private修饰符内部类可以直接访问外部类的所有成员,包括私有的成员。

外部类不能直接访问内部类的成员,必须首先建立内部类的对象才能访问。

成员内部类(使用较多)及应用

创建成员内部类的实例

外部类名.内部类名 实例 = 外部类实例名.new 内部类构造方法(参数)

 
 
  • 1

下面以访问内部类的方法为例子:

class Outer
{
    int data;
    void printData(){
        System.out.println("外部类打印");
    }
    class Inner
    {
        int data;
        void innerPrint(){
            System.out.println("内部类打印");
        }
    }

}

public class Test {
    public static void main(String[] args) {
        Outer ou = new Outer();         //要使用内部类的方法,必须先实例化一个外部类的对象
        Outer.Inner in = ou.new Inner();//再通过这个外部类的对象实例化一个内部类的对象
        in.innerPrint();                //在进行访问方法即可
    }
}

在成员内部类中访问外部类的成员方法和属性

外部类名.this.成员方法
//或者
外部类名.this.成员属性

例如:

class Outer
{
    int data;
    void printData(){
        System.out.println("外部类打印");
    }
    class Inner
    {
        int data;
        void innerPrint(){
            System.out.println("内部类打印");
            Outer.this.printData();  //内部类对外部类方法的访问
            System.out.println("内部类访问外部类的属性:data="+Outer.this.data);//对属性的访问
        }
    }
}

外部类不能直接访问内部类的成员,必须先建立内部类的对象才能访问

(意义不大,用的较多的还是内部类访问外部类)

class Outer
{
    int data;
    void printData(){
        System.out.println("外部类打印");
    }
    //外部类不能直接访问内部类的成员,必须先建立内部类的对象才能访问
    void visitInner(){
        Inner in = new Inner();//先建立内部类的对象
        in.innerPrint();       //通过内部类的对象进行访问
    }

    class Inner
    {
        int data;
        void innerPrint(){
            System.out.println("内部类打印");

        }
    }
}

public class Test {
    public static void main(String[] args) {
        Outer ou = new Outer();         //要使用内部类的方法,必须先实例化一个外部类的对象
        Outer.Inner in = ou.new Inner();//再通过这个外部类的对象实例化一个内部类的对象
        ou.visitInner();                //外部类访问内部类打印
    }
}

成员内部类有以下限制

(1)成员内部类不能和外部类重名

(2)不能在成员内部类中定义static属性、方法、类。(static final形式的常量定义除外)

因为一个成员内部类实例必然与一个外部类实例关联,static成员完全可以移到其外部类中去。

匿名内部类

概念

匿名内部类是没有名称的内部类,没办法引用它们。必须在创建时,作为new语句的一部分来声明并创建它们的实例。

这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口,并同时创建该匿名类的一个新实例。

匿名内部类的创建与访问

匿名内部类必须继承一个类(抽象的,非抽象的都可以),或者实现一个接口,所有父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象方法。

语法:

new interface/superclass(){类体}

 
 
  • 1

例如:

(1)创建后立即访问

abstract class Demo1          //声明了一个抽象类
{
    abstract void printInfo();//声明了一个抽象方法
}

public class Test {
    public static void main(String[] args) {

        new Demo1(){//既初始化又要实现内部的方法 不是实例化 而是创建了匿名内部类并实例化匿名内部类
            void printInfo(){ //匿名内部类必须实现继承的类的所有方法
                System.out.println("这不是demo1,而是匿名内部类的方法");
            }
        }.printInfo();//new的返回值就是一个对象,所以可以直接通过“.”这样访问匿名内部类的方法
        
    }
}

运行结果:

这不是demo1,而是匿名内部类的方法

 
 
  • 1

(2)当然,也可以用“多态”进行访问(目前我也不知道多态是啥)

abstract class Demo1
{
    abstract void printInfo();
}

public class Test {
    public static void main(String[] args) {

        Demo1 d = new Demo1(){    //这感觉像是实例化了一个Demo1得到对象d,实际上得出的这个Demo1是抽象类的子类
            void printInfo(){    //匿名内部类必须实现继承的类的所有方法
                System.out.println("这不是demo1,而是匿名内部类的方法");
            }
        };

        d.printInfo();
    }
}

运行结果:

这不是demo1,而是匿名内部类的方法

 
 
  • 1

(3)匿名内部类实现一个接口

这种用法可能会在安卓的线程,按键响应做这样的事情。

interface Demo2 //接口
{
    abstract void interprint();
}

public class Test {
    public static void main(String[] args) {

        new Demo2(){
            public void interprint(){  //这里不使用public就报错了
                System.out.println("这不是接口的实例,而是匿名内部类的方法");
            }
        }.interprint();

    }
}

运行结果:

这不是接口的实例,而是匿名内部类的方法

 
 
  • 1
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
1关:继承及方法重写 继承是面向对象编程中的一种重要的概念,它允许我们创建一个新类,从现有的类中继承属性和方法。子类可以继承父类中的公共方法和属性,并且可以重写父类中的方法来实现自己的功能。 方法重写是指子类重写父类中已经存在的方法。子类可以根据自己的需要重新定义一个父类中的方法,使其具有不同的行为。在子类中重写方法时,方法名、参数列表、返回类型必须与父类中被重写的方法完全相同。 例如,我们创建一个父类Animal和一个子类Dog,子类Dog继承了父类Animal中的属性和方法,并且重写了其中的方法: ```java public class Animal { private String name; public Animal(String name) { this.name = name; } public void eat() { System.out.println(name + " is eating."); } } public class Dog extends Animal { public Dog(String name) { super(name); } @Override public void eat() { System.out.println("The dog is eating bones."); } } ``` 在上面的例子中,我们定义了一个Animal类,它有一个属性name和一个方法eat,然后我们创建了一个Dog类,它继承了Animal类,并且重写了eat方法。在Dog类中的eat方法中,我们打印出了一条狗在吃骨头的语句。 2关:抽象抽象类是一种特殊的类,它不能被实例化,只能被继承。抽象类中可以包含抽象方法和具体方法。抽象方法是一种没有实现的方法,它只有方法的声明,没有方法体,而具体方法则是有实现的方法。 抽象类通常用于定义一些抽象的概念,它可以被子类继承并实现。抽象类不能被实例化,只能被用作父类。 例如,我们可以定义一个抽象类Animal,其中包含一个抽象方法eat: ```java public abstract class Animal { private String name; public Animal(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract void eat(); } ``` 在上面的例子中,我们定义了一个抽象类Animal,其中包含了一个抽象方法eat,它没有方法体,只有方法的声明。这个抽象类不能被实例化,只能被继承。 3关:接口及实现类定义 接口是一种规范或者一种约定,它定义了一个类应该做什么,但并不规定类应该怎么做。接口中只包含方法的声明,没有方法的实现,它是一种纯粹的抽象概念。 实现类是实现接口的类,它们必须实现接口中的所有方法。实现类可以实现多个接口,这样就可以同时具有多种功能。 例如,我们可以定义一个接口Animal,其中包含一个方法eat: ```java public interface Animal { void eat(); } ``` 在上面的例子中,我们定义了一个Animal接口,其中只包含一个方法eat,没有方法的实现。这个接口可以被其他类实现。 然后我们可以创建一个实现类Dog,它实现了Animal接口: ```java public class Dog implements Animal { @Override public void eat() { System.out.println("The dog is eating bones."); } } ``` 在上面的例子中,我们创建了一个实现类Dog,它实现了Animal接口中的eat方法,并且实现了自己的功能,即打印出一条狗在吃骨头的语句。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

行稳方能走远

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值