Java 修饰符详解:吐血整理,带你从底层语法和开发案例疏通这 11 种常见修饰符

简介: Java 修饰符详解:吐血整理,带你从底层语法和开发案例疏通这 11 种常见修饰符

文章目录


前言

在 Java 的语言体系中共有 11 种常见的修饰符,其在我们日常的开发中一般有四种使用情况:成员变量、成员方法、代码块和内部类,那么在应用过程中我们还应该具体注意些什么?通过本文中我们将从最基础的底层和原理来理解和疏通这些常见修饰符语法说明以及在常见的开发中如何使用。

image.png


一、11 种常见的 Java 修饰符

1.1、修饰符应用表

修饰符 构造方法 方法 数据 解释
(default) 类、构造方法、方法或数据域在所在的包中可见
public 类、构造方法、方法或数据域在任何包任何程序中都可见
private 构造方法、方法或数据域只在所在的类中可见
protected 构造方法、方法或数据域在所属的包中可见,或者在任何包中该类的子类中可见
static 定义类方法、类数据域或静态初始化模块
final 终极类不能扩展。终极方法不能在子类中修改。终极数据域是常量
abstract 抽象类必须被扩展。抽象方法必须在具体的子类中实现
native 用native修饰的方法表明它是用Java以外的语言实现的
synchronized 同一时间只有一个线程可以执行这个方法
strictfp 使用精确浮点数计算模式,保证在所有的Java虚拟机中计算结果都相同
transient 标记实例数据域,使其不进行序列化

1.2、修饰符访问权限对比

public > protected > default > private

说明:以下仅介绍我们常用的 7 种修饰符语法说明以及开发应用说明,另外 4 种用法查看修饰符应用表即可。

二、public 修饰符

2.1、public 修饰符语法说明

  • 修饰类、方法、变量。
  • 可以在任意位置访问,公共的。

2.2、public 修饰符开发应用

  • 开发中,通常类和业务方法都使用 public 修饰。

三、private 修饰符

3.1、private 修饰符语法说明

  • 修饰方法、变量、还可以修饰内部类。
  • 只能在本类中访问,私有的。

3.2、private 修饰符开发应用

  • 开发中,通常实体类(Entity,Vo)中的成员变量使用 private 修饰,会提供访问这些变量的方法 getter 或 setter,原则上要求不准定义私有的方法。
  • 一个实体数据的表通常对应一个实体类。

四、protected 修饰符

4.1、protected 修饰符语法说明

  • 修饰方法、变量、还可以修饰内部类。
  • 同一个包可以访问、子类可以访问(子类和父类不在同一个包也可以访问)。

4.2、protected 修饰符开发应用

  • 开发中,通常方法或变量是用来继承的,都使用 protected 修饰。
  • 在继承中,方法的重写,子类方法的访问权限必须大于或等于父类方法的访问权限,举例代码如下:
class Fu {
  public void play() {
  }
}
class Son extends Fu {
  void play() {
  }
}

五、default 修饰符(不加任何访问权限修饰符)

说明:使用 default 修饰符与不加任何访问权限修饰符效果是一样的。

5.1、default 修饰符语法说明

  • 修饰类、方法、变量。
  • 只能在同一个包中访问,子类也必须在同一个包中。

5.2、default 修饰符开发应用

  • 项目中,类、方法、变量根据需求,通常都会指定访问权限。

六、static 修饰符

由于static 修饰符作用较多,我们对其拆开进行逐步分析。

6.1、类(静态)变量与实例变量

  • 类变量:被存储在方法区中,“只有一份”,被所有对象共享。当类被加载的时候,立即被存储在方法区中,当类被卸载,类变量立即释放内存。
  • 实例变量:在创建对象之后,被分配到堆内存中,实例变量属于某个具体的对象。当创建对象,实例变量出现在堆内存中,当对象被垃圾回收,实例变量立即释放内存。

比如我们创建两个对象,代码如下:

Cell c1 = new Cell(4,5);
Cell c2 = new Cell(5,6);

当创建对象 c1,c2 时,实例变量(4,5),(5,6)出现在堆内存中,当对象 c1,c2 被垃圾回收,实例变量立即释放内存。

6.1.1、类(静态)变量与实例变量语法说明

  • Java 中 可以通过 static 关键字修饰变量达到全局变量的效果
  • static 修饰的变量(静态变量)属于类,在类第一次通过类加载器到 jvm 时被分配至方法区,所以我们也称其为类变量。

image.png

  • 没有 static 修饰的变量,称为实例变量。

6.1.2、类(静态)变量与实例变量开发应用

  • 类变量可以由类名直接访问,开发中推荐使用类名的全称。

比如我们定义一个实体类,代码如下:

public class Student {
  // 实例变量,在创建对象之后,被分配到堆内存中,实例变量属于某个具体的对象
  // 当创建对象,实例变量出现在堆内存中,当对象被垃圾回收,实例变量立即释放内存
  String name;
  // 类变量,被存储在方法区中,"只有一份",被所有对象共享
  static String jtName;
  public void print() {
    System.out.println(this.name);
    System.out.println(jtName);
  }
}

下次使用静态变量 jtName 时,我们直接使用 Student 这个类名直接调用即可。

同时我们也就可以理解下面两个对象的属性取值是一样的,代码如下:

public class Demo01 {
  public static void main(String[] args) {
    // TODO Auto-generated method stub
    Student stu1 = new Student();
    stu1.name = "张三";
    stu1.jtName = "王老师";
    Student stu2 = new Student();
    // 一般直接取类名
    // stu2.jtName = "卢老师";
    Student.jtName = "卢老师";
    System.out.println(stu1.name);// 张三
    System.out.println(stu2.name);// null
    System.out.println(stu1.jtName);// 卢老师
    System.out.println(stu2.jtName);// 卢老师
  }
}

6.2、类(静态)方法与实例方法

  • 静态方法:static 修饰的方法属于类方法,不需要创建对象就可以调用。static 方法中不能使用 this 和 super 等关键字,不能调用非 static 方法,只能访问所属类的静态成员变量和静态方法。静态方法(类方法),当类被加载,静态方法立即被加载到方法区中,类方法可以由类名直接调用。
  • 实例方法:没有 static 修饰的方法,实例方法,当创建对象之后,实例方法立即被加载到方法区中,多个实例共享一份实例方法。

6.2.1、类(静态)方法与实例方法语法说明

  • 类方法中,不能使用 this 关键字,类方法中不隐含调用该方法对象的参数。
  • 实例方法可以直接调用静态方法,静态方法不可以直接访问实例成员,必须创建对象,由对象访问。
  • 所有对象共享的数据,定义为静态变量,否则定义为实例变量方法,方法中没有访问实例成员,可以定义为静态方法。

6.2.2、类(静态)方法与实例方法开发应用

  • 项目中,通常工具类中的方法,都是静态的。

6.3、static 静态代码段

6.3.1、static 静态代码段语法说明

  • JVM 在加载类时会执行 static 静态代码段,常用于初始化静态变量。
  • static 代码只会在类被加载时执行且执行一次。
  • 静态优于对象。

6.3.2、static 静态代码段开发应用

  • 开发中,通常用于加载静态资源,读取配置文件等操作,在静态代码段中实现。

比如我们定义一个工具类,代码如下:

public class SomeUtil {
  // 默认的无参构造
  public SomeUtil() {
    System.out.println("创建对象!");
  }
  // 静态优于对象
  // 静态代码段 当类被加载,立即被执行,一个类在同一个进程中,只加载一次
  static {
    System.out.println("加载静态资源!");
  }
  // 实例代码段
  {
    System.out.println("实例代码段!");
  }
  public static void do1() {
    System.out.println("do1....");
  }
  public static void do2() {
    System.out.println("do2....");
  }
  public static void do3() {
    System.out.println("do3....");
  }
  public static void main(String[] args) {
    SomeUtil.do1();
    SomeUtil.do2();
    SomeUtil.do3();
    SomeUtil s1 = new SomeUtil();
    SomeUtil s2 = new SomeUtil();
  }
}

执行 main 方法,根据输出的内容我们可以明确看出执行的顺序。静态代码段只执行一次,然后是静态方法被执行,最后是 new 的对象执行无参构造和实例代码段,new 一次执行一次。

同时也可以得出我们的结论:静态优于对象,如下图所示:

image.png

6.4、static 内部类

  • static 内部类可以不依赖外部类实例对象而被实例化,而内部类需要在外部类实例化后才能被实例化。
  • 静态内部类不能访问外部类的普通变量,只能访问外部类的静态成员变量和静态方法。

七、final 修饰符

7.1、final 修饰符语法说明

  • final 类,不能被继承。
  • final 方法,不能被重写。
  • final 修饰的变量,是常量。

7.2、final 修饰符开发应用

  • 开发中,我们使用 final 定义数据字典。

比如:在如下 Card 类中我们定义数据字典,用于 main 函数的输出和查询。

说明:数据字典是指对数据的数据项、数据结构、数据流、数据存储、处理逻辑等进行定义和描述,其目的是对数据流程图中的各个元素做出详细的说明,使用数据字典为简单的建模项目。简而言之,数据字典是描述数据的信息集合,是对系统中使用的所有数据元素的定义的集合。

举例使用 final 定义数据字典,代码如下:

public class Card {
  // 开发中,使用final定义数据字典。
  public static final int SPADE = 1;
  public static final int HEART = 2;
  public static final int BLACK = 5;
  public static final int FLOWER = 6;
  public static final int THREE = 0;
  public static final int EIGHT = 5;
  public static final int JACK = 8;
  public static final int QUEEN = 9;
  public static final int KING = 10;
  public static final int ACE = 11;
  public static final int DUCE = 12;
  public static final int JOKER = 13;
  private int suit;
  private int num;
  public Card() {
  }
  public Card(int suit, int num) {
    this.suit = suit;
    this.num = num;
  }
  public int getSuit() {
    return suit;
  }
  public void setSuit(int suit) {
    this.suit = suit;
  }
  public int getNum() {
    return num;
  }
  public void setNum(int num) {
    this.num = num;
  }
  public static void main(String[] args) {
    Card card = new Card(Card.HEART, Card.THREE);
    System.out.println(card.getNum());
  }
}

八、abstract 修饰符

8.1、abstract 修饰符语法说明

  • 抽象的,可以修饰类,修饰方法

修饰抽象类

  • 抽象类存在的意义在于被继承。
  • 抽象类不可以创建对象。
  • abstract 不能和 final 一起使用 。

修饰抽象方法

  • 抽象方法,只有定义没有实现。
  • 如果一个类中有抽象方法,这个类必须是抽象类。
  • 一个抽象类中,可以没有抽象方法。
  • 抽象类的子类,必须实现父类中所有的抽象方法。

8.2、abstract 修饰符开发应用

  • 抽象类中既可以有默认实现的方法,又可以有没有实现的方法。
  • 接口的适配器——用子类去实现接口中的方法。

九、接口(特殊的抽象类)

9.1、接口语法说明

  • 特殊的抽象类接口中的方法都是抽象方法,接口中的变量都是静态常量。
  • 定义接口使用 interface 关键字。
  • 实现接口使用 implements 关键字。
  • 类实现了接口,必须实现接口中所有的方法。

如下我们定义了一个接口 MyInterface,代码如下:

public interface MyInterface {
  // 接口是高一级别的抽象。不能被实例化,所以只能定义常量
  // 定义了变量需要实例化,赋值才能使用,跟接口违背
  // 特殊的抽象类 接口中的方法都是抽象方法 接口中的变量都是静态常量
  int I = 10;
  // 如果类中所有的方法都是抽象方法,使用接口
  void method1();
  void method2();
}

这里我们 MyImpClass 类实现了接口,就必须实现接口中所有的方法,代码如下:

import java.io.Serializable;
/**
 * 其实适配器只是一个类,它实现了某种接口,提供了方法体。 
 * 这样,再用到这个接口时,可以直接继承适配器,这样就不需要把接口中的每一个方法再填充一遍了。
 * 只需要在这个类中复写一下需要用的方法。这样简单,方便。
 * 
 * @author bailu
 *  */
public class MyImpClass implements MyInterface, Serializable {
  // Serializable序列化
  private static final long serialVersionUID = 1L;
  // 重写接口的方法——适配器,
  @Override
  public void method1() {
    System.out.println(I);
  }
  @Override
  public void method2() {
  }
}

9.2、接口开发应用

  • 如果类中所有的方法都是抽象方法,使用接口。
  • 接口是用来制定标准或规范。
  • 可以降低组件之间的耦合度,扩展组件的功能。
  • 体现了设计模式中的开闭原则。

9.3、抽象类和接口的区别是什么?

  • 抽象类中,可以定义抽象方法和非抽象方法。接口中,所有的方法都是抽象方法。
  • 一个类只能继承一个抽象类。一个类可以实现多个接口,多个接口使用逗号分隔。

如下的类既实现了接口 MyInterface,同时实现了 Serializable 序列化序列化,代码如下:

import java.io.Serializable;
/**
 - 其实适配器只是一个类,它实现了某种接口,提供了方法体。 
 - 这样,再用到这个接口时,可以直接继承适配器,这样就不需要把接口中的每一个方法再填充一遍了。
 - 只需要在这个类中复写一下需要用的方法。这样简单,方便。
 - 
 - @author bailu
 -  */
public class MyImpClass implements MyInterface, Serializable {
  // Serializable序列化
  private static final long serialVersionUID = 1L;
  // 重写接口的方法——适配器,
  @Override
  public void method1() {
    System.out.println(I);
  }
  @Override
  public void method2() {
  }
}
  • 抽象类之间也可以继承,但是也只是支持单继承。
  • 接口之间也可以继承,一个接口可以继承多个接口。

9.4、什么是适配器?

适配器只是一个类,它实现了接口,提供了方法体。再用到这个接口时,可以直接继承适配器,这样就不需要把接口中的每一个方法再填充一遍了,只需要在这个类中复写一下需要用的方法。

接口很好地体现了设计模式中的开闭原则。

比如,我们做一个在线商城系统,就需要调用第三方支付——银行或者是支付宝的支付接口。我们就需要第三方为我们提供接口,里面定义了抽象的方法以及实现接口的方法——适配器,我们通过调用适配器里面的方法来完成支付,代码如下:

ZsBankInter obj = 获取实现类对象;
obj.send();
京东、淘宝
银行接口ZsBankInter  
send() 
class DoSend implements ZsBankInter{
    send()具体的方法
}

总结

修饰符在 Java 语言中有四种使用情况:成员变量、成员方法、代码块和内部类。以上我们总结了在日常的开发过程中会遇到的 11 种常见的修饰符,并从最基础的底层和原理理解和疏通这些常见修饰符语法说明以及常见的开发应用案例。其中具体的内容还有很多,本文就暂不一一列举,待日后根据开发需要补充完毕。

image.png


我是白鹿,一个不懈奋斗的程序猿。望本文能对你有所裨益,欢迎大家的一键三连!若有其他问题、建议或者补充可以留言在文章下方,感谢大家的支持!


相关文章
|
5月前
|
存储 Java 容器
Java基本语法详解
本文深入讲解了Java编程的基础语法,涵盖数据类型、运算符、控制结构及数组等核心内容,帮助初学者构建坚实的编程基础。
|
3月前
|
安全 前端开发 Java
《深入理解Spring》:现代Java开发的核心框架
Spring自2003年诞生以来,已成为Java企业级开发的基石,凭借IoC、AOP、声明式编程等核心特性,极大简化了开发复杂度。本系列将深入解析Spring框架核心原理及Spring Boot、Cloud、Security等生态组件,助力开发者构建高效、可扩展的应用体系。(238字)
|
4月前
|
存储 SQL NoSQL
Redis-常用语法以及java互联实践案例
本文详细介绍了Redis的数据结构、常用命令及其Java客户端的使用,涵盖String、Hash、List、Set、SortedSet等数据类型及操作,同时提供了Jedis和Spring Boot Data Redis的实战示例,帮助开发者快速掌握Redis在实际项目中的应用。
344 1
Redis-常用语法以及java互联实践案例
|
4月前
|
Java
Java基础语法与面向对象
重载(Overload)指同一类中方法名相同、参数列表不同,与返回值无关;重写(Override)指子类重新实现父类方法,方法名和参数列表必须相同,返回类型兼容。重载发生在同类,重写发生在继承关系中。
181 1
|
4月前
|
消息中间件 人工智能 Java
抖音微信爆款小游戏大全:免费休闲/竞技/益智/PHP+Java全筏开源开发
本文基于2025年最新行业数据,深入解析抖音/微信爆款小游戏的开发逻辑,重点讲解PHP+Java双引擎架构实战,涵盖技术选型、架构设计、性能优化与开源生态,提供完整开源工具链,助力开发者从理论到落地打造高留存、高并发的小游戏产品。
|
4月前
|
存储 Java 关系型数据库
Java 项目实战基于面向对象思想的汽车租赁系统开发实例 汽车租赁系统 Java 面向对象项目实战
本文介绍基于Java面向对象编程的汽车租赁系统技术方案与应用实例,涵盖系统功能需求分析、类设计、数据库设计及具体代码实现,帮助开发者掌握Java在实际项目中的应用。
206 0
|
5月前
|
JavaScript 安全 前端开发
Java开发:最新技术驱动的病人挂号系统实操指南与全流程操作技巧汇总
本文介绍基于Spring Boot 3.x、Vue 3等最新技术构建现代化病人挂号系统,涵盖技术选型、核心功能实现与部署方案,助力开发者快速搭建高效、安全的医疗挂号平台。
311 3
|
5月前
|
安全 Java 数据库
Java 项目实战病人挂号系统网站设计开发步骤及核心功能实现指南
本文介绍了基于Java的病人挂号系统网站的技术方案与应用实例,涵盖SSM与Spring Boot框架选型、数据库设计、功能模块划分及安全机制实现。系统支持患者在线注册、登录、挂号与预约,管理员可进行医院信息与排班管理。通过实际案例展示系统开发流程与核心代码实现,为Java Web医疗项目开发提供参考。
309 2
|
5月前
|
安全 Oracle Java
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡
430 0
JAVA高级开发必备·卓伊凡详细JDK、JRE、JVM与Java生态深度解析-形象比喻系统理解-优雅草卓伊凡