Java谜题畅读版之更多的类谜题

谜题66:一件私事

在下面的程序中,子类的一个域具有与超类的一个域相同的名字。那么,这个程序会打印出什么呢?
class Base {
    public String className = "Base";
}
class Derived extends Base {
    private String className = "Derived";
}
public class PrivateMatter {
    public static void main(String[ ] args) {
        System.out.println(new Derived().className);
    }
}
这个程序不能编译, 他说你你试图访问不可见的className.
如果className是一个实例方法,而不是一个实例域,那么Derived.className()将覆写Base.className(),而这样的程序是非法的。一个覆写方法的访问修饰符不能降低方法的可见性.
为className是一个域,所以Derived.className隐藏(hide)了Base.className,而不是覆盖了它.对一个域来说,当它要隐藏另一个域时,如果隐藏域的访问修饰符提供的访问权限比被隐藏域的少,尽管这么做不可取的,但是它确实是合法的。事实上,对于隐藏域来说,如果它具有与被隐藏域完全无关的类型,也是合法的:即使Derived.className是GregorianCalendar类型的,Derived类也是合法的。
尽管在Derived实例中的公共域Base.className被隐藏了,但是我们还是可以通过将Derived实例转型为Base来访问到它。
System.out.println(((Base)new Derived()).className);
这说明了覆写与隐藏之间的一个非常大的区别。一旦一个方法在子类中被覆写,你就不能在子类的实例上调用它了(除了在子类内部,通过使用super关键字来方法)。然而,你可以通过将子类实例转型为某个超类类型来访问到被隐藏的域,在这个超类中该域未被隐藏。

谜题67:对字符串上瘾

下面的程序就是在探究当你重用了一个平台类的名字时,会发生什么。
public class StrungOut {
    public static void main(String[] args) {
        String s = new String("Hello world");
        System.out.println(s);
    }
}

class String {
    private final java.lang.String s;
    public String(java.lang.String s) {
        this.s = s;
    }
    public java.lang.String toString() {
        return s;
    }
}
如果你运行程序,它会说java.lang.NoSuchMethodError: main. 可是main白纸黑字写在那里呢.
问题在于main的方法签名出问题了.

谜题68:灰色的阴影

下面的程序在相同的范围内具有两个名字相同的声明,并且没有任何明显的方式可以在它们二者之间做选择。这个程序会打印Black吗?它会打印White吗?甚至,它是合法的吗?
public class ShadesOfGray {
    public static void main(String[] args){
        System.out.println(X.Y.Z);
    }
}
class X {
    static class Y {
        static String Z = "Black";
    }
    static C Y = new C();
}
class C {
    String Z = "White";
}
有一条规则决定着程序的行为,即当一个变量和一个类型具有相同的名字,并且它们位于相同的作用域时,变量名具有优先权[JLS 6.5.2]。

谜题69:黑色的渐隐

假设你不能修改前一个谜题(谜题68)中的X和C这两个类。你能否编写一个类,其main方法将读取X.Y类中的Z域的值,然后打印它。注意,不能使用反射。
方法1:
public class FadeToBlack {
    public static void main(String[] args){
        System.out.println(((X.Y)null).Z);
    }
}
方法2:
public class FadeToBlack {
    static class Xy extends X.Y{ }
    public static void main(String[ ] args){
        System.out.println(Xy.Z);
    }
}

方法3:

public class ShadesOfGray {
    public static void main(String[] args){
    	X.Y a = new X.Y();
        System.out.println(a.Z);
    }
}

方法4:

public class FadeToBlack {
    public static <T extends X.Y> void main(String[] args){
        System.out.println(T.Z);
    }
}

谜题70:一揽子交易

下面这个程序设计在不同的包中的两个类的交互,main方法位于hack.TypeIt中。那么,这个程序会打印什么呢?
package hack;
import click.CodeTalk;
public class TypeIt {
    private static class ClickIt extends CodeTalk {
        void printMessage() {
            System.out.println("Hack");
        }
    }

    public static void main(String[ ] args) {
        ClickIt clickit = new ClickIt();
        clickit.doIt();
    }
}

package click;
public class CodeTalk {
    public void doIt() {
        printMessage();
    }

    void printMessage() {
        System.out.println("Click");
    }
}
经过一番分析,你会说,打印的是Hack,因为你实例化的是ClickIt的对象,最终调用printMessge也将调用ClickIt的。
这是不对的。printMessage这个方法只有包访问权限,包房问权限的方法在其他包是不可见,而写是不能被复写的。所以这两个printMessage之间没有关系,只是名字一样而已。
同样的道理可以扩充到类的私有方法上。私有方法在子类中不可见,且是不可重写的。比如下面:
public class Sub extends Super{
    public void doSomething(){
        System.out.println("Sub.doSomething");
    }
    
    public static void main(String[] args){
        Sub s = new Sub();
        s.doIt();
    }
}
class Super {
    private void doSomething(){
        System.out.println("super.doSomething");
    }
    public void doIt(){
        doSomething();
    }
}
如果让子类可以继承,最起码要是protected。

谜题71:进口税

在5.0版中,Java平台引入了大量的可以使操作数组变得更加容易的工具。下面这个谜题使用了变量参数、自动包装、静态导入以及便捷方法Arrays.toString。那么,这个程序会打印什么呢?
import static java.util.Arrays.toString;
class ImportDuty {
    public static void main(String[ ] args) {
        printArgs(1, 2, 3, 4, 5);
    }
    static void printArgs(Object... args) {
        System.out.println(toString(args));
    }
}
你可能会期望该程序打印[1,2,3,4,5],但是它不能通过编译。
编译器尝试着去应用Object.toString()。导入的toString方法被ImportDuty从Object那里继承而来的具有相同名字的方法所遮蔽(shade)。

谜题72:终极危难

本谜题旨在检验当你试图隐藏一个final域时将要发生的事情。下面的程序将做些什么呢?
class Jeopardy {
    public static final String PRIZE = "$64,000";
}

public class DoubleJeopardy extends Jeopardy {
    public static final String PRIZE = "2 cents";
    public static void main(String[ ] args) {
        System.out.println(DoubleJeopardy.PRIZE);
    }
}
你或许会说这个程序不能通过编译,因为被final修饰的不能被覆写或隐藏。 但是它打印了2 cents。
被final修饰的域只是不能被赋值多次。 这个题还说明了一点,子类final域可以隐藏父类final域。父类和子类的赋值语句都发生了,但是不作用在同一个域上。

谜题74:同一性的危机

下面的程序是不完整的,它缺乏对Enigma的声明,这个类扩展自java.lang.Object。请为Enigma提供一个声明,它可以使该程序打印false:
public class Conundrum {
    public static void main(String[] args) {
        Enigma e = new Enigma();
        System.out.println(e.equals(e));
    }
}
噢,还有一件事:你不能覆写equals方法。
方法是:你可以重载(overload)它。
final class Enigma {
    // Don’t do this!
    public Boolean equals(Enigma other){
         return false;
    }
}

名字重用的术语表

覆写(override)
一个实例方法可以覆写(override)在其超类中可访问到的具有相同签名的所有实例方法[JLS 8.4.8.1],从而使能了动态分派(dynamic dispatch);换句话说,VM将基于实例的运行期类型来选择要调用的覆写方法[JLS 15.12.4.4]。覆写是面向对象编程技术的基础,并且是唯一没有被普遍劝阻的名字重用形式:
class Base {
     public void f() { }
}

class Derived extends Base {
     public void f() { } // overrides Base.f()
}
隐藏(hide)
一个域、静态方法或成员类型可以分别隐藏(hide)在其超类中可访问到的具有相同名字(对方法而言就是相同的方法签名)的所有域、静态方法或成员类型。隐藏一个成员将阻止其被继承[JLS 8.3, 8.4.8.2, 8.5]:
class Base {
     public static void f() { }
}

class Derived extends Base {
     private static void f() { } // hides Base.f()
}

重载(overload)
在某个类中的方法可以重载(overload)另一个方法,只要它们具有相同的名字和不同的签名。由调用所指定的重载方法是在编译期选定的[JLS 8.4.9, 15.12.2]:
class CircuitBreaker {
     public void f(int i)     { } // int overloading
     public void f(String s) { } // String overloading
}
遮蔽(shadow)
一个变量、方法或类型可以分别遮蔽(shadow)在一个闭合的文本范围内的具有相同名字的所有变量、方法或类型。如果一个实体被遮蔽了,那么你用它的简单名是无法引用到它的;根据实体的不同,有时你根本就无法引用到它[JLS 6.3.1]:
class WhoKnows {
     static String sentence = "I don't know.";
     public static woid main(String[ ] args) {
          String sentence = “I know!”;   // shadows static field
          System.out.println(sentence);  // prints local variable
     }
}
尽管遮蔽通常是被劝阻的,但是有一种通用的惯用法确实涉及遮蔽。构造器经常将来自其所在类的某个域名重用为一个参数,以传递这个命名域的值。这种惯用法并不是没有风险,但是大多数Java程序员都认为这种风格带来的实惠要超过其风险:

class Belt {
     private final int size;
     public Belt(int size) { // Parameter shadows Belt.size
          this.size = size;
     }
}
遮掩(obscure)
一个变量可以遮掩具有相同名字的一个类型,只要它们都在同一个范围内:如果这个名字被用于变量与类型都被许可的范围,那么它将引用到变量上。相似地,一个变量或一个类型可以遮掩一个包。遮掩是唯一一种两个名字位于不同的名字空间的名字重用形式,这些名字空间包括:变量、包、方法或类型。如果一个类型或一个包被遮掩了,那么你不能通过其简单名引用到它,除非是在这样一个上下文环境中,即语法只允许在其名字空间中出现一种名字。遵守命名习惯就可以极大地消除产生遮掩的可能性[JLS 6.3.2, 6.5]:
public class Obscure {
     static String System;  // Obscures type java.lang.System
     public static void main(String[ ] args) {
          // Next line won't compile: System refers to static field
          System.out.println(“hello, obscure world!”);
     }
}

Java谜题 Java谜题1——表达式谜题 谜题1:奇数性 谜题2:找零时刻 谜题3:长整除 谜题4:初级问题 谜题5:十六进制的趣事 谜题6:多重转型 谜题7:互换内容 谜题8:Dos Equis 谜题9:半斤 谜题10:八两 Java谜题2——字符谜题 谜题11:最后的笑声 谜题12:ABC 谜题13:畜牧场 谜题14:转义字符的溃败 谜题15:令人晕头转向的Hello 谜题16:行打印程序 谜题17:嗯? 谜题18:字符串奶酪 谜题19:漂亮的火花(块注释符) 谜题20:我的是什么? 谜题21:我的是什么?第2幕 谜题22:URL的愚弄 谜题23:不劳无获 Java谜题3——循环谜题 谜题24:尽情享受每一个字节 谜题25:无情的增量操作 谜题26:在循环中 谜题27:变幻莫测的i值 谜题28:循环者 谜题29:循环者的新娘 谜题30:循环者的爱子 谜题31:循环者的鬼魂 谜题32:循环者的诅咒 谜题33:循环者遇到了狼人 谜题34:被计数击倒了 谜题35:一分钟又一分钟 Java谜题4——异常谜题 谜题36:优柔寡断 谜题37:极端不可思议 谜题38:不受欢迎的宾客 谜题39:您好,再见 谜题40:不情愿的构造器 谜题41:域和流 谜题42:异常为循环而抛 谜题43:异常地危险 谜题44:切掉 谜题45:令人疲惫不堪的测验 Java谜题5——谜题 谜题46:令人混淆的构造器案例 谜题47:啊呀!我的猫变成狗了 谜题48:我所得到的都是静态的 谜题49:比生命更大 谜题50:不是你的谜题51:那个点是什么? 谜题52:合计数的玩笑 谜题53:按你的意愿行事 谜题54:Null与Void 谜题55:特创论 Java谜题6——库谜题 谜题56:大问题 谜题57:名字里有什么? 谜题58:产生它的散列码 谜题59:什么是差? 谜题60:一行的方法 谜题61:日期游戏 谜题62:名字游戏 谜题63:更多同样的问题 谜题64:按余数编组 谜题65:一种疑似排序的惊人传奇 Java谜题7——更多谜题 谜题66:一件私事 谜题67:对字符串上瘾 谜题68:灰色的阴影 谜题69:黑色的渐隐 谜题70:一揽子交易 谜题71:进口税 谜题72:终极危难 谜题73:你的隐私正在公开 谜题74:同一性的危机 谜题75:头还是尾? 名字重用的术语表 Java谜题8——更多的库谜题 谜题76:乒乓 谜题77:搞乱锁的妖怪 谜题78:反射的污染 谜题79:这是狗的生活 谜题80:更深层的反射 谜题81:烧焦(字符化)到无法识别 谜题82:啤酒爆炸 谜题83:诵困难者的一神论 谜题84:被粗暴地中断 谜题85:惰性初始化 Java谜题9——高级谜题 谜题86:有毒的括号垃圾 谜题87:紧张的关系 谜题88:原生型的处理 谜题89:泛型迷药 谜题90:荒谬痛苦的超 谜题91:序列杀手 谜题92:双绞线 谜题93:的战争 谜题94:迷失在混乱中 谜题95:只是些甜点 ********************* Chapter 1. Introduction Chapter 2. Expressive Puzzlers Puzzle 1: Oddity Puzzle 2: Time for a Change Puzzle 3: Long Division Puzzle 4: It's Elementary Puzzle 5: The Joy of Hex Puzzle 6: Multicast Puzzle 7: Swap Meat Puzzle 8: Dos Equis Puzzle 9: Tweedledum Puzzle 10: Tweedledee Chapter 3. Puzzlers with Character Puzzle 11: The Last Laugh Puzzle 12: ABC Puzzle 13: Animal Farm Puzzle 14: Escape Rout Puzzle 15: Hello Whirled Puzzle 16: Line Printer Puzzle 17: Huh? Puzzle 18: String Cheese Puzzle 19: Classy Fire Puzzle 20: What's My Class? Puzzle 21: What's My Class, Take 2 Puzzle 22: Dupe of URL Puzzle 23: No Pain, No Gain Chapter 4. Loopy Puzzlers Puzzle 24: A Big Delight in Every Byte Puzzle 25: Inclement Increment Puzzle 26: In the Loop Puzzle 27: Shifty i's Puzzle 28: Looper Puzzle 29: Bride of Looper Puzzle 30: Son of Looper Puzzle 31: Ghost of Looper Puzzle 32: Curse of Looper Puzzle 33: Looper Meets the Wolfman Puzzle 34: Down for the Count Puzzle 35: Minute by Minute Chapter 5. Exceptional Puzzlers Puzzle 36: Indecision Puzzle 37: Exceptionally Arcane Puzzle 38: The Unwelcome Guest Puzzle 39: Hello, Goodbye Puzzle 40: The Reluctant Constructor Puzzle 41: Field and Stream Puzzle 42: Thrown for a Loop Puzzle 43: Exceptionally Unsafe Puzzle 44: Cutting Class Puzzle 45: Exhausting Workout Chapter 6. Classy Puzzlers Puzzle 46: The Case of the Confusing Constructor Puzzle 47: Well, Dog My Cats! Puzzle 48: All I Get Is Static Puzzle 49: Larger Than Life Puzzle 50: Not Your Type Puzzle 51: What's the Point? Puzzle 52: Sum Fun Puzzle 53: Do Your Thing Puzzle 54: Null and Void Puzzle 55: Creationism Chapter 7. Library Puzzlers Puzzle 56: Big Problem Puzzle 57: What's in a Name? Puzzle 58: Making a Hash of It Puzzle 59: What's the Difference? Puzzle 60: One-Liners Puzzle 61: The Dating Game Puzzle 62: The Name Game Puzzle 63: More of the Same Puzzle 64: The Mod Squad Puzzle 65: A Strange Saga of a Suspicious Sort Chapter 8. Classier Puzzlers Puzzle 66: A Private Matter Puzzle 67: All Strung Out Puzzle 68: Shades of Gray Puzzle 69: Fade to Black Puzzle 70: Package Deal Puzzle 71: Import Duty Puzzle 72: Final Jeopardy Puzzle 73: Your Privates Are Showing Puzzle 74: Identity Crisis Puzzle 75: Heads or Tails? A Glossary of Name Reuse Chapter 9. More Library Puzzlers Puzzle 76: Ping Pong Puzzle 77: The Lock Mess Monster Puzzle 78: Reflection Infection Puzzle 79: It's a Dog's Life Puzzle 80: Further Reflection Puzzle 81: Charred Beyond Recognition Puzzle 82: Beer Blast Puzzle 83: Dyslexic Monotheism Puzzle 84: Rudely Interrupted Puzzle 85: Lazy Initialization Chapter 10. Advanced Puzzlers Puzzle 86: Poison-Paren Litter Puzzle 87: Strained Relations Puzzle 88: Raw Deal Puzzle 89: Generic Drugs Puzzle 90: It's Absurd, It's a Pain, It's Superclass! Puzzle 91: Serial Killer Puzzle 92: Twisted Pair Puzzle 93: Class Warfare Puzzle 94: Lost in the Shuffle Puzzle 95: Just Desserts Appendix A. Catalog of Traps and Pitfalls Section 1. Lexical Issues Section 2. Integer Arithmetic Section 3. Floating-Point Arithmetic Section 4. Expression Evaluation Section 5. Flow of Control Section 6. Class Initialization Section 7. Instance Creation and Destruction Section 8. Other Class- and Instance-Related Topics Section 9. Name Reuse Section 10. Strings Section 11. I/O Section 12. Threads Section 13. Reflection Section 14. Serialization Section 15. Other Libraries Appendix B. Notes on the Illusions Ambiguous Figures Impossible Figures Geometrical Illusions: Size Geometrical Illusions: Direction Subjective Contours Anomalous Motion Illusions Illusions of Lightness Compound Illusions
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值