目录

Java 抽象类

抽象类

抽象方法

抽象方法的定义

抽象方法的特征:

抽象类总结规定

Java 接口

接口与类的区别:

抽象类和接口的区别

接口的声明

定义接口

实现接口

Java 封装 

封装的优点

封装的实现:

实现Java封装的步骤


Java 抽象类

抽象类

java语言提供了两种类,分别为具体类和抽象类。前面学习接触的类都是具体类。这一节介绍一下抽象类。

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

//在 Java 中抽象类的语法格式如下: 

<abstract>class<class_name> {
    <abstract><type><method_name>(parameter-iist);
}

其中,abstract 表示该类或该方法是抽象的;class_name 表示抽象类的名称;method_name 表示抽象方法名称,parameter-list 表示方法参数列表。

如果一个方法使用 abstract 来修饰,则说明该方法是抽象方法,抽象方法只有声明没有实现。需要注意的是 abstract 关键字只能用于普通方法,不能用于 static 方法或者构造方法中。

抽象方法的 3 个特征如下:

  1. 抽象方法没有方法体
  2. 抽象方法必须存在于抽象类中
  3. 子类重写父类时,必须重写父类所有的抽象方法


注意:在使用 abstract 关键字修饰抽象方法时不能使用 private 修饰,因为抽象方法必须被子类重写,而如果使用了 private 声明,则子类是无法重写的。

抽象类的定义和使用规则如下:

  1. 抽象类和抽象方法都要使用 abstract 关键字声明。
  2. 如果一个方法被声明为抽象的,那么这个类也必须声明为抽象的。而一个抽象类中,可以有 0~n 个抽象方法,以及 0~n 个具体方法。
  3. 抽象类不能实例化,也就是不能使用 new 关键字创建对象。

抽象方法

Java 抽象方法,没有主体的方法(没有实现)被称为抽象方法。方法必须始终在抽象类中声明,或者换句话说,如果类具有抽象方法,则应该将其声明为抽象方法。

抽象方法的定义

Java中普通方法的定义方式是:

访问权限 返回类型 方法名(有参数填写参数,没参数为空){

方法内部代码;

}

因为抽象方法我们无法给出具体的实现,所以抽象方法的定义与普通方法有所不同。定义方式如下:

访问权限 abstract 返回类型 方法名(有参数填写参数,没参数为空);

 注意:因为不知如何实现,所以没有大括号了。

抽象方法的特征:

1.抽象方法不允许有方法体,只能以分号“;”结尾

2.有抽象方法的类只能定义成抽象类(含有抽象方法的类必须是抽象类)

3.抽象类中可以包含 0 个或多个抽象方法

4.抽象方法必须被子类实现

5.如果子类不能实现父类中的抽象方法,那么子类也必须是抽象类

举个例子:

不同几何图形的面积计算公式是不同的,但是它们具有的特性是相同的,都具有长和宽这两个属性,也都具有面积计算的方法。那么可以定义一个抽象类,在该抽象类中含有两个属性(width 和 height)和一个抽象方法 area( ),具体步骤如下。

1.首先创建一个表示图形的抽象类 Shap

    public abstract class Shape {
        public int width; // 几何图形的长
        public int height; // 几何图形的宽
        public Shape(int width, int height) {
            this.width = width;
            this.height = height;
        }
        public abstract double area(); // 定义抽象方法,计算面积
    }

2.定义一个正方形类,该类继承自形状类 Shape,并重写了 area( ) 抽象方法。正方形类的代码如下:

    public class Square extends Shape {
        public Square(int width, int height) {
            super(width, height);
        }
        // 重写父类中的抽象方法,实现计算正方形面积的功能
        @Override
        public double area() {
            return width * height;
        }
    }

3.定义一个三角形类,该类与正方形类一样,需要继承形状类 Shape,并重写父类中的抽象方法 area()。三角形类的代码实现如下:

    public class Triangle extends Shape {
        public Triangle(int width, int height) {
            super(width, height);
        }
        // 重写父类中的抽象方法,实现计算三角形面积的功能
        @Override
        public double area() {
            return 0.5 * width * height;
        }
    }

4.最后创建一个测试类,分别创建正方形类和三角形类的对象,并调用各类中的 area() 方法,打印出不同形状的几何图形的面积。测试类的代码如下:

    public class ShapeTest {
        public static void main(String[] args) {
            Square square = new Square(5, 4); // 创建正方形类对象
            System.out.println("正方形的面积为:" + square.area());
            Triangle triangle = new Triangle(2, 5); // 创建三角形类对象
            System.out.println("三角形的面积为:" + triangle.area());
        }
    }

在该程序中,创建了 4 个类,分别为图形类 Shape、正方形类 Square、三角形类 Triangle 和测试类 ShapeTest。其中图形类 Shape 是一个抽象类,创建了两个属性,分别为图形的长度和宽度,并通过构造方法 Shape( ) 给这两个属性赋值。

在 Shape 类的最后定义了一个抽象方法 area( ),用来计算图形的面积。在这里,Shape 类只是定义了计算图形面积的方法,而对于如何计算并没有任何限制。也可以这样理解,抽象类 Shape 仅定义了子类的一般形式。

正方形类 Square 继承抽象类 Shape,并实现了抽象方法 area( )。三角形类 Triangle 的实现和正方形类相同,这里不再介绍。

在测试类 ShapeTest 的 main( ) 方法中,首先创建了正方形类和三角形类的实例化对象 square 和 triangle,然后分别调用 area( ) 方法实现了面积的计算功能。

5.运行该程序,输出的结果如下:

正方形的面积为:20.0
三角形的面积为:5.0

抽象类总结规定

  • 1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。

  • 2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

  • 3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。

  • 4. 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。

  • 5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。


Java 接口

在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)。接口是Java中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成。

接口与类的区别:

  • 接口不能用于实例化对象。
  • 接口没有构造方法。
  • 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。
  • 接口不能包含成员变量,除了 static 和 final 变量。
  • 接口不是被类继承了,而是要被类实现。
  • 接口支持多继承。

抽象类和接口的区别

  • 1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  • 2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  • 3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  • 4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

接口的声明

接口的声明语法格式如下:


[可见度] interface 接口名称 [extends 其他的接口名] {
        // 声明变量
        // 抽象方法
}

 Interface关键字用来声明一个接口。下面是接口声明的一个简单例子

import java.lang.*;
//引入包
 
public interface NameOfInterface
{
   //任何类型 final, static 字段
   //抽象方法
}

接口有以下特性:

  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
  • 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
  • 接口中的方法都是公有的。

定义接口

Java 接口的定义方式与类基本相同,不过接口定义使用的关键字是 interface,接口定义的语法格式如下:

    [public] interface interface_name [extends interface1_name[, interface2_name,…]] {
        // 接口体,其中可以包含定义常量和声明方法
        [public] [static] [final] type constant_name = value;    // 定义常量
        [public] [abstract] returnType method_name(parameter_list);    // 声明方法
    }

对以上语法的说明如下:

  • public 表示接口的修饰符,当没有修饰符时,则使用默认的修饰符,此时该接口的访问权限仅局限于所属的包;
  • interface_name 表示接口的名称。接口名应与类名采用相同的命名规则,即如果仅从语法角度来看,接口名只要是合法的标识符即可。如果要遵守 Java 可读性规范,则接口名应由多个有意义的单词连缀而成,每个单词首字母大写,单词与单词之间无需任何分隔符。
  • extends 表示接口的继承关系;
  • interface1_name 表示要继承的接口名称;
  • constant_name 表示变量名称,一般是 static 和 final 型的;
  • returnType 表示方法的返回值类型;
  • parameter_list 表示参数列表,在接口中的方法是没有方法体的。

注意:一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。

接口对于其声明、变量和方法都做了许多限制,这些限制作为接口的特征归纳如下:

  • 具有 public 访问控制符的接口,允许任何类使用;没有指定 public 的接口,其访问将局限于所属的包。
  • 方法的声明不需要其他修饰符,在接口中声明的方法,将隐式地声明为公有的(public)和抽象的(abstract)。
  • 在 Java 接口中声明的变量其实都是常量,接口中的变量声明,将隐式地声明为 public、static 和 final,即常量,所以接口中定义的变量必须初始化。
  • 接口没有构造方法,不能被实例化。例如:
    public interface A {
        publicA(){…}    // 编译出错,接口不允许定义构造方法
    }

一个接口不能够实现另一个接口,但它可以继承多个其他接口。子接口可以对父接口的方法和常量进行重写。例如:

    public interface StudentInterface extends PeopleInterface {
        // 接口 StudentInterface 继承 PeopleInterface
        int age = 25;    // 常量age重写父接口中的age常量
        void getInfo();    // 方法getInfo()重写父接口中的getInfo()方法
    }

例如,定义一个接口 MyInterface,并在该接口中声明常量和方法,如下:

    public interface MyInterface {    // 接口myInterface
        String name;    // 不合法,变量name必须初始化
        int age = 20;    // 合法,等同于 public static final int age = 20;
        void getInfo();    // 方法声明,等同于 public abstract void getInfo();
    }

实现接口

接口的主要用途就是被实现类实现,一个类可以实现一个或多个接口,继承使用 extends 关键字,实现则使用 implements 关键字。因为一个类可以实现多个接口,这也是 Java 为单继承灵活性不足所作的补充。类实现接口的语法格式如下:

<public> class <class_name> [extends superclass_name] [implements interface1_name[, interface2_name…]] {
    // 主体
}

对以上语法的说明如下:

  • public:类的修饰符;
  • superclass_name:需要继承的父类名称;
  • interface1_name:要实现的接口名称。

实现接口需要注意以下几点:

  • 实现接口与继承父类相似,一样可以获得所实现接口里定义的常量和方法。如果一个类需要实现多个接口,则多个接口之间以逗号分隔。
  • 一个类可以继承一个父类,并同时实现多个接口,implements 部分必须放在 extends 部分之后。
  • 一个类实现了一个或多个接口之后,这个类必须完全实现这些接口里所定义的全部抽象方法(也就是重写这些抽象方法);否则,该类将保留从父接口那里继承到的抽象方法,该类也必须定义成抽象类。

举个例子:

在程序的开发中,需要完成两个数的求和运算和比较运算功能的类非常多。那么可以定义一个接口来将类似的功能组织在一起。下面创建一个示例,具体介绍接口的实现方式。


1.创建一个名称为 IMath 的接口,代码如下:

    public interface IMath {
        public int sum();    // 完成两个数的相加
        public int maxNum(int a,int b);    // 获取较大的数
    }

2.定义一个 MathClass 类并实现 IMath 接口,MathClass 类实现代码如下:

    public class MathClass implements IMath {
        private int num1;    // 第 1 个操作数
        private int num2;    // 第 2 个操作数
        public MathClass(int num1,int num2) {
            // 构造方法
            this.num1 = num1;
            this.num2 = num2;
        }
        // 实现接口中的求和方法
        public int sum() {
            return num1 + num2;
        }
        // 实现接口中的获取较大数的方法
        public int maxNum(int a,int b) {
            if(a >= b) {
                return a;
            } else {
                return b;
            }
        }
    }

在实现类中,所有的方法都使用了 public 访问修饰符声明。无论何时实现一个由接口定义的方法,它都必须实现为 public,因为接口中的所有成员都显式声明为 public。

3.最后创建测试类 NumTest,实例化接口的实现类 MathClass,调用该类中的方法并输出结果。该类内容如下:

    public class NumTest {
        public static void main(String[] args) {
            // 创建实现类的对象
            MathClass calc = new MathClass(100, 300);
            System.out.println("100 和 300 相加结果是:" + calc.sum());
            System.out.println("100 比较 300,哪个大:" + calc.maxNum(100, 300));
        }
    }


//运行结果:
100 和 300 相加结果是:400
100 比较 300,哪个大:300

在该程序中,首先定义了一个 IMath 的接口,在该接口中只声明了两个未实现的方法,这两个方法需要在接口的实现类中实现。在实现类 MathClass 中定义了两个私有的属性,并赋予两个属性初始值,同时创建了该类的构造方法。因为该类实现了 MathClass 接口,因此必须实现接口中的方法。在最后的测试类中,需要创建实现类对象,然后通过实现类对象调用实现类中的方法。


Java 封装 

封装是四个基本OOP概念之一。 其他三个分别是:继承,多态和抽象。

Java中的封装是将数据(变量)和作用于数据(方法)的代码作为一个单元包装在一起的机制。 在封装中,类的变量将从其他类隐藏,并且只能通过当前类的方法访问。 因此,它也被称为数据隐藏。

封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式

这是什么意思呢?

简单的来说就是我将不想给别人看的数据,以及别人无需知道的内部细节, “锁起来” ,我们只留下一些入口,使其与外部发生联系。

封装的优点

  • 1. 良好的封装能够减少耦合。

  • 2. 类内部的结构可以自由修改。

  • 3. 可以对成员变量进行更精确的控制。

  • 4. 隐藏信息,实现细节。

封装的实现:

  Java是使用“访问控制符”来控制哪些细节需要封装,哪些细节需要暴露的。 Java中4种“访问控制符”分别为private、default、protected、public,它们说明了面向对象的封装性,所以我们要利用它们尽可能的让访问权限降到最低,从而提高安全性。

下面说明它们的访问权限问题。其访问权限范围如下表所示:

 

      1. private 表示私有,只有自己类能访问

      2. default表示没有修饰符修饰,只有同一个包的类能访问

      3. protected表示可以被同一个包的类以及其他包中的子类访问

      4. public表示可以被该项目的所有包中的所有类访问

实现Java封装的步骤

  • 将类的变量声明为private
  • 提供公共settergetter方法来修改和获取变量的值。

1. 修改属性的可见性来限制对属性的访问(一般限制为private),例如:

public class Person {
    private String name;
    private int age;
}

这段代码中,将 nameage 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。

2. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:

public class Person{
    private String name;
    private int age;
​
    public int getAge(){
      return age;
    }
​
    public String getName(){
      return name;
    }
​
    public void setAge(int age){
      this.age = age;
    }
​
    public void setName(String name){
      this.name = name;
    }
}

采用 this 关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。

举个例子:

public class EncapTest{
 
   private String name;
   private String idNum;
   private int age;
 
   public int getAge(){
      return age;
   }
 
   public String getName(){
      return name;
   }
 
   public String getIdNum(){
      return idNum;
   }
 
   public void setAge( int newAge){
      age = newAge;
   }
 
   public void setName(String newName){
      name = newName;
   }
 
   public void setIdNum( String newId){
      idNum = newId;
   }
}

以上实例中public方法是外部类访问该类成员变量的入口。

通常情况下,这些方法被称为gettersetter方法。

因此,任何要访问类中私有成员变量的类都要通过这些gettersetter方法。

通过如下的例子说明EncapTest类的变量怎样被访问:

public class RunEncap{
   public static void main(String args[]){
      EncapTest encap = new EncapTest();
      encap.setName("James");
      encap.setAge(20);
      encap.setIdNum("12343ms");
 
      System.out.print("Name : " + encap.getName()+ 
                             " Age : "+ encap.getAge());
    }
}


//运行结果:
Name : James Age : 20

          上篇整理Java概述,Java语言的特点,Java语言基础,Java数据类型和Java的运算符。

Java基础知识总结(详细整理)——上篇https://blog.csdn/m0_73487068/article/details/126596598

            中篇整理Java流程控制语句,java数组,方法和对象与类

Java基础知识总结(详细整理)——中篇https://blog.csdn/m0_73487068/article/details/126620760

            下篇整理Java的继承,重写与重载和Java多态

Java基础知识总结(详细整理)——下篇https://blog.csdn/m0_73487068/article/details/126637338

           完结篇整理Java的抽象,封装和接口

Java基础知识总结(详细整理)——完结篇https://blog.csdn/m0_73487068/article/details/126655427


更多推荐

Java基础知识总结(详细整理)——完结篇