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

本文涉及的产品
云数据库 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
相关文章
|
2天前
|
设计模式 消息中间件 算法
【实习总结】Java学习最佳实践!
【实习总结】Java学习最佳实践!
22 3
|
2天前
|
数据采集 安全 Java
Java并发编程学习12-任务取消(上)
【5月更文挑战第6天】本篇介绍了取消策略、线程中断、中断策略 和 响应中断的内容
29 4
Java并发编程学习12-任务取消(上)
|
19小时前
|
NoSQL 算法 Java
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
【redis源码学习】持久化机制,java程序员面试算法宝典pdf
|
2天前
|
安全 Java 开发者
Java一分钟之-Optional类:优雅处理null值
【5月更文挑战第13天】Java 8的`Optional`类旨在减少`NullPointerException`,提供优雅的空值处理。本文介绍`Optional`的基本用法、创建、常见操作,以及如何避免错误,如直接调用`get()`、误用`if (optional != null)`检查和过度使用`Optional`。正确使用`Optional`能提高代码可读性和健壮性,建议结合实际场景灵活应用。
21 3
|
2天前
|
存储 算法 搜索推荐
滚雪球学Java(27):从零开始学习数组:定义和初始化
【5月更文挑战第2天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
10 3
|
2天前
|
缓存 Java 数据库
Java并发编程学习11-任务执行演示
【5月更文挑战第4天】本篇将结合任务执行和 Executor 框架的基础知识,演示一些不同版本的任务执行Demo,并且每个版本都实现了不同程度的并发性。
34 4
Java并发编程学习11-任务执行演示
|
2天前
|
数据库连接
java+ssm+vue代码视频学习讲解
java+ssm+vue代码视频学习讲解
10 0
|
2天前
|
Java 测试技术 Maven
Spring Boot单元测试报错java.lang.IllegalStateException: Could not load TestContextBootstrapper [null]
Spring Boot单元测试报错java.lang.IllegalStateException: Could not load TestContextBootstrapper [null]
|
2天前
|
Java
java Map删除值为null的元素
java Map删除值为null的元素
|
2天前
|
算法 Java 大数据
Java从入门到精通学习报告
Java从入门到精通学习报告
20 1