当前位置: 首页 > news >正文

Java 面向对象核心基础(一)

本文将详细介绍Java中的包(package)、访问限定符、static,希望能给大家带来帮助。如果有一些地方不严谨,可以在评论区指正或者私信我,我们一起进步!

文章目录

  • 一、包(package)
    • 包的引出
    • 包是什么
  • 二、访问限定符
  • 三、static关键字
    • static的定义
    • 静态变量和静态方法
      • **1.静态成员变量**
      • **2.静态成员方法**

一、包(package)

包的引出

如果代码编写规范的话,在本地一个类就对应一个文件
而当你想定义一个相同类名,就会显示已经存在相同类名的类
原因也很简单,在本地来看,一个类就是一个文件,当你新建一个同名的文件,会有文件名冲突问题。

要想解决这里问题,有两个办法:一个是换一个没有使用过的文件名,避免命名重复;还有一个就是将文件放在一个没有同名文件的文件夹目录下。

如果使用第一个方法,文件名不能顾名思义,这样一来失去了命名的可读性,而且如果都把文件放在同个文件夹中,会导致一个文件夹中有特别多的文件,没有层次性,不方便查找;使用第二个方法可以规避这些问题。

包是什么

而包就类似于第二个方法中的文件夹,它可以防止类名冲突以及提高代码的可读性。

定义:包是Java提供的一种对类、接口、注解等等的管理机制,对不同类型的结构或者不同业务功能的分类

使用包可以:

1.不同的包可以放同名的文件。这避免了类名的重复

2.方便管理代码,比如可以将关于人的类放在同个包(Person、Teacher、Student),关于动物的类可以放在同个包,包括后面接触到的,将工具类放同个包,将实体类放同个包,将请求控制层放用一个包中等等,这样一来,如果想找一个类,可以先根据功能类别找到包,再在包中快速找到对应的类,这大大提高了代码查找效率,也使项目的结构更加清晰明了。以下能快速找到Student类:

创建:在IDEA创建一个包也很简单,步骤就是右键想创建包的 目录 -> New(新建)-> Package(软件包)

弹出”新建软件包“弹窗,输入包名,按回车

这样就创建成功了

当然,包中还可以再创建包。
导入:导入包中的类也有好几种方法

1.将导包语句写在类前面,包名.类名,例如:

publicclassMain{publicstaticvoidmain(String[]args){Person.Studentstudent=newPerson.Student();}}

这种方法最大的问题就是麻烦、代码冗余,如果以后还要创建Student对象,就需要每次都要写上在Student类前面写包名,而且一旦包名很长的话,不仅麻烦,而且可读性比较差:

publicclassMain{publicstaticvoidmain(String[]args){Person.male.teenager.Student student1=newPerson.male.teenager.Student("张三",18);Person.male.teenager.Student student2=newPerson.male.teenager.Student("李四",19);Person.male.teenager.Student student3=newPerson.male.teenager.Student("王五",20);}}

2.在类上方导包

方法一:显式导入

import包名.类名

例如:

importPerson.male.teenager.Student;

这样一来,大大简化的代码:

importPerson.male.teenager.Student;publicclassMain{publicstaticvoidmain(String[]args){Studentstudent1=newStudent("张三",18);Studentstudent2=newStudent("李四",19);Studentstudent3=newStudent("王五",20);}}

方法二:可以使用通配符 *,将 类名 替换成 *

import包名.*

例如:

importPerson.male.teenager.*;

代码的效果和方法一一致。

不过,还是尽量使用方法一这种显式的导入,否则如果代码中导入了多个 用通配符 * 导入的包,你要使用的类刚好在多个包中都有,这样一来会有歧义,系统不知道你要用的是哪个包下的类,例如:java.util包下和java.sql包下都有Date类

很明显地看到,报错了,但是也有解决办法,就是再导入一个显式(方法一)的包

这样一来,利用通配符 * 来导包显得有点多余。所以,还是尽量不要使用 import 包名.* 的方式来导包

注意

1)这里的 * 不是表示将该包下的所有类导入,而是用到谁就导入谁

2)如果同时存在方法一和方法二的导包方式,Java会优先选择方法一这种显示的导入方法,如果没有才会看带有通配符 * 的导入方法是否存在该类

3)如果类中的属性或者方法没有设置访问权限的话,默认是包的访问权限

不过,通常来说,我们可以不需要手动添加导包语句,再编写代码的时候IDEA会提示你要导入什么包,你只需点击你想要导入的包,IDEA会自动帮你导入对应的包

按回车之后会自动添加。

二、访问限定符

使用访问限定符可以控制属性和方法的访问范围,Java提供了4中访问修饰符,权限从小到大分别为:private、default、protected、public

访问范围privatedefaultprotectedpublic
1同包同类
2同包不同类
3不同包的子类
4不同包不同类

private: private修饰的属性或者方法只能在本类使用:private String name;

default: default修饰的属性或者方法只能在本类以及包中其他类使用,default是默认访问权限,又称包访问权限,但是default不是关键字,这里是指没有任何修饰符:String name; 而不是 default String name;

protected: protected修饰的属性或者方法只能在本类、包中其他类、不同包但是是该类的子类中使用:protected String name;

public: public修饰的属性或者方法可以在任何范围中使用:public String name;

三、static关键字

static的定义

static是静态修饰符,可以用来修饰成员变量、成员方法、内部类、代码块,被static修饰的变量、方法、内部类、代码块分别叫做静态变量、静态方法、静态内部类、静态代码块

这些被static修饰的类型属于类而非属于对象,属于对象的意思是指必须先new出对象才能被使用,属于类是指不需要创建对象就可以直接使用

🌰举个例子:

假设在学校宿舍里,每层楼都有一个洗衣机,这台洗衣机不属于某一个宿舍或者某个人,而更像是属于这层楼的公物,是由这层楼的所有人共享。所以,如果有人在用,我们就要等待别人用完我们才能用。而static就像是这里的共享

如果想要在代码的角度来表示这台洗衣机由这层楼的所有人共享,就可以将洗衣机用static修饰,这样就表示所有对象操作的都是同一太洗衣机,它处于什么状态,全体可见。

在这里,我们先来介绍静态变量和静态方法,静态内部类和静态代码块会在后面的文章详细解释

静态变量和静态方法

1.静态成员变量

静态成员变量的定义

修饰符static数据类型 变量名;

示例:

publicstaticStringname;

静态成员变量定义的范围同普通成员变量一样,类中方法外;但是不能定义在方法、循环、分支结构等这些局部区域中,也就是说,局部变量不能被static修饰,即使在mian方法中也不能定义静态变量

静态成员变量的使用

针对洗衣机例子,我们创建一个宿舍类

publicclassDormitory{StringpersonName;Stringbed;Stringtable;Stringchair;staticStringwashMachine="公共洗衣机";publicDormitory(StringpersonName,Stringbed,Stringtable,Stringchair){this.personName=personName;this.bed=bed;this.table=table;this.chair=chair;}publicvoidprint(){System.out.println(personName+"同学的床位是"+bed+",桌椅位是"+table+"和"+chair+",并用着"+washMachine);}}
publicclassMain{publicstaticvoidmain(String[]args){Dormitorydormitory1=newDormitory("张三","1号床","2号桌","2号椅");Dormitorydormitory2=newDormitory("李四","2号床","3号桌","3号椅");Dormitorydormitory3=newDormitory("王五","3号床","4号桌","4号椅");dormitory1.print();dormitory2.print();dormitory3.print();}}

运行结果:

张三同学的床位是1号床,桌椅位是2号桌和2号椅,并用着公共洗衣机 李四同学的床位是2号床,桌椅位是3号桌和3号椅,并用着公共洗衣机 王五同学的床位是3号床,桌椅位是4号桌和4号椅,并用着公共洗衣机

这样一看,我们发现现在用不用static效果似乎差不多。以下是内存分配图,可以清楚地看到static 变量的 “全局共享” 特性

接下来,我们再来看看如何在mian方法中访问静态变量

访问静态变量

因为static修饰的变量是属于类的而不属于对象,对于普通的成员变量来说,是通过 对象.变量 来访问普通成员变量;同理可得,静态成员变量的访问就是通过类名.静态成员变量。例如:

Dormitory.washMachine="王五的洗衣机";

值得注意的是:通过 对象.静态成员变量 也可以访问静态成员变量。编译器编译的时候,进行了静态绑定、语法替换,将 对象.静态成员变量 转化成 类名.静态成员变量。

dormitory3.washMachine="王五的洗衣机";

虽然语法支持,但是却不符合逻辑,毕竟静态成员是属于类的,所以我们还是尽量使用 类名.静态成员变量 的方法进行访问。

这里的静态绑定是指 washMachine这一静态成员变量 与 Dormitory建立了联系,在程序还没运行的时候就已经 它们俩绑定死了,并且不能变了。

下面,我们看个例子:

publicclassMain{publicstaticvoidmain(String[]args){Dormitorydormitory1=newDormitory("张三","1号床","2号桌","2号椅");Dormitorydormitory2=newDormitory("李四","2号床","3号桌","3号椅");Dormitorydormitory3=newDormitory("王五","3号床","4号桌","4号椅");//Dormitory.washMachine = "王五的洗衣机";//效果相同dormitory3.washMachine="王五的洗衣机";dormitory1.print();dormitory2.print();dormitory3.print();}}

运行结果:

张三同学的床位是1号床,桌椅位是2号桌和2号椅,并用着王五的洗衣机 李四同学的床位是2号床,桌椅位是3号桌和3号椅,并用着王五的洗衣机 王五同学的床位是3号床,桌椅位是4号桌和4号椅,并用着王五的洗衣机

结果发现,将静态成员的值修改了,所有对象的静态成员也发生改变了。这有一种牵一发而动全身的感觉。当然,这也很好理解,static在这里表示共享的意思,只要有一个对象将洗衣机这一属性修改了,那大家看的到洗衣机属性都是被修改了的。所以,这就是之前所说的,洗衣机处于什么状态,全体可见。

2.静态成员方法

静态方法的应用与静态成员变量类似

静态成员方法的定义

[修饰符]static返回值 方法名([形参列表]){// 方法体}

示例:

publicstaticvoidtest(){}

访问静态成员方法

类名.静态成员方法

示例:

Dormitory.useWashMachine();

静态成员方法的使用

在NewDormitory类中添加一个静态成员方法

publicclassNewDormitory{publicstaticStringpublicWash="空闲";publicstaticvoidshowState(){System.out.println("洗衣机状态:"+publicWash);}}
publicclassMain{publicstaticvoidmain(String[]args){Dormitory.showState();}}

运行结果:

洗衣机状态:空闲

现在,我不单单想看状态,我想使用洗衣机。接下来,在NewDormitory类中再定义一个普通的use()方法,如果有人在使用洗衣机,将状态设置为“使用中”

publicvoiduse(){if(publicWash.equals("空闲")){showState();System.out.println("你可以使用公共洗衣机");publicWash="使用中";}else{showState();System.out.println("请等待");}}
publicclassMain{publicstaticvoidmain(String[]args){NewDormitorydormitory1=newNewDormitory();NewDormitorydormitory2=newNewDormitory();NewDormitorydormitory3=newNewDormitory();dormitory1.use();System.out.println("-----------------");dormitory2.use();System.out.println("-----------------");dormitory3.use();}}

运行结果:

公共洗衣机状态:空闲 你可以使用公共洗衣机-----------------公共洗衣机状态:使用中 请等待-----------------公共洗衣机状态:使用中 请等待

以上是在use()这一普通成员方法中调用了静态成员变量和静态成员方法。

接下,我们在看一个例子,在NewDormitory类中再定义一个普通的washTip()方法,并在静态方法showState()中引用,在每次大家查看子以及状态时,都要提醒他们要文明使用公共设备。代码调整如下:

publicstaticvoidshowState(){System.out.println("公共洗衣机状态:"+publicWash);washTip();}publicvoidwashTip(){System.out.println("洗衣机使用提示:请文明使用公共设备");}


此时,可以看到,washTip();报错了,我们将鼠标移上去:

IDEA提示 我们无法从 static 上下文引用非 static 方法 ‘washTip()’,并建议我们将washTip()方法设置成静态的。这言外之意就是静态成员方法中不能使用非静态成员方法。这又是为什么呢?

首先我们要清楚,静态成员方法是属于类的,它是在类加载时就被加载到方法区,它在全局只会被加载一次,并且它是直接依靠类来调用,在没创建对象前就可以被使用;而非静态成员方法又称实例方法,它虽然也是在类加载的时候被加载到方法区的,但是它必须在实例化对象后通过对象调用才能被使用

所以,当静态成员方法一开始被加载到了方法区的,这个时候是没有对象的,故静态方法中是不能直接调用实例方法的,要通过对象调用才能在静态方法中使用

我们再来谈谈实例方法的一个知识点。在实例方法中的形参中,编译器将.java文件编译成.class文件会自动在形参列表的最前面加上一个this。那为什么要这样设计呢?

原因是因为实例方法也是加载到方法区的,该方法被所有对象共享,如果现在创建了多个对象并调用这个方法的话,这个时候JVM不知道是谁在调用这个实例方法,所以,为了区分是哪个对象在调用这个方法,编译器会在编译成字节码文件的时候会在形参列表的最前面隐藏添加一个this用来表示当前对象,来区分是哪个对象在调用这个实例方法。

而如果实例方法中调用了一个实例方法的话,编译器在编译的时候也会在实例方法前隐藏添加一个this.来表示是该方法是由当前对象调用,形如this.实例方法名

对于静态成员方法中不能调用非静态成员方法这一规则,也可以理解为,静态成员方法是属于类的,所以在编译器编译的时候,形参列表的最前面没有隐藏的this,而编译器在编译的时候,发现参数列表最前面没有隐藏的this,这时非静态成员方法前面无法补上this,由于编译器不知道是哪个对象在调用这个非静态成员方法,所以就会出现编译时错误

通过以上理解,我们也不难知道,静态成员方法中也不能调用非静态成员变量,原理也和上述一致,这里就不再进行解释了。但是需要注意的是,这里讲的是不能调用非静态成员变量,而不是说不能定义非静态成员变量,这两个概念是存在很大区别的。

http://www.jsqmd.com/news/774355/

相关文章:

  • 在Python项目中接入Taotoken实现多模型智能对话的完整指南
  • 从 DDPM 到 Flow Matching:生成模型的范式革命
  • 一名女性程序员迈向技术SEO的人生之书
  • Shadow Accept:智能自动确认工具,提升AI编程助手工作效率
  • 本地AI视频分析工具:基于Whisper与yt-dlp的智能双轨架构解析
  • AI时代下测试工程师对用例质量审核风险识别的核心能力
  • ChatGPT API本地调试利器:开源UI工具部署与高效使用指南
  • AI数字人开发实战:从语音驱动到视觉渲染的全栈架构解析
  • 缠论分析终极指南:3步用ChanlunX插件实现自动化技术分析
  • AI代码审查与测试重构:让测试代码也能“自我进化”
  • RGB888 转 YCbCr444 / YCbCr422 格式转换 (MATLAB实现)
  • 强化学习优化GAN图像生成:Adv-GRPO算法解析
  • 5分钟学会taskt:免费开源RPA工具让你轻松实现办公自动化革命
  • 解锁TIDAL无损音乐库:24-bit/192kHz音乐下载神器完全指南
  • AI模型部署新方案:用refresh-gpt-chat实现令牌自动管理与统一API接入
  • 2026年4月市场有实力的轻烧粉公司推荐,氢氧化镁/轻烧粉/轻质医药氧化镁/碳酸镁/氧化镁/氧化镁糊,轻烧粉实力厂家推荐 - 品牌推荐师
  • 基于Clean Architecture与CQRS的银行信贷系统后端架构实战
  • Python 爬虫进阶技巧:动态调整请求频率规避 IP 封禁
  • 《龙虾OpenClaw系列:从嵌入式裸机到芯片级系统深度实战60课》020、汇编语言基础——OpenClaw指令集的手写汇编实战
  • 龙虾跳转登录失败,提示ca证书不对
  • Arm Cortex-A75系统寄存器架构与编程实践
  • 创业团队如何利用统一API管理多个AI模型以控制成本
  • 非高斯随机系统轨迹优化:统计收缩与共形推断方法
  • VoXtream2:实时流式语音合成与动态语速控制技术解析
  • 第五篇 量子纠错轻量化改良:彻底摆脱实验室依赖的民用落地路径
  • Stackmoss:模块化工程化工具集,快速搭建现代开发技术栈
  • AI编程助手指令统一工具brief:告别手动同步,实现智能管理
  • AI辅助数据分析:用测试数据与覆盖率数据驱动质量改进
  • 从入门到精通:Gemini 3.1 Pro解决办公问题的完整指南
  • 基于Next.js与MongoDB的现代社交应用全栈开发实战解析