Java的隐藏功能

295

17
请注意,并不总是一个好主意使用这些隐藏的功能;往往会让阅读你代码的其他人感到惊讶和困惑。 - Kevin Bourrillion
1
你(/某人)应该像C#问题那样将答案整洁地总结在问题正文中。 - ripper234
100个回答

53

使用this关键字从内部类中访问包含类的字段/方法。在下面这个有些牵强险峻的例子中,我们想要从匿名内部类中使用容器类的sortAscending字段。使用ContainerClass.this.sortAscending而不是this.sortAscending就可以解决问题。

import java.util.Comparator;

public class ContainerClass {
boolean sortAscending;
public Comparator createComparator(final boolean sortAscending){
    Comparator comparator = new Comparator<Integer>() {

        public int compare(Integer o1, Integer o2) {
            if (sortAscending || ContainerClass.this.sortAscending) {
                return o1 - o2;
            } else {
                return o2 - o1;
            }
        }

    };
    return comparator;
}
}

4
只有在你使用了与方法参数名称相同的名称来屏蔽该名称时(即在你的情况下),才需要这样做。如果你将参数命名为其他名称,则可以直接访问Container类的sortAscending成员变量,而无需使用“this”。 - sk.
7
引用封闭类(class)仍然是有用的,例如如果你需要将其传递给某个方法或构造函数。 - PhiLho
在Android布局开发中经常使用MyActivity.this来获取上下文,例如从按钮的监听器中获取。 - espinchi

52

这并不是一个功能,而是我最近在某个网页上发现的一种有趣的技巧:

class Example
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
    http://Phi.Lho.free.fr

    System.exit(0);
  }
}

这是一个有效的Java程序(尽管它会生成警告)。 如果您不明白原因,请参见Gregory的答案!;-) 好吧,这里的语法突出显示也提示了一下!


15
整洁,带有评论的标签 :) - Thorbjørn Ravn Andersen

46

虽然这不完全是“隐藏功能”,也没有什么用处,但在某些情况下可能会非常有趣:
sun.misc.Unsafe类 - 允许您在Java中实现直接内存管理(如果您尝试很多次甚至可以编写自修改的Java代码):

public class UnsafeUtil {

    public static Unsafe unsafe;
    private static long fieldOffset;
    private static UnsafeUtil instance = new UnsafeUtil();

    private Object obj;

    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(true);

            unsafe = (Unsafe)f.get(null);
            fieldOffset = unsafe.objectFieldOffset(UnsafeUtil.class.getDeclaredField("obj"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    };
}

20
这是一个Sun* API,它并不是Java语言本身的一部分。 - DW.
Unsafe 类中还有其他一些奇特的方法,比如可以创建一个对象而不调用构造函数,也可以使用类似 malloc/realloc/free 的风格方法。 - Peter Lawrey
我特别喜欢原始的内存位置获取器和设置器,比如putDouble(long address, double d)。 - Daniel

42

在使用 Swing 的时候,我喜欢隐藏的 Ctrl - Shift - F1 功能。

它可以打印出当前窗口的组件树。
(假设你没有将该快捷键绑定到其他功能上。)


1
很可能你的窗口管理器绑定了某个键。Gnome没有绑定它,所以我假设你正在运行KDE,它将其绑定到“切换到第13个桌面”。您可以通过进入控制面板、区域设置、键盘快捷键并删除Shift-Ctrl-F1的映射来更改它。 - Devon_C_Miller

40
每个类文件都以十六进制值0xCAFEBABE开头,以标识其为有效的JVM字节码。
解释

38
我的投票支持 java.util.concurrent,它拥有并发集合和灵活的执行器,允许线程池、定时任务和协调任务等功能。其中,DelayQueue 是我最喜欢的,可以在指定延迟后使元素可用。
java.util.Timer 和 TimerTask 可以安全地被淘汰。
此外,虽然与其他日期和时间相关的类不在同一个包中,但 java.util.concurrent.TimeUnit 在将纳秒、微秒、毫秒和秒之间转换时非常有用。
它比通常的 someValue * 1000 或 someValue / 1000 更易于阅读。

最近发现了CountDownLatchCyclicBarrier——非常有用! - Raphael

37

语言级别的assert关键字。


19
assert 的问题在于它需要在运行时打开。 - extraneon
10
但如果它被禁用了,就好像它不存在一样。你可以在代码中添加尽可能多的断言,如果它们被禁用了,你将不会因此遭受任何性能损失。 - Ravi Wallau
5
我认为assert的一个好处是:它可以被关闭而没有任何惩罚。 - andref
问题在于,如果您在断言中意外实现了副作用,那么您必须打开程序的断言才能使其正常工作... - Chii
要检测断言是否开启,您可以使用 { boolean assertsOn = false; assert assertsOn = true; if (assertsOn) { /* 复杂验证 */ } }。这还允许记录或抛出异常,如果断言的状态不是预期的。 - fernacolo

37

虽然并不是 Java 语言的一部分,但随 Sun JDK 附带的 javap 反汇编器并不被广泛知晓或使用。


36

在1.5版本中引入了for-each循环结构。我非常喜欢它。

// For each Object, instantiated as foo, in myCollection
for(Object foo: myCollection) {
  System.out.println(foo.toString());
}

它可以在嵌套实例中使用:

for (Suit suit : suits)
  for (Rank rank : ranks)
    sortedDeck.add(new Card(suit, rank));

对于数组,for-each循环同样适用,并且它隐藏的是索引变量而不是迭代器。以下方法返回int数组中值的总和:

// Returns the sum of the elements of a
int sum(int[] a) {
  int result = 0;
  for (int i : a)
    result += i;
  return result;
}

Sun文档链接


30
在这里使用i会非常令人困惑,因为大多数人希望i是索引而不是数组元素。 - cdmckay
28
唯一让我感到烦恼的是,似乎很容易创建一个关键字来访问循环计数器的值,但实际上却不行。如果我想循环遍历两个数组,并根据第一个数组中的值对第二个数组进行更改,我只能使用旧语法,因为我无法获取第二个数组的偏移量。 - Jherico
6
很遗憾它不适用于枚举类型,比如 JNDI 中使用的那种。在那里需要回到迭代器。 - extraneon
3
请参阅Collections.list(Enumeration<T> e),它可以帮助您在foreach循环中迭代枚举。 - Werner Lehmann
@deepc 不幸的是,这会创建一个枚举的副本,而不是一个“List”视图,因此我创建了自己的“Iterable”适配器,它包装在一个“Enumeration”周围。 - Bart van Heukelom
显示剩余2条评论

34

我个人相对较晚才发现了 java.lang.Void -- 与泛型一起使用可以提高代码可读性,例如 Callable<Void>


2
不太对。在某个时候,您需要具体说明:Executors.newSingleThreadExecutor().submit(new Callable<Void>() {..}) -- 您无法实例化新的 Callable<?>,您需要指定一个明确的类型 -- 因此,它是 Callable<Object> 的替代方法。 - Rahel Lüthy
4
Void比Object更加具体,因为Void只能为null,而Object可以是任何东西。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接