JAVA面向对象基础复习(封装-继承-多态)

本文知识总结点参考:程杰-《大话设计模式》

代码改编自-程杰-《大话设计模式》-附录A

编译环境:IDEA

目录

0、对象

1、类与实例

代码示例1:写一个类并创建实例调用这个类:

2、构造方法

代码示例2:写一个类和它的构造函数

 3、方法重载

代码示例3:使用方法重载,给name重新命名。

 4、属性与修饰符

代码示例4:在类中定义多个字段和属性。

 5、封装

代码示例5:模仿Animal类写一个Dog类。

6、继承

代码示例6:因为Dog类具有Animal类所有功能,可以让Dog类继承Animal类。

7、多态

代码示例7:子类通过覆写父类方法实现各自不同功能。

 8、重构

代码示例8:重构之前代码。

9、抽象类

 代码示例9:抽象类和抽象方法

 10、接口

代码实例10:接口实现


0、对象

  •         对象:是一个自包含的实体,用一组可识别的特性和行为来标识。
  •         面向对象编程 Object-Oriented Programming:就是针对对象进行编程。

1、类与实例

  •         类:就是具有相同属性和功能的对象的抽象集合。
  •         实例:就是一个真实的对象。

代码示例1:写一个类并创建实例调用这个类:

Animal.java

public class Animal {
    public void Shout(String name){
        System.out.println(name+"在叫");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Animal ani = new Animal();
        String aniName="猫";
        ani.Shout(aniName);
    }
}

输出:

2、构造方法

  •         构造方法,也称构造函数,其实就是对类进行初始化。构造方法必须与类同名,没有返回值,也不需要void,在new的时候会默认被调用。
  •         所有的类都有构造方法,如果你不编码,系统会默认生成空的构造方法,若你自己定义了构造方法,那么默认的构造方法就失效了。

代码示例2:写一个类和它的构造函数

Animal.java

public class Animal {

    private String name="";
    public Animal(String name){
        this.name = name;
    }
    public void Shout(){
        System.out.println(name+"在叫");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        String aniName="猫";
        Animal ani = new Animal(aniName);
        ani.Shout();
    }
}

输出:

 3、方法重载

  •         方法重载提供了创建同名的多个方法的能力,但这些方法需要使用不同的参数类型。
  •         在进行方法重载时,两个方法必须是同名的,但是参数类型或个数必须有所不同。
  •         方法重载可以在不改变原方法的基础上,新增功能。

代码示例3:使用方法重载,给name重新命名。

Animal.java 

public class Animal {

    private String name="";
    public Animal(String name){
        this.name = name;
    }
    //方法重载
    public Animal(){
        this.name="狗";
    }
    public void Shout(){
        System.out.println(name+"在叫");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        //String aniName="猫";
        Animal ani = new Animal();
        ani.Shout();
    }
}

输出:

 4、属性与修饰符

  •         属性是一个方法或一对方法,但在调用它的代码看来,它是一个字段,即属性适合于以字段的方式使用方法调用的场合。
  •         字段是存储类要满足其设计所需的数据,字段是与类相关的变量。
  •         public、private都是java中的修饰符。public表示它所修饰的类成员可以允许其他类访问,俗称“公有的”。而private表示只允许同一个类的成员访问,其他类包括它的子类无法访问,俗称私有类。
  •         如果在类中没有加修饰符,则被认为是private。
  •         通常字段都是私有变量(private),属性都是公有变量(public)。

代码示例4:在类中定义多个字段和属性。

Animal.java

public class Animal {

    //名字字段
    private String name="";
    //叫声次数字段
    private int shoutNum = 3;
    //构造函数
    public Animal(String name){
        this.name = name;
    }
    //方法重载
    public Animal(){
        this.name="狗";
    }
    //这里setshoutNum和getshoutNum可以看做是一对属性
    public void setShoutNum(int shoutNum){
        this.shoutNum = shoutNum;
    }
    public int getShoutNum(){
        return shoutNum;
    }
    public void Shout(){
        System.out.println(name+"叫了"+getShoutNum()+"声");

    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Animal ani = new Animal();
        ani.setShoutNum(2);
        ani.Shout();
    }
}

输出:

 5、封装

  •         每个对象都包含他能进行操作所需要的所有信息,这个特性称为封装,因此对象不必依赖其他对象来完成自己的操作。
  •         封装的好处:
  •                 (1)减少耦合
  •                 (2)类内部的实现可以自由更改
  •                 (3)类具有清晰的对外接口

代码示例5:模仿Animal类写一个Dog类。

Dog.java

public class Dog {
    private String name="";
    //叫声次数字段
    private int shoutNum = 3;
    //构造函数
    public Dog(String name){
        this.name = name;
    }
    //方法重载
    public Dog(){
        this.name="狗";
    }
    //这里setshoutNum和getshoutNum可以看做是一对属性
    public void setShoutNum(int shoutNum){
        this.shoutNum = shoutNum;
    }
    public int getShoutNum(){
        return shoutNum;
    }
    public void Shout(){
        System.out.println(name+"叫了"+getShoutNum()+"声");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setShoutNum(3);
        dog.Shout();
    }
}

除了名字不同,Dog类和Animal类基本没什么差别,所以为了更好的实现代码的复用,让开发变的更简洁,我们要用到面向对象的第二大特性——继承。

6、继承

  •         对象的继承代表了一种“is-a”的关系,如果两个对象A和B,可以描述为“B是A”,则表明B可以继承+A。
  •         继承者还可以理解为是对被继承者的特殊化,因为他除了具备被继承者的特性外,还具备自己独特的个性。
  •         继承定义了类如何相互关联,共享特性。继承的工作方式是,定义父类和子类,或叫做基类和派生类,其中子类继承父类的所有特性。子类不但继承了父类的所有特性,还可以定义新的特性。
  •         如果子类继承于父类:
  •                 第一、子类拥有父类非private的属性和功能。
  •                 第二、子类具有自己的属性和功能,即子类可以扩展父类没有的属性和功能。
  •                 第三、子类还可以以自己的方式实现父类的功能(方法重写)。
  •         处了private和public外,还有一个protected修饰符,它表示子类继承父类时,有对父类的完全访问权。
  •         子类从它的父类中继承的成员有方法、域、属性、事件、索引指示器、但对于构造方法有一些特殊,他不能被继承,只能被调用。对于调用父类的构造方法我们可以使用super(参数列表)实现。

代码示例6:因为Dog类具有Animal类所有功能,可以让Dog类继承Animal类。

Animal.java

public class Animal {

    //名字字段
    protected String name="";
    //叫声次数字段
    protected int shoutNum = 3;
    //构造函数
    public Animal(String name){
        this.name = name;
    }
    //方法重载
    public Animal(){
        this.name="无名";
    }
    //这里setshoutNum和getshoutNum可以看做是一对属性
    public void setShoutNum(int shoutNum){
        this.shoutNum = shoutNum;
    }
    public int getShoutNum(){
        return shoutNum;
    }
    public void Shout(){
        System.out.println(name+"叫了"+getShoutNum()+"声");
    }
}

Dog.java

public class Dog extends Animal{
    //调用父类构造函数
    public Dog(){
        super();
    }
    public Dog(String name){
        super(name);
    }

    public void Shout(){
        System.out.println(name+"叫了"+getShoutNum()+"声");
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog("狗");
        dog.setShoutNum(10);//这里子类可以直接调用父类中的属性或方法
        dog.Shout();
    }
}

输出:

  •          如果不使用继承,在修改功能时,就必须在所有重复的方法中修改,代码越多,出错率就越大;而继承的优点是,继承的所有子类公共部分都放在了父类,使得代码得到了共享,这样就避免了重复,另外,继承可使的修改或扩展继承而来的实现都较为容易。
  •         继承也是有缺点的,那就是父类变,子类必须跟着变。
  •         另外,继承会破坏包装,父类实现结点暴露给子类。
  •         同时,继承也是一种类与类之间的强耦合关系。
  •         当两个类之间具备“is-a”关系时,就可以考虑使用继承了。当两个类之间是“has-a”的关系时,表示某个角色具有某项责任,这时就不适合用继承,比如人有两只手,手不能继承人。而狗是动物,狗类就可以继承动物类。

7、多态

  •         面向对象的第三大特性——多态:多态表示不同的对象可以执行相同的动作,但要通过它们自己的代码来执行,不能直接调用父类。
  •         多态需要注意三点:
  •                 第一、子类以父类的身份出现。
  •                 第二、子类在工作时以自己方式来实现。
  •                 第三、子类以父类的身份出现时,子类特有的属性和方法不可用。
  •         为了使子类的实例完全接替来自父类的类成员,父类必须将该成员声明为虚拟的。这是通过在该成员的返回类型之前添加virtual关键字来实现的。
  •         子类可以选择使用override关键字,将父类实现替换为它自己的实现,这就是方法重写Override,或者叫方法覆写。

代码示例7:子类通过覆写父类方法实现各自不同功能。

Animal.java

public class Animal {

    //名字字段
    protected String name="";
    //构造函数
    public Animal(String name){
        this.name = name;
    }
    //方法重载
    public Animal(){
        this.name="无名";
    }

    public String Shout() {
        return name+": ";
    }
}

Dog.java

public class Dog extends Animal{
    //调用父类构造函数
    public Dog(){
        super();
    }
    public Dog(String name){
        super(name);
    }

    public String Shout(){
        return "汪汪汪";
    }
}

Cat.java

public class Cat extends Animal{
    //调用父类构造函数
    public Cat(){
        super();
    }
    public Cat(String name){
        super(name);
    }

    public String Shout(){

        return name+": 喵喵喵";
    }
}

Pig.java

public class Pig extends Animal{
    public Pig(){
        super();
    }
    public Pig(String name){
        super(name);
    }

    public String Shout(){

        return name+": 哼哼哼";
    }
}

Main,java

public class Main {
    //声明一个动物数组

    public static void main(String[] args) {

        Animal[] arrayAnimal;

        arrayAnimal = new Animal[5];

        arrayAnimal[0] = new Cat("猫");
        arrayAnimal[1] = new Dog("狗");
        arrayAnimal[2] = new Pig("猪");

        for (int i = 0; i < 3; i++) {
            System.out.println(arrayAnimal[i].Shout());
        }
    }
}

输出:

 8、重构

        其实在每个子类中的Shout方法也是重复步骤,我们可以在父类中定义一个获取声音的虚函数,然后子类覆写这个函数返回一个声音即可,这样重构后的设计会更加简洁。

代码示例8:重构之前代码。

Animal.java

public class Animal {

    //名字字段
    protected String name="";
    //构造函数
    public Animal(String name){
        this.name = name;
    }
    //方法重载
    public Animal(){
        this.name="无名";
    }
    //获取叫声
    public String getShoutSound(){
        return "";
    }
    public String Shout() {
        return name+": "+getShoutSound();
    }
}

 Dog.java

public class Dog extends Animal{
    //调用父类构造函数
    public Dog(){
        super();
    }
    public Dog(String name){
        super(name);
    }

    public String getShoutSound(){
        return "汪汪汪";
    }
}

Cat.java 

public class Cat extends Animal{
    //调用父类构造函数
    public Cat(){
        super();
    }
    public Cat(String name){
        super(name);
    }

    public String getShoutSound(){
        return "喵喵喵";
    }
}

Pig.java 

public class Pig extends Animal{
    public Pig(){
        super();
    }
    public Pig(String name){
        super(name);
    }

    public String getShoutSound(){
        return "哼哼哼";
    }
}

Main.java 

public class Main {
    //声明一个动物数组

    public static void main(String[] args) {

        Animal[] arrayAnimal;

        arrayAnimal = new Animal[5];

        arrayAnimal[0] = new Cat("猫");
        arrayAnimal[1] = new Dog("狗");
        arrayAnimal[2] = new Pig("猪");

        for (int i = 0; i < 3; i++) {
            System.out.println(arrayAnimal[i].Shout());
        }
    }
}

输出:

9、抽象类

  •         Java允许把类和方法声明为abstract,即抽象类和抽象方法。
  •         抽象类需要注意:
  •                 第一、抽象类不能实例化。
  •                 第二、抽象方法是必须被子类重写的方法。
  •                 第三、如果类中包含抽象方法,那么类就必须定义为抽象类,不论是否还包含其他方法。
  •         所以一开始就把Animal类设为抽象类,就没必要存在虚方法的父类,我们应该考虑让抽象类拥有尽可能多的共同代码,拥有尽可能少的数据。
  •         抽象类通常代表一个抽象概念,它提供一个继承的出发点,当设计一个新的抽象类时,一定是用来继承的,所以,在一个以继承关系形成的等级结构里,树叶节点应该是具体类,树枝结点均应该是抽象类。

 代码示例9:抽象类和抽象方法

 10、接口

  •         接口是把隐式公共方法和属性组合起来,以封装特定功能的一个集合。一旦类实现了接口,类就可以支持接口所有属性和成员。声明接口在语法上与抽象类完全相同,但不允许提供接口中任何成员的执行方式。
  •         实现接口的类就必须要实现接口中所有方法和属性。
  •         一个类可以支持多个接口,多个类也可以支持相同的接口。
  •         接口的命名,前面要加一个大写的字母“I”,也可以不加,但不规范。

代码实例10:接口实现

Animal类:

abstract public class Animal {

    //名字字段
    protected String name="";
    //构造函数
    public Animal(String name){
        this.name = name;
    }
    //方法重载
    public Animal(){
        this.name="无名";
    }
    //获取叫声
    public String getShoutSound(){
        return "";
    }
    public String Shout() {
        return name+": ";
    }
}

 我们先创建一个接口,用来“变东西”。

IChange.interface

public interface IChange {
    String ChangeThing(String thing);
}

再创建一个机器猫类

MachineCat.java

//继承猫类同时实现一个IChange接口
public class MachineCat extends Cat implements IChange {
    public MachineCat(){
        super();
    }
    public MachineCat(String name){
        super(name);
    }
    //实现接口类中的方法
    public String ChangeThing(String thing){
        return super.Shout() + "我的四维口袋可以变出:" + thing;
    }
}

Main.java

public class Main {
    //声明一个动物数组

    public static void main(String[] args) {

        MachineCat mcat = new MachineCat("小叮当");
        System.out.println(mcat.ChangeThing("任意门"));
    }
}

输出:

猜你喜欢

转载自blog.csdn.net/qq_51701007/article/details/127178337