CodeGym/Java 博客/随机的/Java 中的 OOP 概念
John Squirrels
第 41 级
San Francisco

Java 中的 OOP 概念

已在 随机的 群组中发布
个会员
Java 的最大优势之一是面向对象编程 (OOP)。这就是为什么这种语言变得如此流行并且非常适合任何规模的项目的原因。什么是面向对象编程?这不是魔法,但如果你真的投入其中,它会看起来很神奇。OOP 是关于如何构建软件的。它是一个概念,或者更确切地说是 Java 中的一堆 oop 概念,允许您在 Java 对象之间创建一些特定的交互和关系,以便有效地开发和使用软件。Java 中的 OOP 概念 - 1经典 OOP 包括 3 + 1 个主要概念。让我们从经典开始。

物体

Java 对象和真实世界的对象一样具有两个特征:状态和行为。

例如,一个 Human 对象具有状态(姓名、性别、是否睡觉……)和行为(学习 Java、散步、谈话……)。任何 Java 对象都将其状态存储在字段中,并通过方法公开其行为。

封装

数据封装是对外部世界隐藏内部数据,并且只能通过公开暴露的方法访问它。这意味着什么?什么数据?躲着谁?隐藏意味着限制对类的数据成员(字段)的直接访问。

它在 Java 中是如何工作的:

  1. 字段设为私有
  2. 类中的每个字段都有两个特殊方法:getter 和 setter。Getter 方法返回字段的值。Setter 方法允许您以间接但允许的方式更改字段的值。

Java代码封装示例:

public class Student {
private int age;
private String name;

public int getAge() {
return age;
}

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

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

public class Test{
public static void main(String[] args) {
Student firstStudent = new Student();
firstStudent.setName("John");
// The name field is private, so you can no longer do this:  firstStudent.name = "John";
}
}

为什么要使用封装?

主要原因是为了更容易更改代码。假设您有一个曲棍球学校的申请,并且有一个HockeyStudent类,其中有两个字段存储学生的姓名和他或她在学校注册时的年龄。是这样的:
public class HockeyStudent {
public String name;
public  int ageOfEnrollment;
}
ageOfEnrollment字段是公共的,没有 getter 或 setter……这个类被许多其他类使用,一切正常,直到一些开发人员认为单个 int 字段不够用。队列中的一些曲棍球运动员比同龄人大将近一岁,因此根据他们的出生月份将他们分成两组会更方便。所以ageOfEnrollment字段应该更改为一个int 数组 (int[][]):第一个数字是完整的年份,第二个是月份。现在你需要重构所有使用Student类的代码!但是如果你的ageOfEnrollmentfield 是私有的,你有 getters 和 setters,那么一切就更容易了。如果设置学生年龄的要求发生变化,只需更新setAgeOfEnrollment() setter 方法中的逻辑,您的班级就可以继续使用Student而不会出现任何问题!这个例子有点做作,但我希望它能解释为什么使用封装是个好主意。

遗产

即使没有任何实践经验,这个原理也更容易理解。不要重复自己 (DRY) 可能是继承概念的座右铭。继承使您可以创建子类,该子类继承父类的字段和方法而无需重新定义它们。当然,你可以在子类中覆盖父类的字段和方法,但这不是必须的。更重要的是,您可以在子类中添加新的状态和行为。父类有时称为超类或基类,子类称为子类。Java的extends关键字就是用来在代码中实现继承原理的。

它在 Java 中是如何工作的:

  1. 创建父类。
  2. 使用extends关键字创建子类。
  3. 在 Child 类的构造函数中,使用super(parentField1, parentField2, ...)方法设置父类的字段。

构造函数是用于初始化新创建的对象的特殊方法。构造函数与其类名同名。有两种类型的构造函数:默认(无参数构造函数)和参数化构造函数。一个类必须至少有一个构造函数(如果没有定义其他构造函数,它有默认构造函数)并且它可以有很多。

每次创建新对象时,都会调用其构造函数。在上面的示例中,您在这一行中执行此操作:

Student firstStudent = new Student();

您使用new关键字来调用Student类的默认构造函数:tudent()

一些规则:

  1. 一个班级只能有一个父级。
  2. 一个父类可以有多个子类。
  3. 子类可以有自己的子类。

Java代码中的继承示例

让我们创建一个电话类。
public class Phone {
    int price;
    double weight;

// Constructor
public Phone(int price, double weight) {
        this.price = price;
        this.weight = weight;
    }

    void orderPhone(){
        System.out.println("Ordering phone...");
    }
}
当然,有不同类型的手机,所以让我们创建两个子类:一个用于 Android 手机,另一个用于 iPhone。然后我们将添加一些父级没有的字段和方法。我们将使用super()来调用构造函数来初始化父类确实具有的字段。

Java中的继承示例

public class Android extends Phone {

// Some new fields
String androidVersion;
int screenSize;

    String secretDeviceCode;

// Constructor
    public Android(int price, double weight, String androidVersion, int screenSize, String secretDeviceCode) {
        super(price, weight); // Android inherits Phone’s fields

        //this - reference to the current object
        //super - reference to the parent object

        this.androidVersion = androidVersion;
        this.screenSize = screenSize;
        this.secretDeviceCode = secretDeviceCode;
    }

	// New Android-specific method, does not exist in the Phone class
    void installNewAndroidVersion() {
        System.out.println("installNewAndroidVersion invoked...");

    }

}

public class IPhone extends Phone {

    boolean fingerPrint;

    public IPhone(int price, double weight, boolean fingerPrint) {
        super(price, weight);
        System.out.println("IPhone constructor was invoked...");
        this.fingerPrint = fingerPrint;
    }

    void deleteIPhoneFromDb() {
        System.out.println("deleteIPhoneFromDb invoked...");
    }

@Override // This is about polymorphism, see below
void orderPhone(){
        System.out.println("Ordering my new iPhone and deleting the old one...");
    }
}
因此,重复一遍:在 Java 中,继承允许您使用继承父类的字段和方法的子类来扩展一个类。这是实现代码可重用性的绝佳方式。

多态性

多态性是对象变形的能力,采用不同的形式或以不同的方式起作用。在 Java 中,多态性通常发生在使用父类引用来引用子类对象时。

这意味着什么以及它在 Java 中的工作原理:

Java 中的多态性是什么?通常,这意味着您可以为不同的目的使用相同的方法名称。Java中有两种多态:方法覆盖(动态多态)和方法重载(静态多态)。

方法覆盖

您可以在子类中覆盖父类的方法,强制它以不同的方式工作。让我们用play()方法创建一个Musician父类。

Java代码中的多态性示例

public class Musician {
    String name;
    int age;

    // Default constructor
    public Musician() {
    }

    // Parameterized constructor
    public Musician(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void play() {
        System.out.println("I am playing my instrument...");
    }
}
不同的音乐家使用不同的乐器。让我们创建两个子类:PianistViolinist。多亏了多态性,每个人都会执行自己版本的play()方法。覆盖时,可以使用@Override注解,但不是必须的。
public class Pianist extends Musician {

    String favoritePianoType;

    public Pianist(String name, int age, String favoritePianoType) {
        super(name, age);
        this.favoritePianoType = favoritePianoType;
    }


    @Override
void play(){
        System.out.println("I am playing the piano...");
    }
}
小提琴手可以是独奏者或管弦乐队的成员。让我们在覆盖play()方法时考虑到这一点。
public class Violinist extends Musician {
    boolean isSoloist;

public Violinist(String name, int age, boolean isSoloist) {
            super(name, age);
            this.isSoloist = isSoloist;
        }


    @Override
void play(){
if (isSoloist)
        System.out.println("I am playing the violin solo...");
else
System.out.println("I am playing the violin in an orchestra...");

    }
}
让我们创建一个Demo类,我们将在其中创建三个对象,每个对象是之前创建的类的一个实例。我们会看到我们得到什么结果。
public class Demo {
  public static void main(String[] args) {
  Musician musician = new Musician();
  Violinist violinist = new Violinist("John", 32, true);
  Pianist pianist = new Pianist("Glen", 30, "Acoustic");

  System.out.println("Musician said:");
  musician.play();
  System.out.println("Violinist said:");
  violinist.play();
  System.out.println("Pianist said:");
  pianist.play();
    }
}
这是我们得到的:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo…
Pianist said:
I am playing the piano...
每个小提琴家和钢琴家都是音乐家,但不是每个音乐家都是小提琴家或钢琴家。这意味着如果您不需要创建新的演奏方法,您可以使用音乐家的演奏方法。或者您可以使用super关键字从子项调用父项的方法。让我们在 Pianist 的代码中这样做:
public class Pianist extends Musician {

    String favoritePianoType;

    @Override
    void play(){
        super.play();
        System.out.println("I am playing the piano...");
    }
}
现在让我们在Demo类中调用我们的main()方法。结果如下:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...

方法重载

方法重载是指在同一个类中使用不同的同名方法。它们在参数的数量、顺序或类型方面必须不同。假设一位钢琴家可以弹奏原声钢琴和电钢琴。要演奏电子琴,音乐家需要电。让我们创建两个不同的play()方法。第一个没有参数,用于原声钢琴,第二个带有指示是否可用的参数。
public class Pianist extends Musician {

    String name;
    int age;
    String favoritePianoType;

    @Override
    void play(){
        super.play();
        System.out.println("I am playing the piano...");
    }
    void play(boolean isElectricity){
        if (isElectricity) {
            System.out.println("The electricity is on.");
            System.out.println("I am playing the piano...");
        }
        else System.out.println("I can't play this without electricity.");
    }
}
顺便说一下,您可以通过这种方式在第二个play(boolean)方法中使用第一个play()方法:
void play(boolean isElectricity){
        if (isElectricity) {
            System.out.println("The electricity is on.");
            play();
        }
        else System.out.println("I can't play this without electricity.");
    }
让我们在Demo类中添加一些行来演示我们的重载:
public class Demo {
    public static void main(String[] args) {

        Musician musician = new Musician();
        Violinist violinist = new Violinist("John", 23, true);
        Pianist pianist = new Pianist("Glen", 30, "Acoustic");

        System.out.println("Musician said:");
        musician.play();
        System.out.println("Violinist said:");
        violinist.play();
        System.out.println("Pianist said:");
        pianist.play();
        System.out.println("The pianist will now try the electric piano:");
        pianist.play(true);
        System.out.println("The electricity has been shut off. Now when trying the electric piano, the pianist says:");
        pianist.play(false);
    }
}
这是结果:
Musician said:
I am playing my instrument...
Violinist said:
I am playing the violin solo...
Pianist said:
I am playing my instrument...
I am playing the piano...
The pianist will now try the electric piano:
The electricity is on.
I am playing my instrument...
I am playing the piano...
The electricity has been shut off. Now when trying the electric piano, the pianist says:
I can't play this without electricity.
Java 根据其参数和对象类型知道应该使用哪个方法。这就是多态。

抽象

当我们定义一个类时,我们正在尝试构建某种事物的模型。例如,假设我们正在用不同的赛车编写一个名为 MyRacer 的视频游戏。玩家可以选择其中之一,然后更新它或购买不同的。那么……什么是汽车?汽车是一件相当复杂的事情,但如果我们正在尝试创建赛车视频游戏(而不是驾驶模拟器),那么我们不需要描述它包含的所有数千个齿轮和垫圈。我们需要它的型号、最高速度、机动性、价格、颜色……也许这就足够了。这是我们游戏的汽车模型。稍后在 MyRacer 2 中,假设我们决定添加影响道路操控性的轮胎。这里的模型不同,因为我们添加了更多细节。让' s 将数据抽象定义为仅识别对象的重要(或必要)特征并忽略任何不相关细节的过程。有不同层次的抽象。例如,如果您是公共汽车上的乘客,您需要知道您的公共汽车长什么样以及它要去哪里,但您不需要知道如何驾驶它。如果您是公交车司机,您不需要知道如何创建一辆新公交车——您只需要知道如何驾驶它。但是如果你是一个总线制造商,你需要去更底层的抽象层次,因为总线设计的细节对你来说非常重要。我希望你明白我的意思。您需要知道您的公共汽车长什么样以及它要去哪里,但您不需要知道如何驾驶它。如果您是公交车司机,您不需要知道如何创建一辆新公交车——您只需要知道如何驾驶它。但是如果你是一个总线制造商,你需要去更底层的抽象层次,因为总线设计的细节对你来说非常重要。我希望你明白我的意思。您需要知道您的公共汽车长什么样以及它要去哪里,但您不需要知道如何驾驶它。如果您是公交车司机,您不需要知道如何创建一辆新公交车——您只需要知道如何驾驶它。但是如果你是一个总线制造商,你需要去更底层的抽象层次,因为总线设计的细节对你来说非常重要。我希望你明白我的意思。

它在 Java 中是如何工作的:

让我们在 Java 或 OOP 中构建四个抽象级别 — 从最低(最具体)到最高(最抽象)。
  1. 最低的抽象层次是一个特定的对象。它是具有一组属于特定类别的特征的实体。它具有特定的字段值

  2. 用于创建对象的模板是一个类。它是对一组具有相似属性和内部结构的对象的描述。

  3. 抽象类是对一组类的特性的抽象描述(它作为其他类继承的模板)。它具有很高的抽象层次,所以不可能直接从一个抽象类中创建对象。只有抽象类的子类可以用来创建对象。抽象类可以包含具有实现的方法,但这不是必需的。

  4. 接口是 Java 编程语言构造的构造,它仅包含抽象公共方法和静态常量字段(最终静态)。也就是说,抽象类和接口都不能用来生成对象。

顺便说一句,在 Java 8 或更高版本中,接口不仅可以有抽象方法和常量,还可以有默认方法和静态方法。在 Java 中,接口定义行为,而抽象类用于创建层次结构。一个接口可以由多个类实现。

Java 代码中的接口示例

interface Human {
	public void struggle();
	public void protect();
}

interface Vulcan {
	int angleOfPointyEars;
	public void turnOffEmotions(boolean isOn);
	public void telepathy();
}
您可以实现多个接口
The Spock class implements Human and Vulcan {
public void struggle() {
System.out.println("I am struggling...");
}
	public void protect() {
System.out.println("You are under my protection!);
}
public void turnOffEmotions(boolean isOn){
If (isOn) {
System.out.println("I am turning off my emotions.");
isOn= !isOn;
}
}
	public void telepathy() {
System.out.println("Connecting to your brain...");
}

}
对于初学者,它涵盖了 Java 中面向对象编程的所有主要概念。除了 4 个主要的 OOP 原则外,Java 还有关联、聚合和组合。您可以称它们为“附加的 OOP 原则”。他们值得拥有自己的单独文章。
评论
  • 受欢迎
你必须先登录才能发表评论
此页面还没有任何评论