Java 的面向对象编程

在读此教程之前, 我们先理解一下 什么是面向对象编程?

看完了上述文章, 我们对面向对象编程已经基本了解了, 现在我们可以来看看 Java 作为作为一种面向对象语言, 如何实现面向对象中的各种特性吧:

1. Java 中的类

java 中取决你如何抽象, 所以万物皆可类, 只要命名方法符合要求即可, 我们首先定义一个类作为执行容器:

public class Course21YiRunner {

    public static void main(String[] args) {
        System.out.println("Hello, I'm 21yi runner");
    }

}

然后我们在 Course21YiRunner 下创建一个 Animal 类, 代码如下:

class Animal {

    protected int age;

    public void hello() {
        System.out.println("I'm " + age + " days old.");
    }

    public void talk() {
        System.out.println("Make some sounds.");
    }

}

这样我们就有两个类了, 负责运行交互的 Course21YiRunner 和一个用于学习理解的 Animal 类.

1.1 Java 中类的属性

抛开 Course21YiRunner 不看, 在 Animal 类中我们定义了一个属性

protected int age;

一个是 int(整数) 类型的 age. 这个属性就是动物共有的特性之一年龄. 当然动物还有很多其他的特性, 我们不需要一一列出, 只列出我们需要用到的就好了.

1.2 Java 中类的方法

而我们在 Animal 类中定义了 hellotalk 两个方法:

public void hello()

以及

public void talk()

hello 方法表示动物可以做出告诉别人自身有年纪有多少天这个行为(这是种抽象方法不必非得符合现实), 而 talk 方法负责让动物发出一些声音.

两个方法, 没用使用和 Course21YiRunnermain 方法一样的静态修饰符 static , 这说明这两个方法是非静态的方法, 非静态的方法需要在类进行初始化生成一个对象后方能使用.

关于 Java 方法详细说明, 请参照下一节 Java 的方法

2. Java 中的对象

Java 中一个对象的使用, 需要通过初始化之后才能调用他的方法.

2.1 对象的初始化

在 Java 中我们通常使用 new 来初始化一个对象, 我们修改 Course21YiRunner 中 main 方法如下:

    public static void main(String[] args) {
        System.out.println("Hello, I'm 21yi runner");
        Animal animal = new Animal();
        animal.talk();
        animal.hello();
    }

在上述代码中, 我们通过代码 Animal animal = new Animal(); 初始化了一个对象, 并赋值到变量 animal.

然后我们调用了在 Animal 类中定义的 talk() 和 hello() 方法, 执行结果如下:

Java 对象和类运行示例1

这样我们就成功的初始化了一个对象, 并调用了他的方法.

 每次更改后都需要重新编译编辑过的文件以保证修改生效

2.2 构造方法

虽然我们已经成功的调用了 Animal 类的 talk() 和 hello() 方法, 但我们观察后可以发现 hello() 方法实际上使用到了属性 age, 这样对象只能是刚出生的动物, 如果我们想初始化一个出生了很久的动物(比如之前动物实例的妈妈). 这个时候我们就要用到构造方法了,构造方法是一种特殊的方法, 是可以让我们在初始化一个对象时调用的方法, 在这个方法里, 我们可以做一些预定义的处理操作, 比如修改 Animal 对象的 age . 我们在 Animal 类中添加两个构造方法, 具体如下:

    public Animal() {
        
    }

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

首先构造方法的名字是与类名完全一致的, 其次构造方法是没有返回值的, 连 void 都没有.

第一个 public Animal() 方法保持了原始的构造方法, 而  public Animal(int age) 方法修改了 age 属性, 在这个方法里, 我们提供了一个 age 参数, 用来初始化动物的年龄. 因为属性和方法参数的名字都是 age , 所以我们在代码中使用了 this.age 来明确 参数 age 所赋值的对象.

然后我们修改 Course21YiRunner 中 main 方法如下:

    public static void main(String[] args) {
        System.out.println("Hello, I'm 21yi runner");
        Animal animal = new Animal(180);
        animal.talk();
        animal.hello();
    }

在这里我们将 Animal 的初始化参数 age 的值设为了 180 , 因为提供的参数不同, Java 自动帮我们选择了符合参数类型的  Animal(int age) 方法, 执行结果如下:

Java 对象和类执行结果2

这时动物的年龄已经变成 180 了.

3. Java 中的封装

在上述的代码中  Course21YiRunner 类无法干涉到 Animal 类的内部计算, 体现了 Java 的封装性:

除非  Animal 类暴露入口让外部介入, 否则外部无法干涉到  Animal 的内部状态.

4. Java 中的继承

新建一个  Human 继承 Animal , 代码如下:

public class Human extends Animal {

    public Human() {
        super();
    }

    public Human(int age) {
        super(age);
    }

}

这里我们定义了一个类, 并且定义了两个与 Animal 结构类似的构造方法. 代码中的 super() 是调用了父类  Animal 的构造方法.

然后我们修改 Course21YiRunner 中 main 方法如下:

    public static void main(String[] args) {
        System.out.println("Hello, I'm 21yi runner");
        Animal animal = new Animal(180);
        animal.talk();
        animal.hello();
        //小丽十八岁了
        Human xiaoli = new Human(6580);
        xiaoli.talk();
        xiaoli.hello();
    }

执行结果如下:

Java 对象和类执行结果3

这里我们可以清楚的看到 "I'm 6580 days old." , 而子类 Human 完全继承了父类 Animal 的方法以及属性.

5. Java 中的重写

但是作为一个 Human 其对象的 talk 如果只会 "Make sme sounds" 难免有点奇怪. 这时候作为子类在做出 talk() 行为时就无法与其父类 Animal 保持一致了, 这个时候我们就需要在子类中重写父类的 talk() 方法了, 在 Human 中添加代码如下:

    @Override
    public void talk() {
        System.out.println("What? Say something.");
    }

这里的 @Override 是一种叫注解的东西, 用于告诉编译器, 我们做了某种特定的行为, 这里的行为就是告诉编译器, 我已经重写了父类的方法.

重新执行, 结果如下:

Java 对象和类执行结果4

这时, Humantalk() 方法, 就不再是  "Make sme sounds"  了, 而是  "What? Say something."  了

6. Java 中的多态性

多态性是指一个类有多种状态, 在本例中 Animal 就有 Human 这种状态, 既然有这种状态.

那么一个 Human 我们完全可以当成是 Animal 使用, 修改 main 代码如下:

    public static void main(String[] args) {
        System.out.println("Hello, I'm 21yi runner");
        Animal animal = new Animal(180);
        animal.talk();
        animal.hello();
        //小丽十八岁了
        Human xiaoli = new Human(6580);
        xiaoli.talk();
        xiaoli.hello();
        Animal person = new Human(365);
        person.talk();
        person.hello();
    }

执行结果如下: 

Java 对象和类执行结果5

我们可以把 Human 当作 Animal 使用, Human 虽然是 Animal 但实际上仍然做出的是其自身的行为.

同时多态也有这种状态: 只要是 Animal 可以正常运行的地方, 作为其子类 Human 也可以正常运行, 

Course21YiRunner 中添加 animalTalk() 方法:

    public static void animalTalk(Animal animal) {
        animal.talk();
    }

修改 main 方法如下:

    public static void main(String[] args) {
        System.out.println("Hello, I'm 21yi runner");
        Animal animal = new Animal(180);
        animal.talk();
        animal.hello();
        //小丽十八岁了
        Human xiaoli = new Human(6580);
        xiaoli.talk();
        xiaoli.hello();
        Animal person = new Human(365);
        person.talk();
        person.hello();
        animalTalk(new Animal());
        animalTalk(new Human());
    }

执行结果如下:

Java 对象和类执行结果6

animalTalk() 方法中接受一切是 Animal 的类, 然后调用其 talk() 方法, Human 作为 Animal 的子类, 自然也是可以被该方法接受, 即无论 Animal 是何种形态, 只要其是 Animal 就可以.

以上就是 Java 对象和类的全部教程内容了, 下面附上本文中的完整代码:

类 Course21YiRunner:

public class Course21YiRunner {

    public static void main(String[] args) {
        System.out.println("Hello, I'm 21yi runner");
        Animal animal = new Animal(180);
        animal.talk();
        animal.hello();
        //小丽十八岁了
        Human xiaoli = new Human(6580);
        xiaoli.talk();
        xiaoli.hello();
        Animal person = new Human(365);
        person.talk();
        person.hello();
        animalTalk(new Animal());
        animalTalk(new Human());
    }

    public static void animalTalk(Animal animal) {
        animal.talk();
    }

}

类 Animal:

class Animal {

    protected int age;

    public Animal() {
        
    }

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

    public void hello() {
        System.out.println("I'm " + age + " days old.");
    }

    public void talk() {
        System.out.println("Make some sounds.");
    }

}

类 Human:

public class Human extends Animal {

    public Human() {
        super();
    }

    public Human(int age) {
        super(age);
    }
    
    @Override
    public void talk() {
        System.out.println("What? Say something.");
    }

}

7. Java 中的接口 (interface)

在 Java 中如果你想约定一个类该具备那些方法, 而并不在意这些方法具体该如何实现, 那么你就应该使用接口.

我们可以将接口理解为一种契约, 你要实现接口, 必须满足实现接口中所有定义过的方法, 至于实现过程, 我们并不在意. (emm...有点像老板的样子)

又或者你想实现多重继承, 让一个类具备多种特性, 但是在 Java 中, 类无法被多重继承, 但是接口可以实现多个.

接口的实现可以像如下代码一样:

public class Yi21Runner {

    interface Swimmer {
        void swim();
    }

    interface layEgger {
        void layEgg();
    }

    interface WaterAnimal extends Swimmer, layEgger {
    }

    class Crocodile implements WaterAnimal {

        @Override
        public void swim() {
        }

        @Override
        public void layEgg() {
        }

    }

    class Duck implements WaterAnimal {

        @Override
        public void swim() {
        }

        @Override
        public void layEgg() {
        }

    }

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

上述代码解析如下:

  • 定了了两个接口 Swimmer (游泳者) 和  layEgger (下蛋者), 分别需要实现两个方法 swim()layEgg() .
  • 定义了一个接口 WaterAnimal (水边的动物) 继承了 Swimmer layEgger , 这样 WaterAnimal 就成为了具备待实现方法  swim() 和 layEgg() 的接口.
  • 定义一个 Crocodile (鳄鱼)实现了 WaterAnimal 接口, 同时要实现  swim() 和 layEgg() 两个方法
  • 定义一个 Duck (鸭子)实现了 WaterAnimal 接口, 同时要实现  swim() 和 layEgg() 两个方法

从上面我们可以看出, 接口可以继承接口, 类也可以实现多个接口, 另外只要实现了 WaterAnimal 接口, 我们可以并不在意实际是谁来完成这些方法, 无论是鳄鱼还是鸭子.

8. Java 中的抽象类 (abstract class)

使用 abstract 修饰的类称之为抽象类, 抽象类不能直接实例化使用. 抽象类中可以包含抽象方法, 也可以包含具体实现的方法. 但是如果声明了一个抽象方法, 那么声明类的时候则必须声明为抽象类.

抽象类与接口其实很相似, 抽象类也不可实例化, 但是使用抽象类你可以定义具体的字段和方法, 但是无论是否抽象, 您都只能继承一个类, 但是接口可以实现很多个.

此外抽象类如果实现了接口时, 可以不在当下类中实现具体的方法, 而是留给非抽象的子类去实现.

以下是抽象类的代码:

public class Yi21Runner {
    interface Flyer {
        void fly();
    }
    static abstract class LayEggsAnimal implements Flyer {

        abstract void swim();

        public void hello() {
            System.out.println("Tweet!Tweet!Tweet!");
        }

    }
    static class Duck extends LayEggsAnimal {

        @Override
        public void fly() {
            System.out.println("I can't fly.");
        }

        @Override
        void swim() {
            System.out.println("I can swim");
        }

    }
    public static void main(String[] args) {
        Duck duck = new Duck();
        duck.fly();
        duck.hello();
        duck.swim();
    }
}

上述代码声明了一个, 抽象类  LayEggsAnimal (下蛋的动物), 类本身定义了抽象方法 swim (游泳), 实体方法 hello(). 同时  LayEggsAnimal 实现了 Flyer 接口. 但是我们可以看到 Flayer 的方法 fly() 不必在 LayEggsAnimal 中实现. 最终我们通过具象类 Duck 继承了  LayEggsAnimal 类, 实现了类 LayEggsAnimal 的抽象方法 swim() 以及接口 Flyer 的方法 fly(). 最终的执行结果为:

I can't fly.
Tweet!Tweet!Tweet!
I can swim

以上就是Java 的面向对象的全部内容了.

下一篇请看:Java 的修饰符