Java中的类和对象以及封装、继承、多态

446 阅读12分钟

​ 类和对象想必是每位学习Java同学的痛,因其概念多而杂又抽象。大家应该都听说过这么一句话——Java中一切皆对象!何为对象?对象又从哪里来呢?那么接下来就会为你一一解答。

什么是对象?

在了解什么是对象之前要先知道什么是类

对象是由类创建的由类产生对象的过程称为实例化(通过new关键字来实例化对象)

后面会详细讲到。

面向对象和面向过程

面向对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。

面向过程则是注重过程

何谓类

简单认识类

类是用来对一个实体(对象)来进行描述的,主要描述该实体(对象)具有哪些属性(外观尺寸等),哪些功能(用来干啥),描述完成后计算机就可以识别了

  1. 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
  2. 类是一种自定义的类型,可以用来定义变量,但是在java中用类定义出来的变量我们成为对象.
  3. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
  • 通过new 关键字创建一个对象的实例
  • 使用点【.】来访问对象中的属性和方法
  • 同一个类可以创建多个实例

注意事项:

  • 类名注意采用大驼峰定义
  • 成员前写法统一为public
  • 此处写的方法不带 static 关键字.

类的定义格式

在java中定义类时需要用到class关键字

class为定义类的关键字,ClassName为类的名字,{}中为类的主体

// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method; // 行为 或者 成员方法
}

类中包含的内容称为类的成员。属性主要是用来描述类的,称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能,称为类的成员方法。

定义一个狗类

class PetDog {
public String name;//名字
public String color;//颜色
// 狗的属性
public void barks() {
System.out.println(name + ": 旺旺旺~~~");
} 
// 狗的行为
public void wag() {
System.out.println(name + ": 摇尾巴~~~");
}
}

定义一个学生类

public class Student{
public String name;
public String gender;
public short age;
public double score;
public void DoClass(){}
public void DoHomework(){}
public void Exam(){}
}

类的实例化

什么是类的实例化

定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不intdouble是java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:Dog、Student类。它们都是类(一种新定义的类型)有了这些自定义的类型之后,就可以使用这些类来定义实例(或者称为对象)

用类类型创建对象的过程,称为类的实例化,在java中采用new关键字,配合类名来实例化对象。

对象的构造及初始化

如何初始化对象

  1. 通过点这个符号来初始化
  2. 通过创建一个公开的set方法,然后通过调用这个set方法来初始化
  3. 通过构造方法来初始化

构造方法

构造方法(也称为构造器)是一个特殊的成员方法,**名字必须与类名相同,在创建对象时,由编译器自动调用,并且在整个对象的生命周期内只调用一次 **

public class Date {
public int year;
public int month;
public int day;
// 构造方法:
// 名字与类名相同,没有返回值类型,设置为void也不行
// 一般情况下使用public修饰
// 在创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次
public Date(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
System.out.println("Date(int,int,int)方法被调用了");
}
public void printDate(){
System.out.println(year + "-" + month + "-" + day);
}
public static void main(String[] args) {
// 此处创建了一个Date类型的对象,并没有显式调用构造方法
Date d = new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了
d.printDate(); // 2021-6-9
}
}
public class Date {
public int year;
public int month;
public int day;
// 无参构造方法
public Date(){
this.year = 1900;
this.month = 1;

构造方法是干嘛的?

构造方法是用来构造对象的

一个对象的产生-----对象的实例化

​ 1.为对象分配内存

​ 2.调用合适的构造方法(意味着构造方法不止一个)

注意:构造方法的作用就是对对象中的成员进行初始化,并不负责给对象开辟空间

构造方法的特点:

1)构造方法 是没有返回值的方法,方法名和类名是一样的

2)构造方法 不止一个,可以有多个,多个构造方法之间,就构成了重载

3)当我们写了一个类之后,没有写构造方法的时候,编译器就会帮我们默认生成一个不带参数的构造方法

4)一个类 至少有一个构造方法

5)构造方法 本质就是来实例化对象的时候调用的。1.分配内存。2.调用合适的构造方法

6)this可以调用本类中其他的构造方法。必须放第一行!所以,只能在当前构造方法当中,调用一个。

封装

什么是封装?

封装可以理解为将某个东西“包装”起来

封装的意义、作用:

封装的主要作用在于对外隐藏内部实现细节,增强程序的安全性

继承

继承:继承从字面的意思就能知道它是拥有了某样的东西,即对共性的一个抽取,使用extends关键字来实现的

>语法:A extends B

则A称作子类,派生类

B称作父类,基类,超类

意义:为了代码的重复使用。

this关键字

java编译器给每个“成员方法“增加了一个隐藏的引用类型参数,该引用参数指向当前对象(成员方法运行时调用该成员方法的对象),在成员方法中所有成员变量的操作,都是通过该引用去访问

this的三种基本用法:

  1. this.data 调用当前对象的属性
  2. this.func() 调用当前对象的方法
  3. this() 调用当前对象的其他构造方法, **this(); 只能存在于构造函数当中! **

super 关键字

super:【不能出现在静态方法中】因为super代表对父类对象的引用

1.super(); 调用父类的构造方法 2.super.func(); 调用父类的普通方法 3.super.date; 调用父类的常用属性 4.super关键字是在子类对象内部指代其父类对象的引用

final 关键字

如果一个类 不想被继承,我可以设置为final修饰 final int a = 10; 修饰常量不能被修改 final class A 代表整个类不可以被继承 final 修饰方法 代表不允许任何从此类继承的类来重写这种方法

重写

在学习多态前,我们得了解一下什么是重写 覆盖/覆写/重写: a、方法名相同 b、参数列表相同(参数个数+参数的类型) c、返回值相同(特殊:返回值也可以是协变类型) 注意: 1.static方法不能重写 2.private修饰的方法 3.final修饰的方法 4.子类方法的访问权限要大于等于父类的访问权限

向上转型

向上转型的概念:即父类的引用 引用子类对象

Animal animal = new Bird();
Bird bird = (Bird) animal;
bird.fly();

向下转型

向下转型的概念:将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的 方法,此时:将父类引用再还原为子类对象即可,即向下转换

向下转型是不安全的。要用instanceof判断,是的话就向下转型,否则不

instanceof用法: 判断animal这个引用所引用对象是否和Bird这个类的实例化的对象相同,或者Bird这个类是animal这个引用的一个子类

Animal animal = new Dog();
        if (animal instanceof Bird) {
            Bird bird = (Bird) animal;
            bird.fly();
        }

运行时绑定

运行时绑定(也称动态绑定):通过父类引用 调用父类和子类同名的覆盖方法。即发生了重写(这是实现多态的基础也是必要条件)

编译时绑定

编译时绑定:通过函数的重载实现的。编译的时候,会根据你给的参数的个数和类型,在编译期,确定你最终调用的一个方法 注意: 1、子类继承了父类,那么子类在构造的时候,需要先帮助父类来进行构造。需要在子类的构造方法中,使用super关键字来显式调用父类的构造方法。 2、super和this的区别? 重写和重载的区别? 3、访问修饰限定符。 public:哪里都可以访问 protected:同一个包可以访问。不同包,必须是子类才能访问。 包访问权限:类名前什么都不写即默认为包访问权限,只能在同一个包里面访问 private:只有在当前类中可以访问

多态的好处

使用多态的好处:

  • 类调用者对类的使用成本进一步降低。
  • 封装是让类的调用者不需要知道类的实现细节
  • 多态能让类的调用者连这个类的类型是什么都不必知道,只需知道这个对象具有某个方法即可,因此,多态可以理解成是封装的更进一步,让类调用者对类的使用车成本进一步减低

抽象类

类中有abstract 修饰的方法,称为抽象方法,抽象方法所在的类称为抽象类。

  1. 包含抽象方法的类,称为抽象类
  2. 什么是抽象方法,一个没有具体实现的方法,被abstract修饰
  3. 抽象类不能被实例化。new不了
  4. 因为不能被实例化,这个抽象类只能被继承!!!
  5. 抽象类当中,也可以包含,和普通类一样的成员和方法
  6. 一个普通类,继承了一个抽象类,那么这个普通类当中,需要重写这个抽象类的所有方法。
  7. 抽象类的最大作用就是为了被继承
  8. 一个抽象类A,如果继承了一个抽象类B,那么这个抽象类A,可以不实现抽象父类B的抽象方法
  9. 结合第点,当A类再次被一个普通类继承后,那么A和B这两个抽象类当中的抽象方法,必须被重写。
  10. 抽象类不能被final修饰,抽象方法也不可以被final修饰

接口

1.使用interface来修饰的 2.接口当中的普通方法,不能够有具体的实现,如果非要实现,只能 通过关键字default来修饰 这个方法。开头加default 3.接口当中可以有static的方法 4.里面的所有的方法都是public的 5.抽象方法,默认是public abstract 的(抽象方法没有具体实现) 6.接口是不可以通过关键字new来实例化的 7.类和接口之间的关系是通过implements实现的 8.当一个类,实现了一个接口,就必须要重写接口当中的抽象方法 9.接口当中的成员变量,默认是public static final 修饰的 10.当一个类实现一个接口之后,重写这个方法的时候,这个方法前面 必须加上public 11.一个类可以以通过关键字extends继承一个抽象类或者普通类,但是只能继承一个类。 同时,也可以通过implements实现多个接口,接口之间使用逗号隔开就好。 12.类和类之间,类和接口之间的关系是通过implements操作的。那么接口和接口之间是怎样的关系呢? 接口和接口之间可以使用extends来操作他们的关系,此时extends意为:拓展。一个接口通过extends来拓展另一个接口的功能。

接口的出现弥补了java中不能继承多个类的缺陷 某种意义上讲接口就是为了多继承而产生的

接口的注意事项:

  • 使用interface定义一个接口
  • 接口中的方法一定是public,因此可以省略public
  • 接口中的方法一定是abstract的抽象方法,因此也可以省略abstract
  • 使用implements实现接口,此时表达的不再是“扩展”而是“实现”
  • 在调用的时候同样可以创建一个接口的引用,对应到一个子类的实例
  • 接口不能单独被实例化

扩展(extends)和实现(implements)的区别:

  • 扩展指的是当前已经有一定的功能了,进一步扩充功能

  • 实现指的是当前什么都没有,需要从头构造出来

继承:is a的一个关系

接口:什么什么的特性

三个常用接口

Comparable

如果 自定义的数据类型 进行大小比较 一定要实现可以比较的接口 这个接口有一个很大的缺点:对类的入侵性非常强。一旦写好了, 不敢轻易改动。

Comparator

相比于Comparable灵活,对类的入侵性非常弱

Cloneable

用于clone的克隆接口

结语


通过类和对象我们引出了封装、继承、多态、接口等概念,我相信现在大家对类和对象应该有了一个更深刻的印象和理解。