如何看破真假美猴王 ? --java中的Shadowing和Obscuring
故事背景
《西游记》第五十七回:唐僧因悟空又打死拦路强盗,再次把他撵走。六耳猕猴精趁机变作悟空模样,抢走行李关文,又把小妖变作唐僧、八戒、沙僧模样,欲上西天骗取真经。真假二悟空从天上杀到地下,菩萨、玉帝、地藏王等均不能辨认真假,直到雷音寺如来佛处,才被佛祖说出本相,猕猴精被悟空打死。
java之真假美猴王
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, beef
Fido: Woof Woof
Fido: 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. 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. 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. 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.
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();
}
参考资料
【1】https://docs.oracle.com/javase/specs/jls/se12/html/jls-6.html#jls-6.4
【2】java解惑
如何看破真假美猴王 ? --java中的Shadowing和Obscuring的更多相关文章
- java中的锁
java中有哪些锁 这个问题在我看了一遍<java并发编程>后尽然无法回答,说明自己对于锁的概念了解的不够.于是再次翻看了一下书里的内容,突然有点打开脑门的感觉.看来确实是要学习的最好方式 ...
- java中的字符串相关知识整理
字符串为什么这么重要 写了多年java的开发应该对String不陌生,但是我却越发觉得它陌生.每学一门编程语言就会与字符串这个关键词打不少交道.看来它真的很重要. 字符串就是一系列的字符组合的串,如果 ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- java中Action层、Service层和Dao层的功能区分
Action/Service/DAO简介: Action是管理业务(Service)调度和管理跳转的. Service是管理具体的功能的. Action只负责管理,而Service负责实施. DAO只 ...
- Java中常用集合操作
一.Map 名值对存储的. 常用派生类HashMap类 添加: put(key,value)往集合里添加数据 删除: clear()删除所有 remove(key)清除单个,根据k来找 获取: siz ...
- java中的移位运算符:<<,>>,>>>总结
java中有三种移位运算符 << : 左移运算符,num << 1,相当于num乘以2 >> : 右移运算符,num >& ...
- 关于Java中进程和线程的详解
一.进程:是程序的一次动态执行,它对应着从代码加载,执行至执行完毕的一个完整的过程,是一个动态的实体,它有自己的生命 周期.它因创建而产生,因调度而运行,因等待资源或事件而被处于等待状态,因完成任务而 ...
- Java中的进程和线程
Java中的进程与线程 一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是 ...
- Java中的进程与线程(总结篇)
详细文档: Java中的进程与线程.rar 474KB 1/7/2017 6:21:15 PM 概述: 几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进 ...
随机推荐
- [Python] Django框架入门5——静态文件、中间件、上传图片和分页
说明: 本文主要描述Django其他的内容,涉及静态文件处理.中间件.上传文件.分页等. 开发环境:win10.Python3.5.Django1.10. 一.静态文件处理 在Django项目的静态文 ...
- The Best Path(HDU5883)[欧拉路]2016青岛online
题库链接:http://acm.hdu.edu.cn/showproblem.php?pid=5883 欧拉回路裸题,第一次接触欧拉路的我是真的长见识了^-^ 懂了欧拉路这道题就是没什么问题了,欧拉路 ...
- Redis持久化的原理及优化
更多内容,欢迎关注微信公众号:全菜工程师小辉~ Redis提供了将数据定期自动持久化至硬盘的能力,包括RDB和AOF两种方案,两种方案分别有其长处和短板,可以配合起来同时运行,确保数据的稳定性. RD ...
- vmware12中安装MAC OS X 10.10
1. 准备工作 1) VMware Workstation 12 (去vmware官网下载即可) 2) unlocker 203 (OS X 插件补丁) 链接:http://pan.bai ...
- P3119 [USACO15JAN]草鉴定Grass Cownoisseur 分层图或者跑两次最长路
https://www.luogu.org/problemnew/show/P3119 题意 有一个有向图,允许最多走一次逆向的路,问从1再走回1,最多能经过几个点. 思路 (一)首先先缩点.自己在缩 ...
- LeetCode939 最小面积矩形
LeetCode939最小面积矩形 给定在 xy 平面上的一组点,确定由这些点组成的矩形的最小面积,其中矩形的边平行于 x 轴和 y 轴. 如果没有任何矩形,就返回 0. Input [[1,1],[ ...
- 牛客Wannafly挑战赛23 B.游戏
游戏 题目描述 小N和小O在玩游戏.他们面前放了n堆石子,第i堆石子一开始有ci颗石头.他们轮流从某堆石子中取石子,不能不取.最后无法操作的人就输了这个游戏.但他们觉得这样玩太无聊了,更新了一下规则. ...
- PAT L1-043. 阅览室
L1-043. 阅览室 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 天梯图书阅览室请你编写一个简单的图书借阅统计程序.当读者 ...
- 关闭Linux(Ubuntu)错误报告
关于错误报告 网上查了下,Ubuntu(包括elementary,elementary是基于Ubuntu的)桌面版预装了Apport,它是一个错误收集系统,会收集软件崩溃.未处理异常和其他,包括程序b ...
- Linux基础提高_系统性能相关命令
w 看系统的负载信息 用于显示已经登陆系统的用户列表,并显示用户正在执行的指令 uptime [root@localhost]#uptime 17:26:07 up 9:02, 3 users, lo ...