oop面向对象编程_Java中的面向对象编程原理:面向初学者的OOP概念

oop面向对象编程

Object-oriented programming offers a sustainable way to write spaghetti code. It lets you accrete programs as a series of patches.

面向对象的编程提供了一种可持续的方式来编写意大利面条式代码。 它使您可以将程序作为一系列补丁来添加。

Object-oriented programming offers a sustainable way to write spaghetti code. It lets you accrete programs as a series of patches.― Paul Graham

面向对象的编程提供了一种可持续的方式来编写意大利面条式代码。 它使您可以将程序作为一系列补丁来添加。 保罗·格雷厄姆

面向对象编程的基础 (Fundamentals of object-oriented programming)

Object-oriented programming is a programming paradigm where everything is represented as an object.

面向对象的编程是一种编程范例,其中所有内容都表示为一个对象。

Objects pass messages to each other. Each object decides what to do with a received message. OOP focuses on each object’s states and behaviors.

对象之间传递消息。 每个对象决定如何处理收到的消息。 OOP专注于每个对象的状态和行为。

什么是物体? (What Are Objects?)

An object is an entity that has states and behaviors.

对象是具有状态和行为的实体。

For example, dog, cat, and vehicle. To illustrate, a dog has states like age, color, name, and behaviors like eating, sleeping, and running.

例如,狗,猫和车辆。 为了说明这一点,狗的年龄,肤色,名字等状态以及进食,睡眠和奔跑等行为都有。

State tells us how the object looks or what properties it has.

状态告诉我们对象的外观或具有的属性。

Behavior tells us what the object does.

行为告诉我们对象的行为。

We can actually represent a real world dog in a program as a software object by defining its states and behaviors.

通过定义程序的状态和行为,我们实际上可以将程序中的现实世界的狗表示为软件对象。

Software objects are the actual representation of real world objects. Memory is allocated in RAM whenever creating a logical object.

软件对象是真实世界对象的实际表示。 每当创建逻辑对象时,都会在RAM中分配内存。

An object is also referred to an instance of a class. Instantiating a class means the same thing as creating an object.

对象也称为类的实例。 实例化一个类与创建一个对象的意思相同。

The important thing to remember when creating an object is: the reference type should be the same type or a super type of the object type. We’ll see what a reference type is later in this article.

创建对象时要记住的重要事项是:引用类型应该与对象类型相同为父类型。 我们将在本文后面看到什么是引用类型。

什么是课程? (What Are Classes?)

A class is a template or blueprint from which objects are created.

类是从中创建对象的模板或蓝图。

Imagine a class as a cookie-cutter and objects as cookies.

想象一个类作为一个cookie切割器,而对象则作为cookie。

Classes define states as instance variables and behaviors as instance methods.

类将状态定义为实例变量,将行为定义为实例方法。

Instance variables are also known as member variables.

实例变量也称为成员变量。

Classes don't consume any space.

类不占用任何空间。

To give you an idea about classes and objects, let's create a Cat class that represents states and behaviors of real world Cat.

为了让您对类和对象有一个了解,让我们创建一个Cat类,该类代表现实世界中Cat的状态和行为。

public class Cat {
    /*
    Instance variables: states of Cat
     */
    String name;
    int age;
    String color;
    String breed;

    /*
    Instance methods: behaviors of Cat
     */
    void sleep(){
        System.out.println("Sleeping");
    }
    void play(){
        System.out.println("Playing");
    }
    void feed(){
        System.out.println("Eating");
    }

}

Now we have successfully defined a template for Cat. Let’s say we have two cats named Thor and Rambo.

现在,我们已经成功地为Cat定义了模板。 假设我们有两只猫叫雷神(Thor)和兰博(Rambo)。

How can we define them in our program?

我们如何在程序中定义它们?

First, we need to create two objects of the Cat class.

首先,我们需要创建Cat类的两个对象。

public class Main {
    public static void main(String[] args) {
       Cat thor = new Cat();
       Cat rambo = new Cat();
    }
}

Next, we’ll define their states and behaviors.

接下来,我们将定义它们的状态和行为。

public class Main {

    public static void main(String[] args) {
       /*
       Creating objects
        */
       Cat thor = new Cat();
       Cat rambo = new Cat();

       /*
       Defining Thor cat
        */
       thor.name = "Thor";
       thor.age = 3;
       thor.breed = "Russian Blue";
       thor.color = "Brown";

       thor.sleep();

       /*
       Defining Rambo cat
        */
       rambo.name = "Rambo";
       rambo.age = 4;
       rambo.breed = "Maine Coon";
       rambo.color = "Brown";

       rambo.play();
    }

}

Like the above code examples, we can define our class, instantiate it (create objects) and specify the states and behaviors for those objects.

像上面的代码示例一样,我们可以定义我们的类,实例化它(创建对象)并指定这些对象的状态和行为。

Now, we have covered the basics of object-oriented programming. Let's move on to the principles of object-oriented programming.

现在,我们已经介绍了面向对象编程的基础知识。 让我们继续进行面向对象编程的原理。

面向对象编程的原理 (Principles of object-oriented programming)

These are the four main principles of the object-oriented programming paradigm. Understanding them is essential to becoming a successful programmer.

这些是面向对象编程范例的四个主要原理。 了解它们对于成为一名成功的程序员至关重要。

  1. Encapsulation

    封装形式
  2. Inheritance

    遗产
  3. Abstraction

    抽象化
  4. Polymorphism

    多态性

Now let's look at each in more detail.

现在,让我们更详细地看看每个。

封装形式 (Encapsulation)

Encapsulation is a process of wrapping code and data together into a single unit.

封装是将代码和数据包装到一个单元中的过程。

It's just like a capsule that contains a mix of several medicines, and is a technique that helps keep instance variables protected.

就像一个包含多种药物的胶囊一样,这是一种有助于保护实例变量的技术。

This can be achieved by using private access modifiers that can’t be accessed by anything outside the class. In order to access private states safely, we have to provide public getter and setter methods. (In Java, these methods should follow JavaBeans naming standards.)

这可以通过使用private访问修饰符来实现,该修饰符不能被类之外的任何人访问。 为了安全地访问私有国家,我们必须提供公共获取和设置方法。 (在Java中,这些方法应遵循JavaBeans命名标准。)

Let’s say there is a record shop that sells music albums of different artists and a stock keeper who manages them.

假设有一家唱片店,出售不同艺术家的音乐专辑,并管理着唱片商。

If you look at figure 4, the StockKeeper class can access the Album class’s states directly as Album class’s states are set to public.

如果您查看图4,由于Album类的状态设置为publicStockKeeper类可以直接访问Album类的状态。

What if the stock keeper creates an album and sets states to negative values? This can be done intentionally or unintentionally by a stock keeper.

如果库存管理员创建相册并将状态设置为负值怎么办? 这可以由库存管理员有意或无意地完成。

To illustrate, let’s see a sample Java program that explains the above diagram and statement.

为了说明这一点,让我们看一个解释上面的图和语句的示例Java程序。

Album class:

专辑类别:

public class Album {
    public String name;
    public String artist;
    public double price;
    public int numberOfCopies;
    public void sellCopies(){
        if(numberOfCopies > 0){
            numberOfCopies--;
            System.out.println("One album has sold!");
        }
        else{
            System.out.println("No more albums available!");
        }
    }
    public void orderCopies(int num){
        numberOfCopies += num;
    }
}

StockKeeper class:

StockKeeper类:

public class StockKeeper {
    public String name;
    public StockKeeper(String name){
        this.name = name;
    }
    public void manageAlbum(Album album, String name, String artist, double price, int numberOfCopies){
      /*
       Defining states and behaviors for album
       */
        album.name = name;
        album.artist = artist;
        album.price = price;
        album.numberOfCopies = numberOfCopies;

       /*
       Printing album details
        */
        System.out.println("Album managed by :"+ this.name);
        System.out.println("Album details::::::::::");
        System.out.println("Album name : " + album.name);
        System.out.println("Album artist : " + album.artist);
        System.out.println("Album price : " + album.price);
        System.out.println("Album number of copies : " + album.numberOfCopies);
    }
}

Main class:

主班:

public class Main {
    public static void main(String[] args) {
       StockKeeper johnDoe = new StockKeeper("John Doe");
       /*
       Stock keeper creates album and assigns negative values for price and number of copies available
        */
       johnDoe.manageAlbum(new Album(), "Slippery When Wet", "Bon Jovi", -1000.00, -50);
    }
}

Output:

输出:

Album managed by :John Doe
Album details::::::::::
Album name : Slippery When Wet
Album artist : Bon Jovi
Album price : -1000.0
Album number of copies : -50

The album’s price and number of copies can’t be negative values. How can we avoid this situation? This is where we use encapsulation.

专辑的价格和份数不能为负值。 我们如何避免这种情况? 这是我们使用封装的地方。

In this scenario, we can block the stock keeper from assigning negative values. If they attempt to assign negative values for the album’s price and number of copies, we’ll assign them as 0.0 and 0.

在这种情况下,我们可以阻止库存管理者分配负值。 如果他们尝试为相册的价格和份数分配负值,我们会将它们分配为0.0和0。

Album class:

专辑类别:

public class Album {
    private String name;
    private String artist;
    private double price;
    private int numberOfCopies;
    public void sellCopies(){
        if(numberOfCopies > 0){
            numberOfCopies--;
            System.out.println("One album has sold!");
        }
        else{
            System.out.println("No more albums available!");
        }
    }
    public void orderCopies(int num){
        numberOfCopies += num;
    }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getArtist() {
      return artist;
   }
   public void setArtist(String artist) {
      this.artist = artist;
   }
   public double getPrice() {
      return price;
   }
   public void setPrice(double price) {
      if(price > 0) {
         this.price = price;          
      }
      else {
         this.price = 0.0;
      }
   }
   public int getNumberOfCopies() {
      return numberOfCopies;
   }
   public void setNumberOfCopies(int numberOfCopies) {
      if(numberOfCopies > 0) {
         this.numberOfCopies = numberOfCopies;        
      }
      else {
         this.numberOfCopies = 0;
      }
   }
}

StockKeeper class:

StockKeeper类:

public class StockKeeper {
    private String name;
    StockKeeper(String name){
        setName(name);
    }
    public void manageAlbum(Album album, String name, String artist, double price, int numberOfCopies){
         /*
          Defining states and behaviors for album
          */
        album.setName(name);
        album.setArtist(artist);
        album.setPrice(price);
        album.setNumberOfCopies(numberOfCopies);
          /*
          Printing album details
           */
        System.out.println("Album managed by :"+ getName());
        System.out.println("Album details::::::::::");
        System.out.println("Album name : " + album.getName());
        System.out.println("Album artist : " + album.getArtist());
        System.out.println("Album price : " + album.getPrice());
        System.out.println("Album number of copies : " + album.getNumberOfCopies());
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

Main class:

主班:

public class Main {
    public static void main(String[] args) {
       StockKeeper johnDoe = new StockKeeper("John Doe");
       /*
       Stock keeper creates album and assigns negative values for price and number of copies available
        */
       johnDoe.manageAlbum(new Album(), "Slippery When Wet", "Bon Jovi", -1000.00, -50);
    }
}

Output:

输出:

Album managed by :John Doe
Album details::::::::::
Album name : Slippery When Wet
Album artist : Bon Jovi
Album price : 0.0
Album number of copies : 0

With encapsulation, we’ve blocked our stock keeper from assigning negative values, meaning we have control over the data.

通过封装,我们阻止了库存管理者分配负值,这意味着我们可以控制数据。

Java封装的优点 (Advantages of encapsulation in Java)

  1. We can make a class read-only or write-only: for a read-only class, we should provide only a getter method. For a write-only class, we should provide only a setter method.

    我们可以将类设为只读 :对于只读类,我们应该仅提供getter方法。 对于只写类,我们应该只提供一个setter方法。

  2. Control over the data: we can control the data by providing logic to setter methods, just like we restricted the stock keeper from assigning negative values in the above example.

    控制数据:我们可以通过向设置方法提供逻辑来控制数据,就像在上面的示例中限制了库存管理者分配负值一样。
  3. Data hiding: other classes can’t access private members of a class directly.

    数据隐藏:其他类无法直接访问类的私有成员。

遗产 (Inheritance )

Let’s say that the record shop we discussed above also sells Blu-ray movies.

假设我们上面讨论的唱片店也出售蓝光电影。

As you can see in the above diagram, there are many common states and behaviors (common code) between Album and Movie.

如上图所示, AlbumMovie之间有许多常见的状态和行为(通用代码)。

When implementing this class diagram into code, are you going to write (or copy & paste) the entire code for Movie? If you do, you are repeating yourself. How can you avoid code duplication?

在代码中实现此类图时,是否要编写(或复制并粘贴) Movie的整个代码? 如果这样做,您就是在重复自己。 如何避免代码重复?

This is where we use inheritance.

这是我们使用继承的地方。

Inheritance is a mechanism in which one object acquires all the states and behaviors of a parent object.

继承是一种机制,其中一个对象获取父对象的所有状态和行为。

Inheritance uses a parent-child relationship (IS-A relationship).

继承使用父子关系(IS-A关系)。

那么到底是什么继承了呢? (So what exactly is inherited?)

Visibility/access modifiers impact what gets inherited from one class to another.

可见性/访问修饰符会影响从一个类继承到另一类的内容。

In Java, as a rule of thumb we make instance variables private and instance methods public .

在Java中,根据经验,我们将实例变量设为private并将实例方法设为public

In this case, we can safely say that the following are inherited:

在这种情况下,我们可以肯定地说以下内容是继承的:

  1. public instance methods.

    公共实例方法。
  2. private instance variables (private instance variables can be accessed only through public getter and setter methods).

    私有实例变量(只能通过public getter和setter方法访问私有实例变量)。

Java中的继承类型 (Types of Inheritance in Java)

There are five types of inheritance in Java. They are single, multilevel, hierarchical, multiple, and hybrid.

Java有五种继承类型。 它们是单层,多层,分层,多层和混合型。

Class allows single, multilevel and hierarchical inheritances. Interface allows multiple and hybrid inheritances.

类允许单,多级和分层继承。 接口允许多重继承和混合继承。

A class can extend only one class however it can implement any number of interfaces. An interface can extend more than one interfaces.

一个类只能扩展一个类,但是它可以实现任何数量的接口。 一个接口可以扩展多个接口。

人际关系 (Relationships)

I. IS-A relationship

一,IS-A关系

An IS-A relationship refers to inheritance or implementation.

IS-A关系是指继承或实现。

一个。 概括 (a. Generalization)

Generalization uses an IS-A relationship from a specialization class to generalization class.

泛化使用从专门化类到泛化类的IS-A关系。

二。 HAS-A关系 (II. HAS-A relationship)

An instance of one class HAS-A reference to an instance of another class.

一个类的实例HAS-A引用另一个类的实例。

一个。 聚合 (a. Aggregation)

In this relationship, the existence of class A and B are not dependent on each other.

在这种关系中,A类和B类的存在并不相互依赖。

For this aggregation part, we going to see an example of the Student class and the ContactInfo class.

对于此聚合部分,我们将看到Student类和ContactInfo类的示例。

class ContactInfo {
    private String homeAddress;
    private String emailAddress;
    private int telephoneNumber; //12025550156
}
public class Student {
    private String name;
    private int age;
    private int grade;
    private ContactInfo contactInfo;//Student HAS-A ContactInfo
    public void study() {
        System.out.println("Study");
    }
}

Student HAS-A ContactInfo. ContactInfo can be used in other places – for example, a company's Employee class can also use this ContactInfo class. So Student can exist without ContactInfo and ContactInfo can exist without Student . This type of relationship is known as aggregation.

Student HAS-A ContactInfoContactInfo可以在其他地方使用-例如,公司的Employee类也可以使用此ContactInfo类。 因此Student可以不使用ContactInfo而存在,而ContactInfo可以不使用Student而存在。 这种类型的关系称为聚合。

b。 组成 (b. Composition)

In this relationship, class B can not exist without class A – but class A can exist without class B.

在这种关系中,没有A类就不能存在B类,但是没有B类就可以存在A类。

To give you an idea about composition, let's see an example of the Student class and the StudentId class.

为了让您对构图有所了解,让我们看一下Student类和StudentId类的示例。

class StudentId {
    private String idNumber;//A-123456789
    private String bloodGroup;
    private String accountNumber;
}
public class Student {
    private String name;
    private int age;
    private int grade;
    private StudentId studentId;//Student HAS-A StudentId
    public void study() {
        System.out.println("Study");
    }
}

Student HAS-A StudentId. Student can exist without StudentId but StudentId can not exist without Student. This type of relationship is known as composition.

Student HAS-A StudentId 。 没有StudentId Student可以存在,但是没有Student StudentId不能存在。 这种关系称为组合。

Now, let’s back to our previous record shop example that we discussed above.

现在,让我们回到上面讨论的以前的唱片店示例。

We can implement this diagram in Java to avoid code duplication.

我们可以用Java实现此图,以避免代码重复。

继承的优点 (Advantages of inheritance)
  1. Code reuse: the child class inherits all instance members of the parent class.

    代码重用:子类继承父类的所有实例成员。
  2. You have more flexibility to change code: changing code in place is enough.

    您可以更灵活地更改代码:在适当的位置更改代码就足够了。
  3. You can use polymorphism: method overriding requires IS-A relationship.

    您可以使用多态:方法覆盖需要IS-A关系。

抽象化 (Abstraction)

Abstraction is a process of hiding the implementation details and showing only functionality to the user.

抽象是隐藏实现细节并仅向用户显示功能的过程。

A common example of abstraction is that pressing the accelerator will increase the speed of a car. But the driver doesn’t know how pressing the accelerator increases the speed – they don't have to know that.

一个常见的抽象示例是,按下加速器将提高汽车的速度。 但是驾驶员不知道踩油门踏板会如何提高速度–他们不必知道。

Technically abstract means something incomplete or to be completed later.

从技术上讲,抽象意味着不完整的东西或将在以后完成的东西。

In Java, we can achieve abstraction in two ways: abstract class (0 to 100%) and interface (100%).

在Java中,我们可以通过两种方式实现抽象:抽象类(0到100%)和接口(100%)。

The keyword abstract can be applied to classes and methods. abstract and final or static can never be together.

关键字abstract可以应用于类和方法。 abstractfinalstatic永远不能在一起。

一,抽象类 (I. Abstract class)

An abstract class is one that contains the keyword abstract.

抽象类是包含关键字abstract

Abstract classes can’t be instantiated (can’t create objects of abstract classes). They can have constructors, static methods, and final methods.

抽象类无法实例化(无法创建抽象类的对象)。 它们可以具有构造函数,静态方法和最终方法。

二。 抽象方法 (II. Abstract methods)

An abstract method is one that contains the keyword abstract.

抽象方法是一种包含关键字abstract

An abstract method doesn’t have implementation (no method body and ends up with a semi colon). It shouldn’t be marked as private.

抽象方法没有实现(没有方法主体,并且以半冒号结尾)。 不应将其标记为private

三, 抽象类和抽象方法 (III. Abstract class and Abstract methods)
  • If at least one abstract method exists inside a class then the whole class should be abstract.

    如果一个类中至少存在一个抽象方法,则整个类应该是抽象的。
  • We can have an abstract class with no abstract methods.

    我们可以有一个没有抽象方法的抽象类。
  • We can have any number of abstract as well as non-abstract methods inside an abstract class at the same time.

    我们可以在一个抽象类中同时拥有任意数量的抽象方法以及非抽象方法。
  • The first concrete sub class of an abstract class must provide implementation to all abstract methods.

    抽象类的第一个具体子类必须为所有抽象方法提供实现。
  • If this doesn't happen, then the sub class also should be marked as abstract.

    如果没有发生,则子类也应标记为抽象。

In a real world scenario, the implementation will be provided by someone who is unknown to end users. Users don’t know the implementation class and the actual implementation.

在现实世界中,实现将由最终用户未知的人员提供。 用户不知道实现类和实际实现。

Let’s consider an example of abstract concept usage.

让我们考虑一个抽象概念用法的示例。

abstract class Shape {
    public abstract void draw();
}
class Circle extends Shape{
    public void draw() {
        System.out.println("Circle!");
    }
}
public class Test {
    public static void main(String[] args) {
        Shape circle = new Circle();
        circle.draw();
    }
}
我们什么时候要将一个类标记为抽象? (When do we want to mark a class as abstract?)
  1. To force sub classes to implement abstract methods.

    强制子类实现抽象方法。
  2. To stop having actual objects of that class.

    停止拥有该类的实际对象。
  3. To keep having a class reference.

    保持有班级参考。
  4. To retain common class code.

    保留通用的类代码。

接口 (Interface)

An interface is a blueprint of a class.

接口是类的蓝图。

An interface is 100% abstract. No constructors are allowed here. It represents an IS-A relationship.

接口是100%抽象的。 此处不允许使用构造函数。 它表示IS-A关系。

NOTE: Interfaces only define required methods. We can not retain common code.

注意:接口仅定义必需的方法。 我们无法保留通用代码。

An interface can have only abstract methods, not concrete methods. By default, interface methods are public and abstract. So inside the interface, we don’t need to specify public and abstract.

接口只能具有抽象方法,而不能具有具体方法。 默认情况下,接口方法是publicabstract 。 因此,在界面内部,我们无需指定publicabstract

So when a class implements an interface’s method without specifying the access level of that method, the compiler will throw an error stating “Cannot reduce the visibility of the inherited method from interface”. So that implemented method’s access level must be set to public.

因此,当一个类在未指定该方法的访问级别的情况下实现该接口的方法时,编译器将引发错误,指出“Cannot reduce the visibility of the inherited method from interface” 。 因此,必须将实现的方法的访问级别设置为public

By default, interface variables are public, static and final.

默认情况下,接口变量是publicstaticfinal

For instance:

例如:

interface Runnable {
    int a = 10; //similar to: public static final int a = 10;
    void run(); //similar to: public abstract void run();
}
public class InterfaceChecker implements Runnable{
    public static void main(String[] args) {
        Runnable.a = 5;//The final field Runnable.a cannot be assigned.
    }
}

Let’s see an example that explains the interface concept:

让我们看一个解释界面概念的示例:

interface Drawable {
    void draw();
}
class Circle implements Drawable{
    public void draw() {
        System.out.println("Circle!");
    }
}
public class InterfaceChecker {
    public static void main(String[] args) {
        Drawable circle = new Circle();
        circle.draw();
    }
}
接口中的默认方法和静态方法 (Default and Static methods in Interfaces)

Usually we implement interface methods in a separate class. Let’s say we are required to add a new method in an interface. Then we must implement that method in that separate class, too.

通常,我们在单独的类中实现接口方法。 假设我们需要在接口中添加新方法。 然后,我们也必须在单独的类中实现该方法。

To overcome this issue Java 8 introduced default and static methods that implement methods inside an interface, unlike abstract methods.

为了克服这个问题,Java 8引入了默认和静态方法,这些方法在接口内部实现方法,这与抽象方法不同。

  • Default method

    默认方式

public interface DefaultInterface {
    void sleep();
    default void run() {
        System.out.println("I'm running!");
    }
}
public class InterfaceCheckers implements DefaultInterface{
    public void sleep() {
        System.out.println("Sleeping...");
    }
    public static void main(String[] args) {
        InterfaceCheckers checker = new InterfaceCheckers();
        checker.run();
        checker.sleep();
    }
}
/*
Output:
I'm running!
Sleeping...
 */
  • Static method

    静态方法

Similar to static methods of classes, we can call them by their interface’s name.

与类的静态方法类似,我们可以通过它们的接口名称来调用它们。

public interface DefaultInterface {
    void sleep();
    static void run() {
        System.out.println("I'm running!");
    }
}
public class InterfaceCheckers implements DefaultInterface{
    public void sleep() {
        System.out.println("Sleeping...");
    }
    public static void main(String[] args) {
        InterfaceCheckers checker = new InterfaceCheckers();
        DefaultInterface.run();
        checker.sleep();
    }
}
/*
Output:
I'm running!
Sleeping...
 */
  • Marker interface

    标记界面

It’s an empty interface. For instance, Serializable, Cloneable, and Remote interfaces.

这是一个空接口。 例如,可序列化,可克隆和远程接口。

public interface Serializable 
{
  //No fields or methods
}

接口的优点 (Advantages of interfaces)

  • They help us use multiple inheritance in Java.

    它们帮助我们在Java中使用多重继承。
  • They provide abstraction.

    它们提供抽象。
  • They provide loose coupling: objects are independent from one another.

    它们提供松散的耦合:对象彼此独立。

什么时候要将类更改为接口? (When do we want to change a class to an interface?)

  1. To force sub classes to implement abstract methods.

    强制子类实现抽象方法。
  2. To stop having actual objects of that class.

    停止拥有该类的实际对象。
  3. To keep having a class reference.

    保持有班级参考。

NOTE: Remember, we can’t retain common code inside the interface.

注意:请记住,我们不能在界面内保留通用代码。

If you want to define potentially required methods and common code, use an abstract class.

如果要定义可能需要的方法和通用代码,请使用抽象类

If you just want to define a required method, use an interface.

如果您只想定义必需的方法,请使用interface

多态性 (Polymorphism)

Polymorphism is the ability of an object to take on many forms.

多态是对象采取多种形式的能力。

Polymorphism in OOP occurs when a super class references a sub class object.

当超类引用子类对象时,OOP中会发生多态。

All Java objects are considered to be polymorphic as they share more than one IS-A relationship (at least all objects will pass the IS-A test for their own type and for the class Object).

所有Java对象都具有多个IS-A关系(至少所有对象将针对其自身类型和Object类通过IS-A测试),因此被视为多态的。

We can access an object through a reference variable. A reference variable can be of only one type. Once declared, the type of a reference variable cannot be changed.

我们可以通过引用变量访问对象。 参考变量只能是一种类型。 声明后,引用变量的类型无法更改。

A reference variable can be declared as a class or interface type.

引用变量可以声明为类或接口类型。

A single object can be referred to by reference variables of many different types as long as they are the same type or a super type of the object.

单个对象可以由许多不同类型的引用变量引用,只要它们是对象的相同类型超类型即可

方法重载 (Method overloading)

If a class has multiple methods that have same name but different parameters, this is known as method overloading.

如果一个类具有名称相同但参数不同的多个方法,则称为方法重载。

Method overloading rules:

方法重载规则:

  1. Must have a different parameter list.

    必须具有不同的参数列表。

  2. May have different return types.

    可能有不同的返回类型。
  3. May have different access modifiers.

    可能具有不同的访问修饰符。
  4. May throw different exceptions.

    可能会引发不同的异常。
class JavaProgrammer{
    public void code() {
        System.out.println("Coding in C++");
    }
    public void code(String language) {
        System.out.println("Coding in "+language);
    }
}
public class MethodOverloader {
    public static void main(String[] args) {
        JavaProgrammer gosling = new JavaProgrammer();
        gosling.code();
        gosling.code("Java");
    }
}
/*
Output:
Coding in C++
Coding in Java
 */

NOTE: Static methods can also be overloaded.

注意:静态方法也可以重载。

class Addition {
    public static int add(int a,int b) {
        return a+b;
    }
    public static int add(int a,int b,int c) {
        return a+b+c;
    }
}
public class PolyTest {
    public static void main(String[] args) {
        System.out.println(Addition.add(5, 5));
        System.out.println(Addition.add(2, 4, 6));
    }
}

NOTE: We can overload the main() method but the Java Virtual Machine (JVM) calls the main() method that receives String arrays as arguments.

注意:我们可以重载main()方法,但是Java虚拟机(JVM)调用main()方法,该方法接收String数组作为参数。

public class PolyTest {
    public static void main() {
        System.out.println("main()");
    }
    public static void main(String args) {
        System.out.println("String args");
    }
    public static void main(String[] args) {
        System.out.println("String[] args");
    }
}
//Output: String[] args

多态性要遵循的规则 (Rules to follow for polymorphism)

编译时间规则 (Compile time rules)
  1. Compiler only knows reference type.

    编译器仅知道引用类型。
  2. It can only look in reference type for methods.

    它只能在引用类型中查找方法。
  3. Outputs a method signature.

    输出方法签名。
运行时间规则 (Run time rules)
  1. At runtime, JVM follows exact runtime type (object type) to find method.

    在运行时,JVM遵循确切的运行时类型(对象类型)来查找方法。

  2. Must match compile time method signature to method in actual object’s class.

    必须将编译时方法签名与实际对象类中的方法匹配。

方法覆盖 (Method overriding)

If a subclass has the same method as declared in the super class, this is known as method overriding.

如果子类具有与超类中声明的方法相同的方法,则称为方法重写。

Method overriding rules:

方法覆盖规则:

  1. Must have the same parameter list.

    必须具有相同的参数列表。
  2. Must have the same return type: although a covariant return allows us to change the return type of the overridden method.

    必须具有相同的返回类型:尽管协变返回允许我们更改覆盖方法的返回类型。
  3. Must not have a more restrictive access modifier: may have a less restrictive access modifier.

    不得具有限制性更强的访问修饰符:可以具有限制性更小的访问修饰符。
  4. Must not throw new or broader checked exceptions: may throw narrower checked exceptions and may throw any unchecked exception.

    不得引发新的或更广泛的检查异常:可以引发较窄的检查异常,并且可以引发任何未检查的异常。
  5. Only inherited methods may be overridden (must have IS-A relationship).

    只能重写继承的方法(必须具有IS-A关系)。

Example for method overriding:

方法覆盖的示例:

public class Programmer {
    public void code() {
        System.out.println("Coding in C++");
    }
}
public class JavaProgrammer extends Programmer{
    public void code() {
        System.out.println("Coding in Java");
    }
}
public class MethodOverridder {
    public static void main(String[] args) {
        Programmer ben = new JavaProgrammer();
        ben.code();
    }
}
/*
Output:
Coding in Java
 */

NOTE: Static methods can’t be overridden because methods are overridden at run time. Static methods are associated with classes while instance methods are associated with objects. So in Java, the main() method also can’t be overridden.

注意:静态方法不能被覆盖,因为方法在运行时被覆盖。 静态方法与类相关联,而实例方法与对象相关联。 因此,在Java中, main()方法也不能被覆盖。

NOTE: Constructors can be overloaded but not overridden.

注意:构造函数可以重载,但不能覆盖。

对象类型和引用类型 (Object types and reference types)

class Person{
    void eat() {
        System.out.println("Person is eating");
    }
}
class Student extends Person{
    void study() {
        System.out.println("Student is studying");
    }
}
public class InheritanceChecker {
    public static void main(String[] args) {
        Person alex = new Person();//New Person "is a" Person
        alex.eat();
        Student jane = new Student();//New Student "is a" Student
        jane.eat();
        jane.study();
        Person mary = new Student();//New Student "is a" Person
        mary.eat();
        //Student chris = new Person(); //New Person isn't a Student.
    }
}

In Person mary = new Student(); , this object creation is perfectly fine.

Person mary = new Student(); ,此对象创建就很好。

mary is a Person type reference variable and new Student() will create a new Student object.

mary是一个Person类型的引用变量,并且new Student()将创建一个新的Student对象。

mary can’t access study() in compile time because the compiler only knows the reference type. Since there is no study() in the reference type class, it can’t access it. But in runtime mary is going to be the Student type (Runtime type/ object type).

mary在编译时无法访问study() ,因为编译器仅知道引用类型。 由于引用类型类中没有study() ,因此无法访问它。 但是在运行时中, mary将是Student类型(运行时类型/对象类型)。

Please review this post for more information on runtime types.

请查看此文章以获取有关运行时类型的更多信息。

In this case, we can convince the compiler by saying “at runtime, mary will be Student type, so please allow me to call it”. How can we convince the compiler like this? This is where we use casting.

在这种情况下,我们可以说“在运行时maryStudent类型,因此请允许我调用它”来说服编译器。 我们怎样才能说服这样的编译器? 这是我们使用投射的地方。

We can make mary a Student type in compile time and can call study() by casting it.

我们可以使mary在编译时成为Student类型,并可以通过强制转换来调用study()

((Student)mary).study();

We’ll learn about casting next.

接下来,我们将介绍铸造。

对象类型转换 (Object type casting)

Java type casting is classified into two types:

Java类型转换分为两种类型:

  1. Widening casting (implicit): automatic type conversion.

    加宽转换(隐式):自动类型转换。
  2. Narrowing casting (explicit): need explicit conversion.

    缩小转换(显式):需要显式转换。

In primitives, long is a larger type than int . Like in objects, the parent class is a larger type than the child class.

在基元中, long是比int大的类型。 像在对象中一样,父类的类型比子类大。

The reference variable only refers to an object. Casting a reference variable doesn’t change the object on the heap but it labels the same object in another way by means of instance members accessibility.

引用变量仅引用对象。 强制转换引用变量不会更改堆上的对象,但会通过实例成员可访问性以另一种方式标记同一对象。

I. Widening casting

一,拓宽铸造

Superclass superRef = new Subclass();

II. Narrowing casting

二。 缩小铸造

Subclass ref = (Subclass) superRef;

We have to be careful when narrowing. When narrowing, we convince the compiler to compile without any error. If we convince it wrongly, we will get a run time error (usually ClassCastException).

缩小范围时必须小心。 缩小范围时,我们说服编译器进行编译而不会出现任何错误。 如果我们错误地说服它,则会收到运行时错误(通常是ClassCastException )。

In order to perform narrowing correctly, we use the instanceof operator. It checks for an IS-A relationship.

为了正确执行缩小,我们使用instanceof运算符。 它检查IS-A关系。

class A {
    public void display(){
        System.out.println("Class A");
    }
}

class B extends A{
    public void display(){
        System.out.println("Class B");
    }
}

public class Test {
    public static void main(String[] args) {
        A objA = new B();
        if(objA instanceof B){
            ((B)objA).display();
        }
    }
}
/**
 * Output: Class B
 */

As I already stated before, we must remember one important thing when creating an object using the new keyword: the reference type should be the same type or a super type of the object type.

如前所述,在使用new关键字创建对象时,我们必须记住一件重要的事情:引用类型应该是对象类型的相同类型类型。

结论 (Conclusion)

Thank you everyone for reading. I hope this article helped you.

谢谢大家阅读。 希望本文对您有所帮助。

I strongly encourage you to read more related articles on OOP.

我强烈建议您阅读有关OOP的更多相关文章。

Checkout my original article series on Medium: Object-oriented programming principles in Java

查阅我有关“媒介: Java中的面向对象的编程原理”的原始文章系列。

Please feel free to let me know if you have any questions.

如有任何疑问,请随时告诉我。

Dream is not that which you see while sleeping it is something that does not let you sleep.

梦不是您睡觉时看到的东西,它是无法让您睡觉的东西。

A P J Abdul Kalam, Wings of Fire: An Autobiography

APJ Abdul Kalam,《火翼:自传》

Thank you.

谢谢。

Happy Coding!

编码愉快!

翻译自: https://www.freecodecamp.org/news/java-object-oriented-programming-system-principles-oops-concepts-for-beginners/

oop面向对象编程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值