Java语言关键字最全理解

语言
一、Java
1. 语言基础知识

  • 常量
    Java中常量有:整型、浮点型、字符型、字符串常量、布尔型、空常量等六种
  • 数据类型
    Java数据类型分为基本数据类型引用类型两种,基本数据类型如下表:
    在这里插入图片描述
    * 注:不是基本类型就是引用类型,如字符串、类、接口、数组、枚举、注解等,数值范围的大小和字节数无关。

2.重点关键字解析

  • final

1.概述

final关键字的意思是最终的、不可改变的,可用来修饰类、方法、变量(实例变量和局部变量)和参数。被final修饰的类不能再有子类,所有的方法默认带上final;被final修饰的方法不能被子类重写,但不影响子类使用和重载;被final修饰的变量一次赋值不能再被修改,实例变量可以先声明,要在在每个构造函数中赋值,局部变量声明后,保证使用之前赋值即可;被final修饰的参数,值不能再在函数中修改。
2.关键知识点
- final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。final变量一旦被初始化后不能再次赋值。
- 本地变量必须在声明时赋值。 因为没有初始化的过程
- 在匿名类中所有变量都必须是final变量。
- final方法不能被重写, final类不能被继承
- 接口中声明的所有变量本身是final的。类似于匿名类
- final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
- final方法在编译阶段绑定,称为静态绑定(static binding)。
- 将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
3.使用final的好处
- 提高了性能,JVM在常量池中会缓存final变量
- final变量在多线程中并发安全,无需额外的同步开销
- final方法是静态编译的,提高了调用速度
- final类创建的对象是只可读的,在多线程可以安全共享
4.底层原理
final的底层使用了内存屏障,禁止指令重排。在写入final域时,编译器会在 final 域的写之后,构造函数 return 之前,插入一个 StoreStore 屏障,禁止处理器把 final 域的写重排序到构造函数之外,保证对象被其他线程引用可见之前,final域初始完成;在读final域时,编译器会在读 final 域操作的前面插入一个 LoadLoad 屏障(注意,这个规则仅仅针对特殊的处理器如alpha 处理器)
Tip:
final常常和static共同修饰成员变量来当作常数使用。

参考
https://www.infoq.cn/article/java-memory-model-6
https://www.cnblogs.com/AliCoder/p/11594960.html

  • static

1.概述
static关键字表示静态的意思,可用来修饰实例变量和方法。所修饰的实例变量称为静态变量,在内存中只存在一个副本,归类所有,被所有该类对象共享;被static修饰的方法称为静态方法,也是归类所有,被所有该类对象共享。
2.关键知识点

  • 静态变量,静态方法,静态代码块在类第一次加载时初始化完成,只初始化一次,优先于对象的初始化。
  • 静态不能访问非静态,反之可以,因为static先初始化,对象成分后初始化(先者不知后者)。
  • 静态方法中没有this、super。
  • 静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)
    3.使用static的好处
    方便在没有创建对象的情况下来进行调用(方法/变量)
    Tip:
    • static方法是属于类的,非实例对象,在JVM加载类时,就已经存在内存中,不会被虚拟机GC回收掉,这样内存负荷会很大,但是非static方法会在运行完毕后被虚拟机GC掉,减轻内存压力;
    • 构造方法不是静态方法,只是可以静态绑定而已。
    • 归类所有的方法都不能被重写和覆盖,如private、final、static修饰的方法

参考
https://blog.csdn.net/kuangay/article/details/81485324
https://www.iteye.com/blog/rednaxelafx-652719

  • this

1.概述
this表示当前对象,即哪个对象调用方法this就代表哪个对象。this可用来调用本类属性,类的方法和类的其他构造方法(要放在构造方法的第一条语句)
2.作用

  • 区分同名变量

  • 作为方法名来初始化对象

  • 作为参数传递

  • 作为返回值
    Tip:
    除了静态方法外,每个成员方法都默认带有this参数

  • super

1.概述
super代表着父类,用来初始化父类和调用父类属性和方法,子类的每个构造函数中默认都带有super()
2.作用

  • 作为父类句柄

  • 区别子类和父类同名变量

  • 作为方法名来初始化对象
    Tip:
    this()和super()不能存在一个构造函数中

  • abstract

1.概述
abstract为抽象的意思,用来修饰类和方法,抽象方法只存在于抽象类中,没有方法体,必须实现才能使用;抽象类不能实例化,必须由子类实现才能使用,子类必须实现抽象类中所有的抽象方法。
2.关键知识点

  • 抽象方法没有自己的主体(没有{}包起来的业务逻辑),跟接口中的方法有点类似,所以我们没法直接调用抽象方法。

  • 抽象方法不能用private修饰,因为抽象方法必须被子类实现(覆写),而private权限对于子类来,说是不能访问的,所以就会产生矛盾

  • 抽象方法也不能用static修饰,试想一下,如果用static修饰了,那么我们可以直接通过类名调用,而抽象方法压根就没有主体,没有任何业务逻辑,这样就毫无意义了。

  • 用abstract关键字来表达的类,其表达形式为:(public)abstract class 类名{}

  • 抽象类不能被实例化,也就是说我们没法直接new 一个抽象类。抽象类本身就代表了一个类型,无法确定为一个具体的对象,所以不能实例化就合乎情理了,只能由它的继承类实例化。

  • 抽象类虽然不能被实例化,但有自己的构造方法

  • 抽象类与接口(interface)有很大的不同之处,接口中不能有实例方法去实现业务逻辑,而抽象类中可以有实例方法,并实现业务逻辑,比如我们可以在抽象类中创建和销毁一个线程池。

  • 抽象类不能使用final关键字修饰,因为final修饰的类是无法被继承,而对于抽象类来说就是需要通过继承去实现抽象方法,这又会产生矛盾。

  • 如果一个类中至少有一个抽象方法,那么这个类一定是抽象类,但反之则不然。也就是说一个抽象类中可以没有抽象方法。这样做的目的是为了此类不能被实例化。

  • 如果一个类继承了一个抽象类,那么它必须全部覆写抽象类中的抽象方法,当然也可以不全部覆写,如果不覆写全部抽象方法则这个子类也必须是抽象类(这样做就无意义了)
    3.作用

  • 由于抽象类不能被实例化,最大的好处就是通过方法的覆盖来实现多态的属性。也就是运行期绑定。

  • 抽象类将事物的共性的东西提取出来,由子类继承去实现,代码易扩展、易维护。
    Tip:
    对于抽象类中的非statci(静态)和非abstract(抽象)方法中的this关键字代表的是它的继承类,而非抽象类本身,这个好理解,因为抽象类本身不能被实例化。如果有多个继承类,谁调用this就代表谁。

参考
https://blog.csdn.net/weixin_40096176/article/details/79094991

  • interface
    1.概述
    interface意思为接口,用来定义一个接口,是抽象方法和定义常数值的集合,从本质上讲,接口是一种百分之百的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现(jdk1.8之前)。在jdk8以后,可以定义默认方法,私有方法和静态方法。
    2.关键知识点

  • 我们不能直接去实例化一个接口,因为接口中的方法都是抽象的,是没有方法体的;但是,我们可以使用接口类型的引用指向一个实现了该接口的对象,并且可以调用这个接口中的方法。(实际上就是使用了Java中多态的特性)。

  • 接口中没有构造方法

  • 一个类可以实现不止一个接口

  • 一个接口可以继承于另一个接口,或者另一些接口,接口也可以继承,并且可以多继承

  • 一个类如果要实现某个接口的话,那么它必须要实现这个接口中的所有抽象方法

  • 接口中所有的方法都是抽象的和public的,所有的属性都是public static final的。(jdk1.8之前)。
    3.作用

  • 接口被用来描述一种抽象,定义一种标准,实现多态属性。

  • 接口用来弥补Java类无法实现多继承的局限。

  • 接口也被用来实现解耦(面向接口编程)。

  • 接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?原因是抽象类内部可能包含非final的变量,但是在接口中存在的变量一定是final,public,static的
    Tip:
    并不是所有的接口内部都必须要有方法,如Seriallizable接口。jdk1.8以后接口中可以定义默认方法,可以解决接口升级问题;接口中定义的静态方法只能用接口类来访问。jdk9开始,接口中允许定义私有方法,可以解决多个默认方法之间重复代码问题;静态私有方法,可以解决多个静态方法之间重复代码问题。
    参考
    https://blog.csdn.net/sun_shine56/article/details
    https://blog.csdn.net/qq_19782019/article/details

  • enum
    1.概述
    enum关键字用来创建枚举类型,用来存放常量。enum 的语法结构尽管和 class 的语法不一样,但是经过编译器编译之后产生的是一个class文件。该class文件经过反编译可以看到实际上是生成了一个类,该类继承了java.lang.Enum。
    2.作用
    用来统一管理常量。
    参考
    https://www.cnblogs.com/hyl8218/p/5088287.html
    https://blog.csdn.net/qq_39949109/article/details/80432477

  • switch
    1.概述
    switch是Java内置关键字,作为程序的一种选择结构,和if-else的作用一样,但switch只支持byte,short,int,char及其包装类,以及enum和字符串(jdk1.7以后)

2.关键知识点

  • case语句中少写了break,编译不会报错,但是会一直执行之后所有case条件下的语句而不再判断,直到default语句。
  • 若果没有符合条件的case就执行default下的代码块,default并不是必须的,也可以不写。
  • case之后可以直接是常量数值,也可以是一个使用常量计算式;但不能是变量或带有变量的表达式,当然也不能是其他非支持类型。
  • 在case与常量值之后,需要一个冒号,请注意不要疏忽。
  • 必要时,可在各个case中使用{}来明确产生独立的复合语句。

3.作用

  • 使用switch作选择,使代码逻辑看起来更加的清晰,多个分支选择的时候比起使用if-else更加的方便;缺点就是对类型有限制。

  • 提高性能,switch的性能要比if-else高,但在99.99%的情况下,性能是一样的,除非分支的情况很巨大。

  • 4.原理
    switch是通过lookupswitch指令tableswitch指令实现的,当switch的case比较稀疏的时候,使用lookupswitch指令对int值的case进行一一比较,直至找到对应的case(这里的查找,可以优化为二分查找);当switch的case比较密集的时候,使用tableswitch指令把case的值作为switch的下标,可以在时间复杂度为O(1)的情况下找到对应的case(可以类比HashMap)。
    Tip:
    java虚拟机的tableswitch和 lookupswitch指令仅对int数据有效,所以switch支持的类型都是能转化为int类型,至于为什么是int类型,应该是基于性能和实现的复杂度的考量。enum是直接用枚举的顺序当作相关的case,string类是使用哈希码和值比较实现。
    参考
    https://www.jb51.net/article/174019.htm
    https://www.cnblogs.com/balmylee/articles/4208414.html
    https://www.cnblogs.com/Wilange/p/7872638.html

  • finally
    1.概述
    finally不能单独使用,必须和try或者try-catch配合使用。
    2.关键知识点

  • 不管有木有出现异常,finally块中代码都会执行,除非在执行到finally之前jvm退出了(比如System.exit(0))。

  • 当try和catch中有return时,finally仍然会执行。

  • finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的。

  • finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。

  • native
    1.概述
    native修饰的方法为本地方法,和abstract修饰的方法一样,只有方法签名,没有方法体。native方法表示的是非Java语言实现的,如是C或的C++。
    2.作用
    由于Java语言无法访问操作系统底层信息(比如:底层硬件设备等),需要借助C语言来完成。本地方法非常有用,因为它有效地扩充了jvm。事实上,我们所写的java代码已经用到了本地方法,在sun的java的并发(多线程)的机制实现中,许多与操作系统的接触点都用到了本地方法,这使得java程序能够超越java运行时的界限。有了本地方法,java程序可以做任何应用层次的任务
    参考
    https://blog.csdn.net/zw6161080123/article/details

  • strictfp
    1.概述
    strictfp, 即 strict float point (精确浮点),可以将一个类、接口以及方法声明为strictfp,但是不允许对接口中的方法以及构造函数声明strictfp关键字,一旦使用了strictfp来声明一个类、接口或者方法时,那么所声明的范围内Java的编译器以及运行环境会完全依照浮点规范IEEE-754来执行,使得浮点运算更加精确
    参考
    https://blog.csdn.net/redv/article/details

  • transient
    1.概述
    transient关键字表示瞬态的意思,用来修饰成员变量,当对象实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
    2.关键知识点

  • 变量被transient修饰,变量将不会被序列化。

  • transient关键字只能修饰变量,而不能修饰方法和类。

  • 被static关键字修饰的变量不参与序列化,一个静态static变量不管是否被transient修饰,均不能被序列化。

  • final变量值参与序列化,final transient同时修饰变量,final不会影响transient,一样不会参与序列化。

  • 本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口

  • 反序列化后类中static型变量的值实际上是当前JVM中对应static变量的值,这个值是JVM中的并不是反序列化得出的。
    3.作用
    被transient关键字修饰导致不被序列化,其优点是可以节省存储空间。优化程序!随之而来的是会导致被transient修饰的字段会重新计算,初始化!同时也做到安全保护

Tip:
静态变量不管加不加transient都不会被序列化,使用实现Externalizable接口实例化对象时,和加不加transient没有关系。

参考
https://www.cnblogs.com/yichunguo/p/11923126.html

  • volatile
    1.概述
    volatile是Java提供的轻量级同步机制,Java语言包含两种内在的同步机制:synchronized修饰的同步方法(或同步块)和volatile变量,相比于synchronized(synchronized通常称为重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度。但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其使用也更容易出错。
    2.作用
  • 保证不同线程之间共享变量可见性,但不保证原子性。
  • 禁止指令重排。
  • 3.原理
    volatile可以保证线程可见性且提供了一定的有序性,但是无法保证原子性。在JVM底层volatile是采用缓存一致性协议MESI和“内存屏障”来实现的。观察加入volatile关键字和没有加入volatile关键字时所生成的汇编代码发现,加入volatile关键字时,会多出一个lock前缀指令(汇编代码是:Lock addl),lock前缀指令实际上相当于一个内存屏障(也成内存栅栏),内存屏障会提供3个功能:
  • 它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成。
  • 它会强制将对缓存的修改操作立即写入主存
  • 如果是写操作,它会导致其他CPU中对应的缓存行无效
    Tip:
    volatile保证可见性,但不保证原子性,DCL(双重检查锁)一定要加volatile;volatile不适用于非原子性操作,如a++,volatile的一个重要作用就是和CAS(Compare and Swap,采用while循环很浪费cpu资源)结合,保证了原子性,如java.util.concurrent.atomic包下的类。

参考
https://blog.csdn.net/u012723673/article/details/80682208

  • synchronized
    1.概述
    Synchronized是Java中解决并发问题的一种最常用的方法,它是一种重量级的同步机制,可用来修饰实例方法、静态方法和同步块。
    2.作用
  • 确保线程互斥的访问同步代码。
  • 保证共享变量的修改能够及时可见(保证可见性)。
  • 有效解决指令重排序问题。
    3.原理
    java 虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现, 无论是显式同步(有明确的 monitorenter 和 monitorexit 指令,即同步代码块)还是隐式同步都是如此。在 Java 语言中,同步用的最多的地方可能是被 synchronized 修饰的同步方法。同步方法 并不是由 monitorenter 和 monitorexit 指令来实现同步的,而是由方法调用指令读取运行时常量池中方法的 ACC_SYNCHRONIZED 标志来隐式实现的。对象的锁信息和锁标志存在于对象头Mark Word中。对象头和锁的关系如下图(网上大神总结):
    在这里插入图片描述

Tip:
在JVM中,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充。锁状态有:无锁状态,偏向锁(比较Thread ID),轻量级锁(CAS自旋),重量级锁(依赖于底层的操作系统的Mutex Lock来实现的)。
参考
https://www.cnblogs.com/paddix/p/5367116.html
https://blog.csdn.net/javazejian/article/details
https://www.jianshu.com/p/76959115d486

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值