【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?

 这篇文章我们主要学习的是两个知识点,可以来解决文章标题所提出来的三个问题。

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第1张图片

 

目录

1.抽象类

1.1 抽象类概念

1.2 抽象类语法

1.3 抽象类特性

1.4 抽象类的作用

2.内部类

2.1 内部类的分类

2.2 实例内部类

2.3 静态内部类

2.4 匿名内部类

2.5 局部内部类


1.抽象类

在多态的学习中,我们曾写过这样的一段代码:

class Shape {
    //属性....
    public void draw() {
        System.out.println("画图形!");
    }
}
class Rect extends Shape {
    @Override
    public void draw() {
        System.out.println("♦");
    }
}
class Cycle extends Shape {
    @Override
    public void draw() {
        System.out.println("●");
    }
}
class Triangle extends Shape {
    @Override
    public void draw() {
        System.out.println("▲");
    }
}

但是,我们会发现,在父类Shape中的draw()方法似乎不曾被使用过,我们可不可以不写draw()的实现部分呢?答案是可以的,抽象类将回来帮我们解决这个问题。


1.1 抽象类概念

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果 一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。 比如:

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第2张图片

说明:

  1. 矩形、三角形、圆形都是图形,因此和Shape类的特性应该是继承关系。
  2. 虽然图形图Shape中也存在draw的方法,但由于Shape类并不是具体的图形,因此其内部的draw方法实际是没有办法实现的。
  3. 由于Shape类没有办法描述一个具体的图形,导致其draw0方法无法具体实现,因此可以将Shape类设计为“抽象类"。

在打印图形例子中, 我们发现, 父类 Shape 中的 draw 方法好像并没有什么实际工作, 主要的绘制图形都是由 Shape 的各种子类的 draw 方法来完成的. 像这种没有实际工作的方法, 我们可以把它设计成一个抽象方法(abstract method), 包含抽象方法的类我们称为抽象类(abstract class)

1.2 抽象类语法

Java中,一个类如果被 abstract 修饰称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体。

对于上面的shape类,我们可以做出如下修改:

abstract class Shape {
    //属性....
    public abstract void draw();
}

这样,shape就是一个抽象类。

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第3张图片

// 抽象类:被abstract修饰的类
abstract class Shape {
    // 抽象方法:被abstract修饰的方法,没有方法体
    abstract public void draw();
    abstract void calcArea();
    // 抽象类也是类,也可以增加普通方法和属性
    public double getArea() {
        return area;
    }
    protected double area; // 面积
}

 注意:抽象类也是类,内部可以包含普通方法和属性,甚至构造方法

1.3 抽象类特性

1. 抽象类不能直接实例化对象

2. 抽象方法不能是 private

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第4张图片

3. 抽象方法不能被finalstatic修饰,因为抽象方法要被子类重写

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第5张图片

4. 抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰

5. 抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类

6. 抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第6张图片

1.4 抽象类的作用

抽象类本身不能被实例化, 要想使用, 只能创建该抽象类的子类,然后让子类重写抽象类中的抽象方法。

我们可能会想, 普通的类也可以被继承呀, 普通的方法也可以被重写呀, 为啥非得用抽象类和抽象方法呢?

确实如此. 但是使用抽象类相当于多了一重编译器的校验。

使用抽象类的场景就如上面的代码, 实际工作不应该由父类完成, 而应由子类完成.。那么此时如果不小心误用成父类 了, 使用普通类编译器是不会报错的.。但是父类是抽象类就会在实例化的时候提示错误, 让我们尽早发现问题。

很多语法存在的意义都是为了 "预防出错", 例如我们曾经用过的 final 也是类似. 创建的变量用户不去修改, 不 就相当于常量嘛? 但是加上 final 能够在不小心误修改的时候, 让编译器及时提醒我们。充分利用编译器的校验, 在实际开发中是非常有意义的。

2.内部类

当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服 务,那么这个内部的完整结构最好使用内部类。在 Java 中,可以将一个类定义在另一个类或者一个方法的内部, 前者称为内部类,后者称为外部类。内部类也是封装的一种体现。

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第7张图片【注意事项】

1. 定义在class 类名{}花括号外部的,即使是在一个文件里,都不能称为内部类

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第8张图片

 2. 内部类和外部类共用同一个java源文件,但是经过编译之后,内部类会形成单独的字节码文件

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第9张图片

2.1 内部类的分类

先来看下,内部类都可以在一个类的哪些位置进行定义

class OutClass {
    // 成员位置定义:未被static修饰 --->实例内部类
    public class InnerClass1 {
    }

    // 成员位置定义:被static修饰 ---> 静态内部类
    static class InnerClass2 {
    }

    public void method() {
        // 方法中也可以定义内部类 ---> 局部内部类:几乎不用
        class InnerClass5 {
        }
    }
}

 根据内部类定义的位置不同,一般可以分为以下几种形式:

  1. 成员内部类(普通内部类:未被static修饰的成员内部类 和 静态内部类:被static修饰的成员内部类)
  2. 局部内部类(不谈修饰符)、匿名内部类

注意:内部类其实日常开发中使用并不是非常多,大家在看一些库中的代码时候可能会遇到的比较多,日常开始中使用最多的是匿名内部类。

2.2 实例内部类

即未被static修饰的成员内部类。

实例内部类成员变量的定义:

在实例内部类中,不能定义static修饰的成员变量,除非加final修饰:

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第10张图片

创建实例内部类对象时,先将外部类对象先创建出来,然后再创建实例内部类对象:

在实例内部类中可以直接访问外部类中:任意访问限定符修饰的成员

如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的

如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字

class OuterClass {
    public int data1 = 1;
    public static int data2 = 2;
    private int data3 = 3;

    class InnerClass {
        public int data1 = 111;

        private int data4 = 4;
        public static final int data5 = 5;  //data5为常量
        protected int data6 = 6;

        public void test() {
            System.out.println("InnerClass::test()");
            System.out.println(data1);//优先访问的是内部类自己的data1
            System.out.println(OuterClass.this.data1); //访问外部类的data1
            System.out.println(data2);
            System.out.println(data3);
            System.out.println(data4);
            System.out.println(data5);
            System.out.println(data6);
        }
    }

    public void test() {
        System.out.println("OuterClass::test()");
        System.out.println(data1); //访问外部类成员变量
        System.out.println(data2);
        System.out.println(data3);
        //外部类方法访问内部类需要先创建内部类对象来访问
        InnerClass innerClass = new InnerClass();
        System.out.println(innerClass.data1);
        System.out.println(innerClass.data4);
        System.out.println(innerClass.data6);
    }
}

public class Test3 {
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        OuterClass.InnerClass innerClass = outerClass.new InnerClass();
        innerClass.test();
        outerClass.test();
    }
}

输出结果:

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第11张图片

 【注意事项】

1. 外部类中的任何成员都可以在实例内部类方法中直接访问。

2. 实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的        约束。

3. 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成          员,必须:外部类名称.this.同名成员 来访问。

4. 实例内部类对象必须在先有外部类对象前提下才能创建。

5. 实例内部类的非静态方法中包含了一个指向外部类对象的引用。

6. 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。

2.3 静态内部类

static修饰的内部成员类称为静态内部类。

创建静态内部类对象不需要先创建外部类对象:

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第12张图片

静态内部类不能直接访问外部类非静态成员变量:

class OuterClass {
    public int data1 = 1;
    public static int data2 = 2;
    private int data3 = 3;

    public static class InnerClass {
        public int data4 = 4;
        public static int data5 = 5;
        private int data6 = 6;
        void test() {
            System.out.println("InnerClass::test()");
            OuterClass outerClass = new OuterClass();
            //System.out.println(data1); //编译报错
            System.out.println(outerClass.data1);
            System.out.println(data2);
            //System.out.println(data3); //编译报错
            System.out.println(outerClass.data3);            
            System.out.println(data5);
            System.out.println(data6);
        }
    }
}

【注意事项】

1. 在静态内部类中只能访问外部类中的静态成员

2. 创建静态内部类对象时,不需要先创建外部类对象

2.4 匿名内部类

学过接口的大家都知道,接口是不能实例化出对象的:

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第13张图片

 但是我们可以通过接口创建出匿名内部类对象:

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第14张图片

 输出结果:

2.5 局部内部类

定义在外部类的方法体或者{}中,该种内部类只能在其定义的位置使用,一般使用的非常少,此处简单了解下语法格式。

public class Test3 {
    public static void func() {
        class AA {
            public int a = 1;
        }

        AA aa = new AA();
        System.out.println(aa.a);
    }

    public static void main(String[] args) {
        func();
    }
}

 

【注意事项】

1. 局部内部类只能在所定义的方法体内部使用

2. 不能被public、static等修饰符修饰

3. 编译器也有自己独立的字节码文件,命名格式:外部类名字$数字内部类名字.class

4. 几乎不会使用

【JavaSE】什么是抽象类?什么是内部类?以及它们的作用是什么?_第15张图片

你可能感兴趣的:(JavaSE,java,开发语言,ide,学习方法,intellij-idea)