跳至主要內容

Java基础 - 面向对象

Zenghr大约 7 分钟Java

Java基础 - 面向对象

提示

本文介绍 Java 面向对象的相关知识

封装

封装好处

  • 尽可能的隐藏信息和功能实现细节
  • 保证数据的安全性,防止随意修改数据
  • 提高组件的复用性

JavaBean的三个规范

  • 类名用 public 修饰符修饰
  • 类的成员变量用 private 修饰,阻止外部直接调用,并且需要提供一对 公共访问器(getter,setter) 给外界使用
  • 当显示定义了 有参构造方法 时需要 提供 无参构造器,当你有定义有参构造器时, JVM 不会自动帮你分配无参构造器
// 规范1 类名使用 public 修饰符
public class Student {
    // 规范二 字段使用 private 修饰符 修饰
    private String name; // 名字
    private int age; // 年龄
	
    // 规范三 要有无参构造
    public Student() {
        
    }
    
    public Student(String name, int age) {
        setName(name);
        setAge(age);
    }
    
    // 规范四 每个字段要有 get、set
    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;
    }
}

继承

访问修饰符

Java 中有三个访问修饰符 privateprotectedpublic以及一个缺省的修饰符,表示包可见

可以对类或者类的字段、方法加上访问修饰符,下面的表格表示各个修饰符的范围:

访问修饰符本类同包子类同包其他类不同包子类不同包其他类
private
默认
protected
public
  • private: 私有的,该修饰符控制只能本类中使用
  • 默认(缺省): 友好的,访问范围是 本包中可见,也经常称为:包可见
  • protected: 受保护的,访问范围是:本包可见以及继承的子类可见
  • public: 公共的,所有地方都可以访问

提示

2021-04-14 添加 protected 补充理解: A是B的子类,B有一个 protected 的方法C, A的对象是否能够直接调用C方法?

protected 方法在子类中可用,指的是 子类的代码中可以用,不是子类的对象

具体例子:Object 是所有类的超类,其中 clone() 方法是用 protected 修饰的,clone() 就只能在子类代码中使用,子类实例化的对象不能使用,除非这个子类和 Object 在同一个包

1. 什么是抽象类

  • 抽象类就是使用 abstract 关键字定义的类
  • 抽象类不能创建实例
  • 抽象类中,可以定义抽象方法和普通方法,抽象方法必须定义在抽象类中
  • 子类继承抽象类必须实现抽象类中的抽象方法,否则子类必须是抽象类

抽象类被创造出来就是为了继承

抽象类继承方式:在类名后接 extends 关键字,子类只能继承一个父类

2. 什么是接口

提示

接口类就是使用 interface 关键字定义的一种特殊的抽象类

接口是一种约定的规范,定义了应该有什么功能,本身不实现功能,具体交给实现类实现

接口特性

  • 接口可以包含变量,成员变量会被隐式地指定public static final 变量(并且只能是public static final变量,用private修饰会报编译错误)
  • 接口可以包含方法,方法会被隐式地指定public abstract 方法且只能是public abstract方法(用其他关键字,比如private、protected、static、 final等修饰会报编译错误),并且接口中所有的方法不能有具体的实现,也就是说,接口中的方法必须都是抽象方法
  • 一个类可以同时继承多个接口,且需要实现所继承接口的所有方法

接口实现方式

  • 接口类使用 interface 定义
  • 实现类使用 implements 关键字实现, 并且要在继承关键字 (extends) 后面,一个类可以实现多个接口类,使用 (,) 隔开就行

扩展:从Java1.8开始, Java支持在接口中定义有实现的方法:

public interface IWalkable {
	public abstract void walk();//抽象方法
    default void defaultMethod(){
       System.out.println("有默认实现的方法, 属于对象");
    }
    static void defaultMethod(){
       System.out.println("有默认实现的方法, 属于类");
    }
}

3. 抽象与接口的区别

相同点

  1. 都不能被实例化
  2. 接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化。

不同点

  1. 抽象类可以提供成员方法的实现细节,而接口中只能存在 public abstract 方法;
  2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的;
  3. 接口只有定义,不能有方法的实现,java 1.8中可以定义default方法体,而抽象类可以有定义与实现,方法可在抽象类中实现。
  4. 接口中不能含有静态代码块,而抽象类可以有静态代码块和静态方法;
  5. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

4. 何时使用抽象、接口

提示

抽象类本质就是从 多个类中提取相同行为,更合适定义公共的行为

接口适合用来定义扩展功能

  • 当需要注重代码的扩展性或者可维护性,优先使用接口,接口和类之间没有任何层次关系
  • 当需要为一些类提供公共的方法时,优先考虑抽象类;提供扩展功能使用接口

多态

1、分类

多态分为编译时和运行时多态

  • 编译时多态:设计时多态,主要是指 方法的重载
  • 运行时多态:指程序中定义的对象引用所指向的具体类型在运行期间才确定

2、必要条件

  • 必须要有继承关系
  • 必须要重写(实现),没有继承就没有重写
  • 父类引用指向子类对象子类对象指向父类引用

3、继承关系

父类 变量名 = new 实现类();
变量名.方法();

Animal类

public class Animal {
    public void shut() {
    	System.out.println("Animal...shout...");
    }
}

Cat类

public class Cat extends Animal{
    public void shut() {
    	System.out.println("妙妙妙...");
    }
}

Dog类

public class Dog extends Animal{
    public void shut() {
    	System.out.println("哇哇哇...");
    }
}

测试类

public class AnimalDemo {
    public static void main(String[] args) {
        Animal animal = null;
        // 创建Cat对象
        animal = new Cat();
        animal.shut();

        // 创建Dog对象
        animal = new Dog();
        animal.shut();
    }
}
// 输出结果:
// 妙妙妙...
// 哇哇哇...

总结

提示

父类引用变量指向于子类对象,调用方法时实际调用的是子类的方法。

4、实现关系

接口 变量名 = new 实现类();
变量名.方法();

ISwimable 接口

public interface ISwimable {
	void swim();
}

Fish类

public class Fish implements ISwimable{
    public void swim() {
    	System.out.println("游啊游...");
    }
}

Dog类

public class Dog extends Animal implements ISwimable{
    public void shut() {
    	System.out.println("哇哇哇...");
    }
    public void swim() {
    	System.out.println("狗刨式...");
    }
}

测试类

public class FishDemo {
    public static void main(String[] args) {
        // 创建Fish对象
        ISwimable fish = new Fish();
        fish.swim();
        fish = new Dog();//Dog也是实现了ISwimable接口的
        fish.swim();
    }
}
// 输出结果:
// 游啊游...
// 狗刨式...

总结

提示

接口引用变量指向实现类对象,调用方法时实际调用的是实现类实现接口的方法。

5、多态时方法调用问题

在上面的例子中,Animal 对象调用 shut 方法,是调用 Animal 中的还是 Cat?观察下图👇

mark
mark

调用流程:

  • 编译时判断 shut 方法是否在父类存在
  • 不存在,则报错
  • 找到:运行时再看子类 Cat 中是否有 该方法
  • 找不到,执行父类的方法
  • 找到,执行子类的方法

6、多态中的类型转换

类型转换

自动类型转换(向上转型):把子类对象赋给父类变量(多态)

// 父类 <= 子类
Animal a = new Dog();

强制类型转换(向下转型):把父类类型对象赋给子类类型变量。

// 子类 <= (子类)父类
Animal a = new Dog();
Dog d = (Dog) a; //正确
Cat c = (Cat) a; //错误

instanceOf

判断该对象是否是某一个类/接口的实例

语法格式:
boolean b = 对象A  instanceofB;  //判断 A对象是否是 B类的实例?如果是,返回true
Animal a = new Dog();
System.out.println(a instanceof Animal); //true
System.out.println(a instanceof Dog); //true
System.out.println(a instanceof Cat); //false

7、多态总结

提示

一句话概括:多态就是 同一个引用数据类型变量,由于引用的实例不同,执行相同的方法,产生不同的结果

参考资料

Java 全栈知识体系 - 面向对象open in new window