Java面向对象基本知识

本文详细介绍了Java的面向对象特性,包括类、对象、访问权限修饰符、继承、多态、抽象类、接口等核心概念。深入讲解了构造方法、this关键字、static关键字的使用,以及内部类的类型。此外,还探讨了封装、初始化、方法覆盖和重写等重要概念,强调了面向对象编程在代码复用和维护性上的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java面向对象

0.面向对象程序设计

面向对象程序设计思想
数据结构优先,算法在后,是方法的集合
传统结构程序设计思想
算法优先,数据结构在后,数据结构服务于算法,是对象以及对象间的消息的集合

1.面向对象基本思想

1.1 类(class)

是构造对象的模板或蓝图,由类构造对象的过程是创建类的实例,描述了对象属性和行为的共性。对象中的数据是实例字段,操作数据的过程是方法,特定对象的实例字段值就是对象的当前状态,只要在对象上调用一个方法,对象的当前状态就有可能发生变化。
封装给对象赋予了黑盒特性,程序只能通过对象的方法和对象数据进行交互。

1.2 类的定义
  • 成员变量
    指的是事物的属性,定义在类中方法体之外的变量
  • 成员方法
    指的是事物的行为,没有static关键字的方法

类的定义,本质是对数据类型的定义,是我们自己定义的数据类型。创建对象就是类的实例化,对象是类的实例

1.3 类在JVM中的内存映像

对于同一个JVM,一次运行最多只加载一次类
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kCiuXtSQ-1641519509091)(/assets/MemoryOfClass.drawio.png)]


2.面向对象特殊语法

2.1 局部变量和成员变量的比较

  • 在类中定义的位置不同
    局部变量:定义在方法中(方法体中和方法形式参数)
    成员变量:类中方法体之外
  • 在内存中的位置不同
    局部变量:栈空间栈帧中
    成员变量:堆上的对象里
  • 生命周期不同
    局部变量:生命周期和方法运行有直接关系
    成员变量:生命周期和方法运行没有直接关系
  • 初始化值不同
    局部变量:手动赋初值
    成员变量:天生有初值

2.2 对象作为方法参数

时刻注意,实际的参数到底有没有改变,参数有两份,但是参数的实际值只有一份

2.3 构造方法

创建对象时对成员变量初始化

语法

  • 构造方法方法名必须与类名相同
  • 没有返回值声明,加了返回值就不是构造方法了

注意事项

  • 方法重载同样适用
    • 参数类型不同
    • 参数个数不同
    • 参数类型顺序不同
  • 没有构造方法的时候,JVM会默认添加构造方法;定义了构造方法后,就不会默认添加构造方法了。
  • 对象创建及初始化过程
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y2HBS7tt-1641519509093)(/assets/2022-01-03_15-19-57.png)]
  • 当方法中定义了和成员变量同名的局部变量,成员变量被隐藏,因此需要区分成员变量和局部变量(this)

2.4 this关键字

作用:

  • 用于区分成员变量和局部变量
  • 访问对象的成员(包含成员变量和成员方法)
    public void eat(){
      this.sleep();
      System.out.println(name + " is eating");
  }
  • 访问对象的构造方法
public Student(){
        this("Unknown", -1, -1);
    }

该语句只能在构造方法的方法体中,并且只能位于构造方法的第一条语句位置

this代表对当前对象的引用,那么当前对象是哪个对象?

  1. 在构造方法中的对象
    当构造方法执行时,JVM正在创造一个对象,所以this就指正在创建的那个对象
  2. 在普通成员方法中
    访问的是哪个对象,this就指那个对象

2.5 static关键字

可以修饰成员和方法,被修饰的成员变量,该变量我们称之为静态成员变量(静态变量);被修饰的成员方法,称之为静态成员方法(静态方法)

特点:

  1. 被当前类的所有对象所共享
    • 被修饰成员变量被类的所有对象共享
    • 被修饰成员方法,从共享的角度看,和普通方法没有区别
  2. 可以通过类名访问静态变量或访问静态方法
  3. 静态变量,随着类加载被放进方法区(首次访问静态成员时会触发类加载)同时,静态方法也是随着类加载而被放进方法区,在对象还未创建时就可以直接访问
class StaticClasses{
    static int staticField;
    static void staticField(){
        System.out.println("sao");
    }
}
  1. 静态变量、静态方法优先于对象存在,不依赖于对象而存在

注意事项:

  1. 静态上下文中,无法访问非静态的成员变量(成员方法)
    • 静态方法的方法体(只是静态上下文的一种,后面会补充)
    • 无法访问普通成员变量(成员方法), 是因为有可能访问不到当前对象
    • 并非在静态方法体中,都不能访问静态变量和静态方法,我们可以在自己new的对象上访问
  2. 不能出现在方法体当中

使用场景:

  1. 针对成员变量,如果我们想让成员变量被当前类的所有对象共享,使用static修饰成员变量
  2. 针对成员方法,通常工具方法会被定义成静态方法。

2.6 代码块

2.6.1 局部代码块

出现在方法中的代码块,方法体中用花括号定义的代码,随着方法执行而执行

2.6.2 构造代码块

定义在类中方法体之外的代码块,创建对象时执行,每个对象创建都会执行
特点:

  • 构造代码块优先于构造方法执行
  • 成员变量初始化语句,和构造方法比构造代码块后执行
  • 成员变量初始化语句和构造代码块比,谁先定义谁先执行

作用:

  • 在构造代码块中,执行对对象成员变量值的初始化
  • 如果在多个构造方法中,有需要执行的公共代码,公共代码可以放到构造代码块中
2.6.3 静态代码块(也是一种静态上下文)

被static修饰的定义在类中方法体之外的代码块
特点:

  • 随类加载而加载,而在JVM的一次运行当中,一个类最多只会执行一次,那静态代码块最多也只会执行一次

作用

  • 如果有些代码只需要执行一次,可以放在静态代码块中

2.7 package关键字

声明可以使文件中定义的类成为指定包的成员

没有package关键字并不意味着java文件不属于任何一个包,java语言里有一个默认包,类总是被包组织起来的。

2.8 import关键字

导入全限定类名,编译器默认我们导入的是当前包下的类,要用其它包的类需要使用import

注意事项:

  • import语句在package后,class前
  • java.lang包中的类被隐式导入,例:String类
  • import <包名> .*
    • 按需导入

3.访问权限修饰符

3.1 修饰类中成员

权限/权限关键字publicprotecteddefaultprivate
同一个类中访问
同包其它类中访问×
跨包访问× (跨包子类可以访问)××

普通成员方法和普通成员变量从访问权限的角度来说,是一样的。

private作用:

  1. 提示用户不用触碰他们不该触碰的代码
  2. 类库设计者可以安全地修改实现细节

3.2 修饰类

  • 类只有两种访问权限default和public
  • 一个Java文件中只能有一个类具有public访问权限
  • 一旦类被public修饰,类名必须和Java文件名相同

public 其它任意类可见
default 同包类可见

4.面向对象三大特征

4.1 封装

  • 将数据和基于数据的操作封装在一起
  • 数据被保护在内部
    private修饰成员变量,使用get和set方法获取和修改成员变量内容,同时又能保护内部数据,又能控制外部对成员变量控制的访问
    如果把所有构造方法的访问权限定义为private,那么在其他类就无法新建对象了

4.2 继承

特点:

  • Java只支持单重继承,但是一个类可以继承父类以及其所有祖先类中定义的成员

继承中的名词:

  • 父类(基类,超类)指被继承的类
  • 子类(派生类,导出类)指继承的类

优点:

  • 代码复用
  • 提高了代码的维护性
  • 弱化Java的类型约束
    可以让父类引用指向子类对象

缺点:

  • 父类修改会被继承到所有子类中

继承的注意事项:

  • 子类只能访问父类中的非私有成员
  • 子类不能继承父类的构造方法
4.2.1 子类对象的初始化问题

先父后子
原因:

  • 父得有东西,子才能继承
  • 子类有可能要依赖父类成员变量值

如何实现?
子类构造方法体执行之前先去调用父类的构造方法

子类对象初始化方式:

  • 隐式初始化方式
    JVM自动保证父类构造方法先构造
    条件:
    • 父类必须有默认构造方法(无参构造方法)
    • 子类构造方法中没有显式调用父类的其它构造方法
  • 显式初始化方式
    结合super关键字,访问父类构造方法,程序员手动保证父类构造方法先执行
4.2.2 super关键字

super指向了子类对象存储空间里父类对象成员变量的存储空间
用法:

  • 访问成员变量
  • 访问构造方法(访问父类构造方法)
  • 访问成员方法

注意事项:

  • 保证先父后子的顺序,显式和隐式初始化都无所谓
  • super只能用在子类的方法中使用,super调用父类无参构造方法只能在子类构造方法中的第一条语句
  • super和this在构造方法中不能同时存在
  • 为了保证先父后子,父类的成员变量初始化语句、构造代码块、构造方法都优先于子类中的初始化语句、构造代码块和构造方法
4.2.3 父类域field的隐藏
  • 父类方法体中访问同名成员变量,访问的是父类成员变量的变量值;子类方法提中访问同名成员变量,访问的是子类成员变量的变量值
  • 如果在子类对象上访问成员变量值,先在子类对象上搜索有没有该成员变量,有则访问,没有则去父类对象找
4.2.4 方法的覆盖和重写

JVM对待执行方法的搜索策略:

  • 子类中搜索待执行的方法,找到就执行
  • 去父类找,找到就执行
  • 一路溯源,直到最后找到就执行

方法覆盖的条件:

  • 方法的访问权限
    子类方法的访问权限不必和父类方法完全相同,只需保证子类方法的访问权限大于等于父类即可
  • 方法的返回值
    • 如果返回值是基本数据类型,子类方法的返回值类型和父类方法相同
    • 如果返回值是引用数据类型,子类方法的返回值类型不必和父类方法相同,但是在这种情况下,子类返回值类型是父类返回值类型的子类
  • 方法的方法签名(方法名+参数列表)
    方法签名必须完全一致

方法覆盖的使用场景
修改父类中的方法实现

方法覆盖的注意事项

  • 父类中私有方法不能被覆盖
4.2.5 final关键字

final是最终的意思,可以修饰类、方法、变量。

  • 被修饰的类不能继承
  • 被修饰的方法不能被覆盖
  • 被修饰的变量
    修饰局部变量:变成了常量,只能被赋值一次
    修饰成员变量:必须保证,在对象创建完毕之前给它赋值一次且仅一次(初始化语句、构造方法、构造代码块)

4.3 多态

多态是同一个行为具有多个不同表现形式或形态的能力(同一个行为在不同对象上的表现形式
必要条件:

  • 继承
  • 方法覆盖
  • 父类引用指向子类对象

多态成员的额访问特征

  • 成员变量
    编译看左边(我们所能访问到的成员是根据引用变量的类型决定的),运行看左边(成员变量有父类的外貌特征)
  • 成员方法
    编译看左边(我们所能访问到的方法是根据引用变量的类型决定的),运行看右边
    编译时,能够访问的成员变量是父类所具有的,最后访问的也是父类的变量;
    而能够访问的成员方法是父类的方法,但是实际调用的是子类的重写方法

问题:

  • 父类类型引用的引用变量无法访问到子类自己定义的方法
    solution:引用变量类型转化
    • 子类类型–>父类类型:向上转型(一定安全,编译器默认允许)
    • 父类类型–>子类类型:向下转型(编译器默认不允许,运行可能存在安全问题)当然,可以强制转化,可是如果向下转型时,当前被转化的实际指向的对象类型如果不是真正的子类,转型会失败
      • 解决方案
        instanceof
        引用变量 instanceof 目标类的类名
        返回true:引用变量指向对象目标类的对象
        返回false:引用变量指向对象不是目标类的对象
        需要注意的是, null instanceof 任意类 的结果都是false

优点:

  • 提高程序可维护性
  • 提高代码可扩展性

5. 抽象类

抽象类不能实例化,因此其必须要被子类继承才能使用;子类中需要实现的方法,需要在抽象类中声明,即声明抽象方法,该方法不需要方法体。

抽象类的成员组成

  • 成员变量:和普通类没有任何区别
  • 构造方法:和普通类也没有任何区别
  • 成员方法:
    • 抽象方法:声明该类,有这种行为
    • 非抽象方法:如果知道行为如何实现,可以定义非抽象方法实现

注意事项:

  • abstract不能和private, final, static共存,因为被这三个关键字修饰的抽象方法是无法被覆盖的

6. 接口

接口打破了单重继承特性
接口表示数据类型,侧重于描述一组有特殊功能的行为。可以定义一个类,让类实现接口,这种关系叫做实现关系。

特征:

  • 接口不能直接实例化,但是可以间接实例化
    接口类型 引用变量 = 接口的子类对象
  • 接口的子类,可以是抽象类也可以是具体类
    如果子类是普通类,则必须重写接口里的所有方法

接口的组成:

  • 成员变量:
    接口中定义的成员变量,实际上被public static final修饰
  • 构造方法:
    接口不能定义构造方法,因为接口的方法都是抽象方法
  • 成员方法
    只能定义抽象方法,默认被public abstract修饰

接口定义其它方法(不建议,也很少使用到)
默认方法
我们原来说接口里只能定义抽象方法,实际上默认方法也是可以的,默认方法不强制所有子类覆盖它。
静态方法
作为工具方法

6.1 接口的多重继承

  • 接口和接口之间可以多重继承
  • 一个类可以实现多个接口《Java编程思想》

6.2 完整类定义语法

class 类名 extends 类名 implements 接口1,接口2...{
  类定义
}

6.3 抽象类和接口的比较

成员区别

  • 抽象类 变量,常量;有抽象方法; 非抽象方法
  • 接口 常量;抽象方法

关系区别

  • 类与类 继承,单继承
  • 类与接口 实现,单实现,多实现
  • 接口与接口 继承,单继承,多继承

设计理念区别

  • 抽象类 被继承体现的是:”is a”的关系,是一种共性功能
  • 接口 被实现体现的是:”like a”的关系,每个接口只实现了接口的冰山一角,是一种扩展功能

7.内部类

内部类指的是一个类里嵌套其它的类

7.1 非静态内部类

被嵌套的类拥有访问外部类的权限,由于嵌套在外部类中,因此必须先实例化外部类,然后创建内部类的对象实现。

class OuterClass{
  int x = 10;
  class InnerClass{
    int y = 5;
  }
}

7.2 私有内部类

内部类可以被private和protected修饰,这样内部类不能被外部类访问。

7.3 静态内部类

即不需要先进性外部实例化就可以直接访问内部类,但是不能访问外部类。

7.4 内部类访问外成员

class Outerclass{
  int x = 10;
  class InterClass{
    public int myInnerMethod(){
      return x;
    }
  }
}

这就是Java面向对象的基础知识,欢迎大家讨论交流😘!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值