Java 中有时候也会出现真假美猴王的事件,请看下面的程序后打印什么?

public class Pet {public final String name;public final String food;public final String sound;public Pet(String name, String food, String sound) {this.name = name;this.food = food;this.sound = sound;}public void eat() {System.out.println(name + ": Mmmmm, " + food);}public void play() {System.out.println(name + ": " + sound + " " + sound);}public void sleep() {System.out.println(name + ": Zzzzzzz...");}public void live() {new Thread() {public void run() {while (true) {eat();play();sleep();}}}.start();}public static void main(String[] args) {new Pet("Fido", "beef", "Woof").live();}
}

我们期望程序打印:

Fido: Mmmmm, beefFido: Woof WoofFido: Zzzzzzz…

实际上报编译错误。

The method sleep(long) in the type Thread is not applicable for the arguments ()

查看 Thread 的 sleep 方法:

 /*** Causes the currently executing thread to sleep (temporarily cease* execution) for the specified number of milliseconds, subject to* the precision and accuracy of system timers and schedulers. The thread* does not lose ownership of any monitors.** @param millis* the length of time to sleep in milliseconds** @throws IllegalArgumentException* if the value of {@code millis} is negative** @throws InterruptedException* if any thread has interrupted the current thread. The* <i>interrupted status</i> of the current thread is* cleared when this exception is thrown.*/public static native void sleep(long millis) throws InterruptedException;/*** Causes the currently executing thread to sleep (temporarily cease* execution) for the specified number of milliseconds plus the specified* number of nanoseconds, subject to the precision and accuracy of system* timers and schedulers. The thread does not lose ownership of any* monitors.** @param millis* the length of time to sleep in milliseconds** @param nanos* {@code 0-999999} additional nanoseconds to sleep** @throws IllegalArgumentException* if the value of {@code millis} is negative, or the value of* {@code nanos} is not in the range {@code 0-999999}** @throws InterruptedException* if any thread has interrupted the current thread. The* <i>interrupted status</i> of the current thread is* cleared when this exception is thrown.*/public static void sleep(long millis, int nanos)throws InterruptedException {if (millis < 0) {throw new IllegalArgumentException("timeout value is negative");}if (nanos < 0 || nanos > 999999) {throw new IllegalArgumentException("nanosecond timeout value out of range");}if (nanos >= 500000 || (nanos != 0 && millis == 0)) {millis++;}sleep(millis);}

等等!

我不是要调用 Thread 的 sleep 方法,而是要调用 Pet 的 sleep 方法。为什么出现这种情况呢?

JSL-6.4 定义了这种情况:

It is a compile-time error if the name of a formal parameter is used to declare a new variable within the body of the method, constructor, or lambda expression, unless the new variable is declared within a class declaration contained by the method, constructor, or lambda expression.

注:如果形参的名字用在方法体、构造器体或者 lambda 表示式体内声明的新变量,将会抛出编译时错误,除非该新变量是在方法体、构造器体或者 lambda 表示式所包含的类声明内声明的。

It is a compile-time error if the name of a local variable v is used to declare a new variable within the scope of v, unless the new variable is declared within a class whose declaration is within the scope of v.

注:如果局部变量v的名字用来在v的作用域内声明新的变量,将会抛出编译时错误,除非该新变量是其类声明在v作用域的类内声明的。

It is a compile-time error if the name of an exception parameter is used to declare a new variable within the Block of the catch clause, unless the new variable is declared within a class declaration contained by the Block of the catch clause.

注:如果表达式参数的名字用在catch子句的语句块内声明的新变量,将会抛出编译时错误,除非该新变量是在catch子句的语句块所包含的类声明内声明的。

It is a compile-time error if the name of a local class C is used to declare a new local class within the scope of C, unless the new local class is declared within another class whose declaration is within the scope of C.

注:如果局部类c的名字用来在c的作用域内声明新的局部类,将会抛出编译时错误,除非该新局部类是在其类声明在c的作用域内的另一个类内声明的。

Java 中有 Shadowing (遮蔽))的描述,其中:

Shadowing:Some declarations may be shadowed in part of their scope by another declaration of the same name, in which case a simple name cannot be used to refer to the declared entity.

简单的意思是:在作用域内,一个地方的声明可能被另一个同名的声明所遮蔽。在这种情况下不能简单的使用名字来引用他们所声明的实体。

变量 Shadowing 举例:

class Test1 {public static void main(String[] args) {int i;for (int i = 0; i < 10; i++)System.out.println(i);}
}

编译报错,但编译检测也不是万能的,也有一些 trick 来逃避:

class Test2 {public static void main(String[] args) {int i;class Local {{for (int i = 0; i < 10; i++)System.out.println(i);}}new Local();}
}

如果在不同 block,则不会出现 Shadowing 的问题:

class Test3 {public static void main(String[] args) {for (int i = 0; i < 10; i++)System.out.print(i + " ");for (int i = 10; i > 0; i--)System.out.print(i + " ");System.out.println();}
}

原因找到了,那该怎么解决呢?

问题解决

方式一:线程内调用,改成 Pet.this.sleep(); 限定具体的方法:

public void live() {new Thread() {public void run() {while (true) {eat();play();Pet.this.sleep();}}}.start();
}

方式二:将 sleep 名称改为其它不冲突的名称,如 petSleep,然后线程内调用该方法:

public void petSleep() {System.out.println(name + ": Zzzzzzz...");
}

方式三:也是最好的方式,使用 Thread(Runnable) 构造器来替代对 Thread 的继承。那个匿名类不会再继承Thread.sleep 方法,故也不会有冲突了。

public void live(){new Thread(new Runnable(){public void run(){while(true){eat();play();sleep();}}}).start();
}

Java小白踩坑录 - Shadowing Obscuring 揭秘相关推荐

  1. 【Java笔记+踩坑】SpringBoot基础3——开发。热部署+配置高级+整合NoSQL/缓存/任务/邮件/监控

      导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...

  2. 西安交通大学915考研--编程题Java代码踩坑(2020年真题)

    西安交通大学915考研–编程题Java代码踩坑(2020年真题) 目录 西安交通大学915考研--编程题Java代码踩坑(2020年真题) 2020.1--寻找方程组的解 2020.2--几组数中筛选 ...

  3. 【Java笔记+踩坑】SpringBoot基础2——运维实用

      导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...

  4. 【Java笔记+踩坑】SpringBoot——基础

      导航: [黑马Java笔记+踩坑汇总]JavaSE+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud/SpringCloudAlibaba+黑马旅游+谷粒商城 目录 ...

  5. 从0.3开始搭建LeGO-LOAM+VLP雷达+小车实时建图(保姆级教程,小白踩坑日记)

    背景:SLAM小白,因为项目需要花了两天时间编译代码+连接雷达实现了交互. 踩了很多坑,简单记录一下,让后面感兴趣的朋友少走点弯路~ 肯定有很多不专业的.错误的地方,还请大家不吝赐教(噗通) 也可以见 ...

  6. 小白踩坑记:springboot运行一直报错:There was an unexpected error (type=Not Found, status=404).

    唉,最近在学习springboot集成thymeleaf模板引擎时,明明都配置的好好的,却一直给爷报错,给小爷整懵了:更奇特的是,就挺秃然的就发现似乎哪里有问题了,一经改正,终于拨云见日了... 首先 ...

  7. 海思芯片HI35xx NNIE踩坑录

    本文实际使用的芯片: hi3566v100 SDK: Hi3562V100_MobileCam_SDK_V2.0.0.1 1. open /dev/ive err  报错如下: [Func]:ive_ ...

  8. iOS旧版微信SDK升级1.8.6版本小白踩坑记

    虽然写了多年前端,但是一直都是写的lua,这次突然接到通知要升级微信SDK,以前也不是我捣鼓的,这下可愁坏了.本着万事不明,先备份改错的心态去下了微信SDK然后对比了下,发现跟以前没太大区别.主要区别 ...

  9. java foreach 原理_一不小心就让Java开发者踩坑的failfast是个什么鬼?

    1 什么是fail-fast 首先我们看下维基百科中关于fail-fast的解释: 在系统设计中,快速失效系统一种可以立即报告任何可能表明故障的情况的系统.快速失效系统通常设计用于停止正常操作,而不是 ...

最新文章

  1. jQuery对象与DOM对象的相互转化
  2. 2015中学计算机考试题,2017年初中信息技术考试试题及答案
  3. C#开发纽曼来电小秘书总结(指南)
  4. 所有配置_Springboot 打印所有配置
  5. c++ ifstream 文件不结束_C/C++编程笔记:你不知道的windows保存文件的坑
  6. 【渝粤教育】国家开放大学2018年秋季 3950T金融基础 参考试题
  7. 行内块的巧妙运用(HTML、CSS)
  8. 数据结构与算法之PHP排序算法(桶排序)
  9. 鸿蒙系统能玩魔兽世界吗,苹果M1可以玩魔兽世界吗 M1芯片能玩魔兽吗
  10. Eplan2.7 安装教程
  11. 【JAVA】java获取项目地址或tomcat绝对地址
  12. Eclipse_设置JSP模板
  13. 预测模型构建利器——基于logistic的列线图(R语言)
  14. BZOJ 4316: 小C的独立集 仙人掌 + 树形DP
  15. 如何防御ddos攻击?
  16. LQ_IM68A硅麦测试报告
  17. 爷青回!经典扫雷再现!
  18. 【做题笔记】P2327 [SCOI2005]扫雷
  19. NoteBurner iTunes DRM Audio Converter for Mac(音频转换工具) V2.4.4破解版
  20. ​网络赚钱的几个逻辑

热门文章

  1. 常见时间复杂度耗费时间从小到大是?
  2. 搜索引擎优化与信息检索有什么关联
  3. 解:一阶齐次或非齐次线性微分方程-详细推导
  4. 4种免费将图片转成PDF的方法,手机电脑都能用
  5. 2048网页版html项目报告,jQuery编写网页版2048小游戏
  6. PlatoFarm几大创新经济模型,给予当下元宇宙市场的启发
  7. Web服务器之Tomcat大全
  8. 【认知计算】Deepfake/Anti-deepfake综述探究
  9. 为啥在VS中使用scanf函数会有警告呢?如何解决此问题?(如何添加#define _CRT_SECURE_NO_WARNINGS 1)
  10. 测试宝宝体重的软件,如何测试宝宝身高体重