重拾Java基础 2021-12-05

今天开始复习Java面向对象那一块,之前其中可能有零零散散的点落下,之后再补充吧!本来也是为了过一下基础知识。

Java面向对象

面向对象编程简称 OOP(Object Oriented Programing),20 世纪 80 年代以后,有了面向对象分析(OOA)、 面向对象设计(OOD)、面向对象程序设计(OOP)等新的系统开发方式模型的研究。

对 Java语言来说,一切皆是对象。把现实世界中的对象抽象地体现在编程世界中,一个对象代表了某个具体的操作。一个个对象最终组成了完整的程序设计,这些对象可以是独立存在的,也可以是从别的对象继承过来的。对象之间通过相互作用传递信息,实现程序开发。

面向对象的三大核心特性

封装 、继承、多态

封装

在面向对象程式设计方法中,封装是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装还可以理解为,编写常用的一些函数,常常多次调用,这样我们可以把代码封装起来,之后直接调用传参,而不用去修改源代码,提高了代码的复用性。

封装的优点

  1. 良好的封装能够减少耦合。
  2. 类内部的结构可以自由修改。
  3. 可以对成员变量进行更精确的控制。
  4. 隐藏信息,实现细节。

实现Java封装的步骤

  1. 修改属性的可见性来限制对属性的访问(一般限制为private)
public class Person {
    private String name;
    private int age;
}

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

  1. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:
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;
    }
}
public class Demo {
    public static void main(String[] args) {
    Person p = new Person();
    p.setName("张三");
    System.out.println(p.getName());
    }
}

我们看不到里面实际的代码,只是这个对象对外 提供了公共访问的权限,我们可以操作里面的get 和set方法来获取和设置里面的成员变量。
通常情况下,这些方法被称为getter和setter方法。
因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。

封装方法

public class Person {
    // 成员变量  类中的所有方法都可以使用
    private String p_name;
    // 成员变量
    private String p_age;
    // 这是类变量,也叫静态变量,private是私有的
    private static String p_addr = "北京市";

    // 自定义函数
    public  void printName(String name,String age){
        // 静态变量属于类,直接用类.变量名 调用  Person.p_addr
        System.out.println("姓名:" + name + " 年龄:" + age + "   地址:" + Person.p_addr);
    }

    public  void eat(){
        // 局部变量,方法执行完,生命周期结束,会被回收
        String str = "外卖到了";
        System.out.println(str + "开始吃饭");

    }

    public  void run(){
        System.out.println("睡觉之前去跑几公里");
    }

    public  void sleep(){
        System.out.println("跑步回来,洗完澡,开始睡觉");
    }

    public int chengfa(int a,int b){
        return a * b;
    }


    public String getP_name() {
        return p_name;
    }

    public void setP_name(String p_name) {
        this.p_name = p_name;
    }

    public String getP_age() {
        return p_age;
    }

    public void setP_age(String p_age) {
        this.p_age = p_age;
    }

    public static String getP_addr() {
        return p_addr;
    }

    public static void setP_addr(String p_addr) {
        Person.p_addr = p_addr;
    }
}
public class Demo {

    public static void main(String[] args) {

        Person p = new Person();
        p.setP_name("这是类中名字属性");
        // 对象调用获取名字信息
        String p_name = p.getP_name();
        System.out.println(p_name);
       int num =  p.chengfa(3,4);
        System.out.println(num);

    }
}
这是类中名字属性
12

Java 继承

继承的概念:
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

继承.jpg

兔子和羊属于食草动物类,狮子和豹属于食肉动物类。
食草动物和食肉动物又是属于动物类。
所以继承需要符合的关系是:is-a,父类更通用,子类更具体。
虽然食草动物和食肉动物都是属于动物,但是两者的属性和行为上有差别,所以子类会具有父类的一般特性也会具有自身的特性。

类的继承关键字 extends

class 父类 {
}
 
class 子类 extends 父类 {
}

为什么需要继承?

就拿动物来说,食草动物、食肉动物都属于动物,那动物都有相同行为,跑、吃、叫等,如果每个类中都去写相同的方法,那么代码的工作量就会臃肿,如果把父类的方法继承过来,是不是就很方便了。减少了代码的量,还易于维护。

public class Animal {

     int id;

     String name;

    public Animal(int id){
        this.id = id;
    }

    public Animal(int id,String name){
        this.id = id;
        this.name = name;
    }

    public Animal(){

    }




    public void eat(){
        System.out.println(name+"正在吃");
    }
    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() {
        System.out.println("大家好!我是"         + id + "号" + name + ".");
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

public class Rabbit extends Animal {

     String color;

    // 空参的构造器
    public  Rabbit(){

    }

    // 带参的构造器
    public  Rabbit(String name,int id,String color){
        this.name = name;
        this.id = id;
        this.color = color;

    }


    public void run(String name){
        System.out.println(name + "在草地上跑");
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int getId() {
        return id;
    }

    @Override
    public void setId(int id) {
        this.id = id;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

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

        Animal animal = new Animal();
        animal.setId(1001);
        animal.setName("动物");
        animal.eat();

        Rabbit rabbit = new Rabbit();
        rabbit.setId(10010);
        rabbit.setColor("白");
        rabbit.setName("小" + rabbit.getColor() + "兔");
        rabbit.run(rabbit.getName());
        rabbit.eat();
        rabbit.sleep();


    }
}
动物正在吃
小白兔在草地上跑
小白兔正在吃
小白兔正在睡

从上边的代码和执行可以看出,子类可以继承父类的属性和方法,父类中有的子类可以继承过来,子类可以写自己锁拥有的方法和属性,执行的时候结果都是一样的,这样就避免了子类中重复的去写相同的属性和方法。

注:虽然子类可以继承父类的属性和方法,但是父类私有的虽然可以继承过来,但是不能直接访问,属性需要使用get或set方法,方法需要类中其他的方法调用仍然可以。

public class Car {

    private String name;
    String color;

    public Car(){

    }

    public Car(String name){
        this.name = name;
    }

    public Car(String name,String color){
        this.name = name;
        this.color = color;
    }



    public void runCar(){
        System.out.println("驾驶车辆" + name);
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

public class CarBwm extends Car{

    public CarBwm() {

    }

    public CarBwm(String name) {
        this.name = name;
    }

    public CarBwm(String name, String color) {
        super(name, color);
    }

    public void startCar(String name){
        System.out.println("启动" + name);
    }
}

public class CarMain {

    public static void main(String[] args) {
        Car car = new Car();
        car.setName("车的父类");
        car.setColor("炫酷色");
        car.runCar();

        CarBwm carBwm = new CarBwm();
        carBwm.setName("宝马X*");
        carBwm.setColor("白色");
        carBwm.runCar();
        carBwm.startCar(carBwm.getName());
        System.out.println(carBwm.getColor());
    }
}
驾驶车辆车的父类
驾驶车辆宝马X*
启动null
白色

上述的执行结果可以看出,private的name虽然继承过来了,但是我们无法直接访问,返回的null,所以父类私有的子类是不能直接访问的。
如下:

public class Car {

    private String name;
    String color;

    public Car(){

    }

    public Car(String name){
        this.name = name;
    }

    public Car(String name,String color){
        this.name = name;
        this.color = color;
    }

    public void runCar(){
        System.out.println("驾驶车辆" + name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }
}

public class CarBwm extends Car{

    public CarBwm() {

    }


    public void startCar(){
        System.out.println("启动 " +color  + getName());
    }

public class CarMain {

    public static void main(String[] args) {
        Car car = new Car("车的父类","炫酷色");
        car.runCar();

        CarBwm carBwm = new CarBwm();
        carBwm.setName("宝马X*");
        carBwm.setColor("白色");
        carBwm.runCar();
        carBwm.startCar();
    }
}
}
驾驶车辆车的父类
驾驶车辆宝马X*
启动 白色宝马X*

Java 多态

多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:


多态.png

多态性是对象多种表现形式的体现。

现实中,比如我们按下 F1 键这个动作:
如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
如果当前在 Word 下弹出的就是 Word 帮助;
在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。

多态存在的三个必要条件

继承
重写
父类引用指向子类对象:Parent p = new Child();


多态三个条件.jpg

多态的优点

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性
class Shape {
    void draw() {}
}
 
class Circle extends Shape {
    void draw() {
        System.out.println("Circle.draw()");
    }
}
 
class Square extends Shape {
    void draw() {
        System.out.println("Square.draw()");
    }
}
 
class Triangle extends Shape {
    void draw() {
        System.out.println("Triangle.draw()");
    }
}

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

重写

就是子类能够重写父类的方法。
当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。
要想调用父类中被重写的方法,则必须使用关键字 super。

public class Employee {
   private String name;
   private String address;
   private int number;
   public Employee(String name, String address, int number) {
      System.out.println("Employee 构造函数");
      this.name = name;
      this.address = address;
      this.number = number;
   }
   public void mailCheck() {
      System.out.println("邮寄支票给: " + this.name
       + " " + this.address);
   }
   public String toString() {
      return name + " " + address + " " + number;
   }
   public String getName() {
      return name;
   }
   public String getAddress() {
      return address;
   }
   public void setAddress(String newAddress) {
      address = newAddress;
   }
   public int getNumber() {
     return number;
   }
}

public class Salary extends Employee
{
   private double salary; // 全年工资
   public Salary(String name, String address, int number, double salary) {
       super(name, address, number);
       setSalary(salary);
   }
   public void mailCheck() {
       System.out.println("Salary 类的 mailCheck 方法 ");
       System.out.println("邮寄支票给:" + getName()
       + " ,工资为:" + salary);
   }
   public double getSalary() {
       return salary;
   }
   public void setSalary(double newSalary) {
       if(newSalary >= 0.0) {
          salary = newSalary;
       }
   }
   public double computePay() {
      System.out.println("计算工资,付给:" + getName());
      return salary/52;
   }
}

public class VirtualDemo {
   public static void main(String [] args) {
      Salary s = new Salary("员工 A", "北京", 3, 3600.00);
      Employee e = new Salary("员工 B", "上海", 2, 2400.00);
      System.out.println("使用 Salary 的引用调用 mailCheck -- ");
      s.mailCheck();
      System.out.println("\n使用 Employee 的引用调用 mailCheck--");
      e.mailCheck();
    }
}
Employee 构造函数
Employee 构造函数
使用 Salary 的引用调用 mailCheck -- 
Salary 类的 mailCheck 方法 
邮寄支票给:员工 A ,工资为:3600.0

使用 Employee 的引用调用 mailCheck--
Salary 类的 mailCheck 方法 
邮寄支票给:员工 B ,工资为:2400.0

Java 重写(Override)与重载(Overload)

重写(Override)

重写(Override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。
例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,抛出 IOException 异常或者 IOException 的子类异常。

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      System.out.println("狗可以跑和走");
   }
}
 
public class TestDog{
   public static void main(String args[]){
      Animal a = new Animal(); // Animal 对象
      Animal b = new Dog(); // Dog 对象
 
      a.move();// 执行 Animal 类的方法
 
      b.move();//执行 Dog 类的方法
   }
}
动物可以移动
狗可以跑和走

方法的重写规则

参数列表与被重写方法的参数列表必须完全相同。
返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
父类的成员方法只能被它的子类重写。
声明为 final 的方法不能被重写。
声明为 static 的方法不能被重写,但是能够被再次声明。
子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
构造方法不能被重写。
如果不能继承一个类,则不能重写该类的方法。

public class Person {

    private String name;
    private int age;
    private String sex;


    public void info(){
        System.out.println("每个人都有不同的职责");
    }


    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 String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

public class Teacher extends Person{

    private String name;
    private int age;
    private String sex;


    @Override
    public void info() {
        System.out.println("老师的职责是教书育人");
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int getAge() {
        return age;
    }

    @Override
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String getSex() {
        return sex;
    }

    @Override
    public void setSex(String sex) {
        this.sex = sex;
    }
}

public class Student extends Person{

    private String name;
    private int age;
    private String sex;

    @Override
    public void info() {
        System.out.println("学生的职责是好好学习天天向上");
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public int getAge() {
        return age;
    }

    @Override
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String getSex() {
        return sex;
    }

    @Override
    public void setSex(String sex) {
        this.sex = sex;
    }
}

public class TestMain {

    public static void main(String[] args) {
        // 这是父类
        Person p = new Person();
        p.info();

        // 这是父类声明Teacher类实例化
        Person p1 = new Teacher();
        p1.info();

        // 这是父类声明Student类实例化
        Person p2 = new Student();
        p2.info();

    }
}
每个人都有不同的职责
老师的职责是教书育人
学生的职责是好好学习天天向上

Super 关键字的使用

当需要在子类中调用父类的被重写方法时,要使用 super 关键字。

class Animal{
   public void move(){
      System.out.println("动物可以移动");
   }
}
 
class Dog extends Animal{
   public void move(){
      super.move(); // 应用super类的方法
      System.out.println("狗可以跑和走");
   }
}
 
public class TestDog{
   public static void main(String args[]){
 
      Animal b = new Dog(); // Dog 对象
      b.move(); //执行 Dog类的方法
 
   }
}
动物可以移动
狗可以跑和走

重载(Overload)

重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。
重载规则:
被重载的方法必须改变参数列表(参数个数或类型不一样);
被重载的方法可以改变返回类型;
被重载的方法可以改变访问修饰符;
被重载的方法可以声明新的或更广的检查异常;
方法能够在同一个类中或者在一个子类中被重载。
无法以返回值类型作为重载函数的区分标准。

public class Animal {

     int id;

     String name;
    // 空构造器
     public Animal(){
         
     }
    // 有一个参数的构造器
    public Animal(int id){
        this.id = id;
    }
    // 有两个参数的构造器
    public Animal(int id,String name){
        this.id = id;
        this.name = name;
    }
    
    // 没有参数
    public void eat(){
        System.out.println(name+"正在吃");
    }
    // 有参数,吃的什么东西
    public void eat(String fd){
        System.out.println(name+"正在吃" + fd);
    }

    public void sleep(){
        System.out.println(name+"正在睡");
    }
    public void introduction() {
        System.out.println("大家好!我是"         + id + "号" + name + ".");
    }

}

重写与重载之间的区别

重写与重载的区别.jpg

总结

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。


重写与重载.jpg

Java 抽象类

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
在 Java 语言中使用 abstract class 来定义抽象类。如下实例:

public abstract class Employee
{
   private String name;
   private String address;
   private int number;
   public Employee(String name, String address, int number)
   {
      System.out.println("Constructing an Employee");
      this.name = name;
      this.address = address;
      this.number = number;
   }
   public double computePay()
   {
     System.out.println("Inside Employee computePay");
     return 0.0;
   }
   public void mailCheck()
   {
      System.out.println("Mailing a check to " + this.name
       + " " + this.address);
   }
   public String toString()
   {
      return name + " " + address + " " + number;
   }
   public String getName()
   {
      return name;
   }
   public String getAddress()
   {
      return address;
   }
   public void setAddress(String newAddress)
   {
      address = newAddress;
   }
   public int getNumber()
   {
     return number;
   }
}

注意:Employee 类没有什么不同,尽管该类是抽象类,但是它仍然有 3 个成员变量,7 个成员方法和 1 个构造方法。 现在如果你尝试如下的例子:

/* 文件名 : AbstractDemo.java */
public class AbstractDemo
{
   public static void main(String [] args)
   {
      /* 以下是不允许的,会引发错误 */
      Employee e = new Employee("George W.", "Houston, TX", 43);
 
      System.out.println("\n Call mailCheck using Employee reference--");
      e.mailCheck();
    }
}

当你尝试编译 AbstractDemo 类时,会产生如下错误:

Employee.java:46: Employee is abstract; cannot be instantiated
      Employee e = new Employee("George W.", "Houston, TX", 43);
                   ^
1 error

继承抽象类

public class Salary extends Employee
{
   private double salary; //Annual salary
   public Salary(String name, String address, int number, double
      salary)
   {
       super(name, address, number);
       setSalary(salary);
   }
   public void mailCheck()
   {
       System.out.println("Within mailCheck of Salary class ");
       System.out.println("Mailing check to " + getName()
       + " with salary " + salary);
   }
   public double getSalary()
   {
       return salary;
   }
   public void setSalary(double newSalary)
   {
       if(newSalary >= 0.0)
       {
          salary = newSalary;
       }
   }
   public double computePay()
   {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
}


public class AbstractDemo
{
   public static void main(String [] args)
   {
      Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
      Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
 
      System.out.println("Call mailCheck using Salary reference --");
      s.mailCheck();
 
      System.out.println("\n Call mailCheck using Employee reference--");
      e.mailCheck();
    }
}
Constructing an Employee
Constructing an Employee
Call mailCheck using  Salary reference --
Within mailCheck of Salary class
Mailing check to Mohd Mohtashim with salary 3600.0

Call mailCheck using Employee reference--
Within mailCheck of Salary class
Mailing check to John Adams with salary 2400.

抽象方法

如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
Abstract 关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。

public abstract class Employee{
   private String name;
   private String address;
   private int number;
   
   public abstract double computePay();
   
   //其余代码
}

如果一个类包含抽象方法,那么该类必须是抽象类。
任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。
如果Salary类继承了Employee类,那么它必须实现computePay()方法:

public class Salary extends Employee
{
   private double salary; // Annual salary
  
   public double computePay() {
      System.out.println("Computing salary pay for " + getName());
      return salary/52;
   }
 
   //其余代码
}

抽象类总结规定

  1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
  2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
  4. 构造方法,类方法(用 static 修饰的方法)不能声明为抽象方法。
  5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。

Java 接口

什么是接口?

在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

接口与类相似点:

一个接口可以有多个方法。
接口文件保存在 .java 结尾的文件中,文件名使用接口名。
接口的字节码文件保存在 .class 结尾的文件中。
接口相应的字节码文件必须在与包名称相匹配的目录结构中。

接口与类的区别:

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

接口特性

接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。

抽象类和接口的区别

  1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行。
  2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的。
  3. 接口中不能含有静态代码块以及静态方法(用 static 修饰的方法),而抽象类是可以有静态代码块和静态方法。
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
    注:
    JDK 1.8 以后,接口里可以有静态方法和方法体了。
    JDK 1.8 以后,接口允许包含具体实现的方法,该方法称为"默认方法",默认方法使用 default 关键字修饰。
    JDK 1.9 以后,允许将方法定义为 private,使得某些复用的代码不会把方法暴露出去。

接口的声明

public interface NameOfInterface
{
   //任何类型 final, static 字段
   //抽象方法
}

接口有以下特性:

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

public  interface Animal {
   public void eat();
   public void travel();
}

接口的实现

当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。

public  interface Animal {
   public void eat();
   public void travel();
}

public class MammalInt implements Animal{
 
   public void eat(){
      System.out.println("Mammal eats");
   }
 
   public void travel(){
      System.out.println("Mammal travels");
   } 
 
 
   public static void main(String args[]){
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}
Mammal eats
Mammal travels

重写接口中声明的方法时,需要注意以下规则:

类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
如果实现接口的类是抽象类,那么就没必要实现该接口的方法。

在实现接口的时候,也要注意一些规则:

一个类可以同时实现多个接口。
一个类只能继承一个类,但是能实现多个接口。
一个接口能继承另一个接口,这和类之间的继承比较相似。

接口的继承

一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。

public interface Sports
{
   public void setHomeTeam(String name);
   public void setVisitingTeam(String name);
}
 
// Football 接口继承Sports接口
public interface Football extends Sports
{
   public void homeTeamScored(int points);
   public void visitingTeamScored(int points);
   public void endOfQuarter(int quarter);
}
 
// Hockey 接口继承Sports接口
public interface Hockey extends Sports
{
   public void homeGoalScored();
   public void visitingGoalScored();
   public void endOfPeriod(int period);
   public void overtimePeriod(int ot);
}

接口的多继承

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

public interface Sports
{
   public void homeGoalScored();
   public void visitingGoalScored();
}
 
// Football 接口继承Sports接口
public interface Football
{
   public void endOfQuarter(int quarter);
}
 
// Hockey 接口继承Sports接口
public interface Hockey extends Sports,Football
{
   public void homeGoalScored();
   public void visitingGoalScored();
   public void endOfQuarter(int quarter);
   public void endOfPeriod(int period);
   public void overtimePeriod(int ot);
}

标记接口

最常用的继承接口是没有包含任何方法的接口。
标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其他代码来测试允许做一些事情。
标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。
例如:java.awt.event 包中的 MouseListener 接口继承的 java.util.EventListener 接口定义如下:

package java.util;
public interface EventListener
{}

没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的:

1、建立一个公共的父接口:

正如EventListener接口,这是由几十个其他接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。

2、向一个类添加数据类型:

这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过多态性变成一个接口类型。
反正我是没用过这种方式,也是第一次听到标记接口,算是学习到了。

Java 文档注释

Java 支持三种注释方式。前两种分别是 // 和 /* /,第三种被称作说明注释,它以 /* 开始,以 */结束。
说明注释允许你在程序中嵌入关于程序的信息。你可以使用 javadoc 工具软件来生成信息,并输出到HTML文件中。
说明注释,使你更加方便的记录你的程序信息。

javadoc 标签

javadoc标签.jpg

文档注释

在开始的 /** 之后,第一行或几行是关于类、变量和方法的主要描述。
之后,你可以包含一个或多个各种各样的 @ 标签。每一个 @ 标签必须在一个新行的开始或者在一行的开始紧跟星号(*).
多个相同类型的标签应该放成一组。例如,如果你有三个 @see 标签,可以将它们一个接一个的放在一起。

/*** 这个类绘制一个条形图
* @author heybo
* @version 1.2
* @return void
*/

javadoc 输出什么?

javadoc 工具将你 Java 程序的源代码作为输入,输出一些包含你程序注释的HTML文件。
每一个类的信息将在独自的HTML文件里。javadoc 也可以输出继承的树形结构和索引。
由于 javadoc 的实现不同,工作也可能不同,你需要检查你的 Java 开发系统的版本等细节,选择合适的 Javadoc 版本。

import java.io.*;
 
/**
* 这个类演示了文档注释
* @author heybo
* @version 1.8
*/
public class SquareNum {
   /**
   * This method returns the square of num.
   * This is a multiline description. You can use
   * as many lines as you like.
   * @param num The value to be squared.
   * @return num squared.
   */
   public double square(double num) {
      return num * num;
   }
   /**
   * This method inputs a number from the user.
   * @return The value input as a double.
   * @exception IOException On input error.
   * @see IOException
   */
   public double getNumber() throws IOException {
      InputStreamReader isr = new InputStreamReader(System.in);
      BufferedReader inData = new BufferedReader(isr);
      String str;
      str = inData.readLine();
      return (new Double(str)).doubleValue();
   }
   /**
   * This method demonstrates square().
   * @param args Unused.
   * @return Nothing.
   * @exception IOException On input error.
   * @see IOException
   */
   public static void main(String args[]) throws IOException
   {
      SquareNum ob = new SquareNum();
      double val;
      System.out.println("Enter value to be squared: ");
      val = ob.getNumber();
      val = ob.square(val);
      System.out.println("Squared value is " + val);
   }
}

使用 javadoc 工具处理 SquareNum.java 文件:

$ javadoc SquareNum.java
Loading source file SquareNum.java...
Constructing Javadoc information...
Standard Doclet version 1.5.0_13
Building tree for all the packages and classes...
Generating SquareNum.html...
SquareNum.java:39: warning - @return tag cannot be used\
                      in method with void return type.
Generating package-frame.html...
Generating package-summary.html...
Generating package-tree.html...
Generating constant-values.html...
Building index for all the packages and classes...
Generating overview-tree.html...
Generating index-all.html...
Generating deprecated-list.html...
Building index for all classes...
Generating allclasses-frame.html...
Generating allclasses-noframe.html...
Generating index.html...
Generating help-doc.html...
Generating stylesheet.css...
1 warning
$

因为是自己整理,难免有不全的地方,想起来再补充吧!至于Java内部类有时间单独抽出来写一章吧!

你可能感兴趣的:(重拾Java基础 2021-12-05)