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


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


相关文章
|
10天前
|
Java API Maven
如何使用Java开发抖音API接口?
在数字化时代,社交媒体平台如抖音成为生活的重要部分。本文详细介绍了如何用Java开发抖音API接口,从创建开发者账号、申请API权限、准备开发环境,到编写代码、测试运行及注意事项,全面覆盖了整个开发流程。
53 10
|
16天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
34 4
|
18天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
47 4
|
22天前
|
jenkins Java 测试技术
如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例详细说明
本文介绍了如何使用 Jenkins 自动发布 Java 代码,通过一个电商公司后端服务的实际案例,详细说明了从 Jenkins 安装配置到自动构建、测试和部署的全流程。文中还提供了一个 Jenkinsfile 示例,并分享了实践经验,强调了版本控制、自动化测试等关键点的重要性。
58 3
|
23天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
24天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
45 2
|
24天前
|
监控 Java 数据库连接
在Java开发中,数据库连接管理是关键问题之一
在Java开发中,数据库连接管理是关键问题之一。本文介绍了连接池技术如何通过预创建和管理数据库连接,提高数据库操作的性能和稳定性,减少资源消耗,并简化连接管理。通过示例代码展示了HikariCP连接池的实际应用。
19 1
|
17天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
31 0
WK
|
23天前
|
开发框架 移动开发 Java
C++和Java哪个更适合开发移动应用
本文对比了C++和Java在移动应用开发中的优劣,从市场需求、学习难度、开发效率、跨平台性和应用领域等方面进行了详细分析。Java在Android开发中占据优势,而C++则适合对性能要求较高的场景。选择应根据具体需求和个人偏好综合考虑。
WK
42 0
|
Java
Java中需要注意的一些案例
Java中需要注意的一些案例
119 0
下一篇
无影云桌面