前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java面向对象编程知识小结(一)

java面向对象编程知识小结(一)

作者头像
魚迹
发布2023-05-06 21:32:10
1800
发布2023-05-06 21:32:10
举报

面向对象编程知识小结

1、简要介绍

Java是一种面向对象的编程语言。面向对象编程,英文是Object-Oriented Programming,简称OOP。面向对象编程,是一种通过对象的方式,把现实世界映射到计算机模型的一种编程方法。

2、基本概念

2.1 类

class是一种对象模版,它定义了如何创建实例。而instance是对象实例,instance是根据class创建的实例。

  • 定义person类
代码语言:javascript
复制
class Person {
    public String name;
    public int age;
}

2.2实例

用new操作符创建一个实例,然后,我们需要定义一个引用类型的变量来指向这个实例:

代码语言:javascript
复制
Person ming = new Person();

上述代码创建了一个Person类型的实例,并通过变量ming指向它。

2.3. 方法

2.3.1简要介绍

一个class可以包含多个属性,例如,我们给Person类就定义了两个属性:name和age。但是,直接把属性(field)用public暴露给外部可能会破坏封装性。所以需要结合使用修饰符public、private、protected,然后定义方法,实现类的封装。

代码语言:javascript
复制
public class Oop {
    public static void main(String[] args) {
        Person ming = new Person();
        ming.name = "Xiao Ming"; // 对字段name赋值
        ming.age = 12; // 对字段age赋值
    }
}
class Person {
    private String name;
    private int age;
}

例如上方代码中,将person的成员变量用private修饰,但未设置成员方法访问,在实例化对象后直接报错:

在这里插入图片描述
在这里插入图片描述

所以这个时候,为了既实现封装,又能访问、操作class的私有属性,就需要为类添加public修饰的方法。具体如下代码所示:

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        Person ming = new Person();
        ming.setName("Xiao Ming"); // 设置name
        ming.setAge(12); // 设置age
        System.out.println(ming.getName() + ", " + ming.getAge());
    }
}

class Person {
    private String name;    //私有属性
    private int age;

    public String getName() {  //成员方法
        return this.name;
    }

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

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        if (age < 0 || age > 100) {
            throw new IllegalArgumentException("invalid age value");
        }
        this.age = age;
    }
}

2.3.2 this变量

在方法内部,可以使用一个隐含的变量this,它始终指向当前实例。因此,通过this.field就可以访问当前实例的字段。

2.3.3方法参数

方法可以包含0个或任意个参数。方法参数用于接收传递给方法的变量值。调用方法时,必须严格按照参数的定义一一传递。

代码语言:javascript
复制
//示例代码
class Person {
    ...
    public void setNameAndAge(String name, int age) {//两个参数
        ...
    }
}

2.3.4构造方法

创建实例的时候,实际上是通过构造方法来初始化实例的。如下类中的有两个参数的构造方法。

代码语言:javascript
复制
class Person {
    private String name;
    private int age;

    public Person(String name, int age) {//两个参数的构造方法
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

构造方法的名称就是类名构造方法的参数没有限制,在方法内部,也可以编写任意语句。但是,和普通方法相比,构造方法没有返回值(也没有void),调用构造方法,必须用new操作符。 任何类都有构造方法,如果一个类没有定义构造方法,编译器会自动为我们生成一个默认构造方法,它没有参数,也没有执行语句,例如:

代码语言:javascript
复制
class Person {
    public Person() { //默认的构造方法,如果不显式定义构造方法的,编译器会自动生成一个类似这样的构造方法。
    }
}

要特别注意的是,如果我们自定义了一个构造方法,那么,编译器就不再自动创建默认构造方法如下示例中,就会产生错误:

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
        Person p = new Person(); // 编译错误:找不到这个构造方法
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }
}

错误如下:

在这里插入图片描述
在这里插入图片描述

总之,想要使用什么样的构造方法,要自己显式定义出来,并且可以定义多个构造方法

2.3.5方法重载

在一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。例如,在Hello类中,定义多个hello()方法:

代码语言:javascript
复制
 public void hello() {
 //方法名相同,参数不同。
        System.out.println("Hello, world!");
    }

    public void hello(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public void hello(String name, int age) {
        if (age < 18) {
            System.out.println("Hi, " + name + "!");
        } else {
            System.out.println("Hello, " + name + "!");
        }
    }

注意:方法重载的返回值类型通常都是相同的。 方法重载的目的是,功能类似的方法使用同一名字,更容易记住,因此,调用起来更简单。

3、实现方式

3.1 继承

继承是面向对象编程中非常强大的一种机制,它首先可以复用代码。Java使用extends关键字来实现继承:

代码语言:javascript
复制
class Person {
    private String name;
    private int age;

    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
}

class Student extends Person {
    // 不要重复name和age字段/方法,
    // 只需要定义新增score字段/方法:
    private int score;

    public int getScore() { … }
    public void setScore(int score) { … }
}

注意

  1. 通过继承,Student只需要编写额外的功能,不再需要重复代码。
  2. 在OOP的术语中,我们把Person称为超类(super class),父类(parent class),基类(base class),把Student称为子类(subclass),扩展类(extended class)。
  3. Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,它没有父类。
  4. 继承有个特点,就是子类无法访问父类的private字段或者private方法。为了让子类可以访问父类的字段,我们需要把private改为protected。
  5. 用protected修饰的字段可以被子类访问。protected关键字可以把字段和方法的访问权限控制在继承树内部,一个protected字段和方法可以被其子类,以及子类的子类所访问
  6. super关键字表示父类(超类)。子类引用父类的字段时,可以用super.fieldName。
  7. 正常情况下,只要某个class没有final修饰符,那么任何类都可以从该class继承。 在Java中,任何class的构造方法,第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句super();
代码语言:javascript
复制
class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(); // 自动调用父类的构造方法
        /*
        如果父类没有无参的构造方法,可以在super()中添加已定义且与构造方法相同的参数列表,如下所示
        super(name, age);  调用父类的构造方法Person(String, int)
        */
        this.score = score;
    }
}

结论:如果父类没有默认的构造方法,子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。

从Java 15开始,允许使用sealed修饰class,并通过permits明确写出能够从该class继承的子类名称。 示例:

代码语言:javascript
复制
public sealed class Shape permits Rect, Circle, Triangle {
    ...
}

上述Shape类就是一个sealed类,它只允许指定的3个类继承它。 如果写:

代码语言:javascript
复制
public final class Rect extends Shape {...}

是没问题的,因为Rect出现在Shape的permits列表中。 但是如果不是shape指定的三个类,则会报错,如:

代码语言:javascript
复制
public final class Ellipse extends Shape {...}
// Compile error: class is not allowed to extend sealed class: Shape
  1. 向上转型 把一个子类类型安全地变为父类类型的赋值,被称为向上转型(upcasting)。向上转型实际上是把一个子类型安全地变为更加抽象的父类型:
代码语言:javascript
复制
Student s = new Student(); //student 继承 person
Person p = s; // upcasting, ok
Object o1 = p; // upcasting, ok
Object o2 = s; // upcasting, ok
  1. 向下转型 和向上转型相反,如果把一个父类类型强制转型为子类类型,就是向下转型(downcasting).例如:
代码语言:javascript
复制
Person p1 = new Student(); // upcasting, ok
Person p2 = new Person();
Student s1 = (Student) p1; // ok
Student s2 = (Student) p2; // runtime error! ClassCastException!

Person类型p1实际指向Student实例,Person类型变量p2实际指向Person实例。在向下转型的时候,把p1转型为Student会成功,因为p1确实指向Student实例,把p2转型为Student会失败,因为p2的实际类型是Person,不能把父类变为子类,因为子类功能比父类多,多的功能无法凭空变出来。 因此,向下转型很可能会失败。失败的时候,Java虚拟机会报ClassCastException。 为了避免向下转型出错,Java提供了instanceof操作符,可以先判断一个实例究竟是不是某种类型:

代码语言:javascript
复制
Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // false

Student s = new Student();
System.out.println(s instanceof Person); // true
System.out.println(s instanceof Student); // true

Student n = null;
System.out.println(n instanceof Student); // false

instanceof实际上判断一个变量所指向的实例是否是指定类型,或者这个类型的子类。如果一个引用变量为null,那么对任何instanceof的判断都为false。

3.2多态

在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为覆写(Override)。 例如,在Person类中,我们定义了run()方法:

代码语言:javascript
复制
class Person {
    public void run() {
        System.out.println("Person.run");
    }
}
在子类Student中,覆写这个run()方法:

class Student extends Person {
    @Override
    public void run() {
        System.out.println("Student.run");
    }
}

Override和Overload不同的是,如果方法签名不同,就是Overload,Overload方法是一个新方法;如果方法签名相同,并且返回值也相同,就是Override。

加上@Override可以让编译器帮助检查是否进行了正确的覆写,@Override不是必需的。希望进行覆写,但是不小心写错了方法签名,编译器会报错。如下所示:

代码语言:javascript
复制
public class Main {
    public static void main(String[] args) {
    }
}

class Person {
    public void run() {}
}

public class Student extends Person {
    @Override // Compile error!
    public void run(String s) {}
}

Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。 这个非常重要的特性在面向对象编程中称之为多态。它的英文拼写非常复杂:Polymorphic。

  1. 定义 多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。多态的特性就是,运行期才能动态决定调用的子类方法。对某个类型调用某个方法,执行的实际方法可能是某个子类的覆写方法.
  2. 在子类的覆写方法中,如果要调用父类的被覆写的方法,可以通过super来调用。
  3. 继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为final。用final修饰的方法不能被Override.
  4. 如果一个类不希望任何其他类继承自它,那么可以把这个类本身标记为final。用final修饰的类不能被继承
  5. 对于一个类的实例字段,同样可以用final修饰。用final修饰的字段在初始化后不能被修改。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 面向对象编程知识小结
  • 1、简要介绍
  • 2、基本概念
    • 2.1 类
      • 2.2实例
        • 2.3. 方法
          • 2.3.1简要介绍
          • 2.3.2 this变量
          • 2.3.3方法参数
          • 2.3.4构造方法
          • 2.3.5方法重载
      • 3、实现方式
        • 3.1 继承
          • 3.2多态
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档