【小家java】对java中null、void、Void的理解学习

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【小家java】对java中null、void、Void的理解学习

相关阅读


【小家java】java5新特性(简述十大新特性) 重要一跃

【小家java】java6新特性(简述十大新特性) 鸡肋升级

【小家java】java7新特性(简述八大新特性) 不温不火

【小家java】java8新特性(简述十大新特性) 饱受赞誉

【小家java】java9新特性(简述十大新特性) 褒贬不一

【小家java】java10新特性(简述十大新特性) 小步迭代

【小家java】java11新特性(简述八大新特性) 首个重磅LTS版本


每篇一句

理解一门技术的原理,最好最扎实的方式就是自己尝试去实现一遍


1、概述


本篇博文很简单啊,主要说说咱们平时最长看见的null、void和Void等。一般人可能不会留意,但此文通过一些简单的例子,希望可以加深同学们对他哥几个的了解


2、栗子


关于null,估计很多人可能恨透它了,因为它是NullPointerException的罪魁祸首。但是用好了它,我们还是能成为好朋友滴。null是所有引用类型的默认值,但是我要澄清一些误解,null既不是对象也不是一种类型,它仅是一种特殊的值,你可以将其赋予任何引用类型,你也可以将null转化成任何类型(这个估计很多人没有用过)

public final class Main {
    public static void main(String[] args) {
        Main m = (Main) null; //这样子是不报错的 其实编译器底层会对null这样做处理
        System.out.println(m); //输出null
        m.doSomething(); //java.lang.NullPointerException
    }
    private void doSomething() {
        System.out.println("doSomething");
    }
}

对上述结果进行分析:第一个对null的强转,其实是java编译器底层的实现,看.class文件可以看出来结果。第二个,我们想到m的值肯定为null啊,为什么调用doSomething没有空指针呢?但下面代码就空指针了:

public final class Main {
    public static void main(String[] args) {
        Main m = (Main) null; //这样子是不报错的 其实编译器底层会对null这样做处理
        System.out.println(m); //输出null
        m.doSomething(); //java.lang.NullPointerException
    }
    private void doSomething() {
        System.out.println("doSomething");
    }
}


public final class Main {

   public static void main(String[] args) {

       Main m = (Main) null; //这样子是不报错的 其实编译器底层会对null这样做处理

       System.out.println(m); //输出null

       m.doSomething(); //java.lang.NullPointerException

   }


   private void doSomething() {

       System.out.println("doSomething");

   }

}

各位同学从这两个例子的对比,应该也能看出来了吧。所以对静态方法调用这里奉送两句话,记住就行:


所引用对象是否为null无关紧要,因为访问静态方法不需要实例对象。

如果引用不为null,运行时对象类型也无关紧要,因为静态调用不会导致动态调用分派。而是与类相关。

因此,静态方法的访问,不建议用实例调用,反而让语意变得晦涩了。最后提一点,在java中的自动拆装箱的过程中,如果遇到null值,处理的时候需要当心:


任何含有null值的包装类在Java拆箱生成基本数据类型时候都会抛出一个空指针异常


在看下面例子,判断null值的类型

public final class Main {
    public static void main(String[] args) {
        Main m = (Main) null;
        System.out.println(m instanceof Main); //返回false哦 返回false哦 返回false哦
        System.out.println(m.getClass()); //空指针
    }
}


我们会发现:如果使用了带有null值的引用类型变量,instanceof操作将会返回false。

我们可以使用或者!=操作来比较null值,但是不能使用其他算法或者逻辑操作,例如小于或者大于。在Java中**nullnull将返回true**。


接下来聊聊void和Void。可能很多人咋一看挺懵逼的,好像没啥区别啊。


void不是函数,是方法的修饰符,void的意思是该方法没有返回值,意思就是方法只会运行方法中的语句,但是不返回任何东西。 java.lang.Void是一种类型。例如给Void引用赋值null。通过Void类的源代码可以看到,Void类型不可以继承与实例化。

public final class Main {
    public void do1() {
        return; //返回void,return可写可不写
    }
    public Void do2() {
        return null; //此处必须返回null 返回其余类型都不好使
    }
}


public final class Main {
    public static void main(String[] args) {
        System.out.println(Void.class); //class java.lang.Void
        System.out.println(void.class); //void
        //类似于下面的
        System.out.println(Integer.class); //class java.lang.Integer
        System.out.println(int.class); //int
    }
}


public final class Main {
    public static void main(String[] args) {
        System.out.println(Void.class); //class java.lang.Void
        System.out.println(void.class); //void
        //类似于下面的
        System.out.println(Integer.class); //class java.lang.Integer
        System.out.println(int.class); //int
    }
}


如上,可以清晰的看到void和Void的一些区别,但有些人可能会问,Void我们到底有什么用呢?其实在泛型出现之前,Void一般用于反射之中。例如,下面的代码打印**返回类型为void(这里必须借助Void类)**的方法名:


public static <T> T doInLock(Supplier<T> supplier, RedisTemplate<String, String> redisTemplate, String lockKey) {
        //这里我们使用函数式变成supplier来提供回调函数并且接收返回值
        return supplier.get();
    }

还有有的时候,并不需要返回值的抽像性设计,比如我设计的分布式锁:RedisLock


public static <T> T doInLock(Supplier<T> supplier, RedisTemplate<String, String> redisTemplate, String lockKey) {
        //这里我们使用函数式变成supplier来提供回调函数并且接收返回值
        return supplier.get();
    }


如上,如果使用者实现supplier方法并不需要返回值怎么办呢?这个时候最优雅的处理方式如下:

LockUtil.doInLock(() -> {
  ..... //处理一系列业务逻辑
  return Void.class; //返回这个就非常的优雅了,阅读起来也十分明白
}, stringRedisTemplate,"aaa");


另外,再介绍两种情况下Void的使用,虽然使用较少,但技多不压身嘛。


泛型出现后,某些场景下会用到Void类型。例如Future用来保存结果,但如果操作并没有返回值呢?这种情况下就可以用Future表示。当调用get后结果计算完毕则返回后将会返回null。(原理同上示例)


另外Void也用于无值的Map中(只需要key不需要值),例如Map<,Void>这样map将具Set有一样的功能。


因此当你使用泛型时函数并不需要返回结果或某个对象不需要值时候这是可以使用java.lang.Void类型表示。


Void类可能本身作用就只是不起任何作用,但是本身只是一个占位符类。即Void类本身只是一个占位符类,不能被实例化,多用于泛型中作占位符使用。


3、使用场景


惊不惊喜,意不意外,没想到平时毫不起眼的一个Void,竟然还是有这么多使用场景的。这里附上Void.class源码里的一句代码,就更加能辅助小伙伴们理解了


public static final Class<Void> TYPE = (Class<Void>) Class.getPrimitiveClass("void");

4、最后


本文的内容可能平时使用很少,但我建议,这个可以当作装逼神器,哈哈。so,这技能你get到了吗?


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
25天前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
86 43
Java学习十六—掌握注解:让编程更简单
|
10天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
1月前
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
31 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
18天前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
1月前
|
Java 编译器
Java“返回类型为 void 的方法不能返回一个值”解决
在 Java 中,如果一个方法的返回类型被声明为 void,那么该方法不应该包含返回值的语句。如果尝试从这样的方法中返回一个值,编译器将报错。解决办法是移除返回值语句或更改方法的返回类型。
|
1月前
|
小程序 Oracle Java
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
这篇文章是关于JVM基础知识的介绍,包括JVM的跨平台和跨语言特性、Class文件格式的详细解析,以及如何使用javap和jclasslib工具来分析Class文件。
41 0
JVM知识体系学习一:JVM了解基础、java编译后class文件的类结构详解,class分析工具 javap 和 jclasslib 的使用
|
1月前
|
前端开发 Java 应用服务中间件
Javaweb学习
【10月更文挑战第1天】Javaweb学习
32 2
|
1月前
|
存储 安全 Java
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
【用Java学习数据结构系列】探索顺序表和链表的无尽秘密(附带练习唔)pro
23 3
|
1月前
|
存储 安全 Java
【用Java学习数据结构系列】探索栈和队列的无尽秘密
【用Java学习数据结构系列】探索栈和队列的无尽秘密
30 2
|
1月前
|
存储 Java 编译器
【用Java学习数据结构系列】初识泛型
【用Java学习数据结构系列】初识泛型
20 2