2024-04-20 09:00:01

Java的隐藏特性

在阅读了c#的隐藏特性之后,我想知道Java的隐藏特性有哪些?


当前回答

我知道Java 6包括脚本支持,但我最近才发现jrunscript, 它可以交互式地解释和运行JavaScript(以及其他脚本语言,如Groovy),有点像Ruby中的Python shell或irb

其他回答

类型参数方差的联合:

public class Baz<T extends Foo & Bar> {}

例如,如果你想取一个参数,它既是可比的又是集合的:

public static <A, B extends Collection<A> & Comparable<B>>
boolean foo(B b1, B b2, A a) {
   return (b1.compareTo(b2) == 0) || b1.contains(a) || b2.contains(a);
}

如果两个给定的集合相等,或者其中任何一个包含给定元素,则该方法返回true,否则返回false。需要注意的一点是,您可以对参数b1和b2调用Comparable和Collection方法。

那么自JDK 1.5以来就存在的协变返回类型呢?它的宣传很差,因为它是一个不吸引人的附加,但据我所知,它对泛型工作是绝对必要的。

本质上,编译器现在允许子类将被覆盖方法的返回类型缩小为原始方法返回类型的子类。所以这是允许的:

class Souper {
    Collection<String> values() {
        ...
    }
}

class ThreadSafeSortedSub extends Souper {
    @Override
    ConcurrentSkipListSet<String> values() {
        ...
    }
}

您可以调用子类的values方法并获得一个排序的线程安全的字符串集,而不必向下强制转换为ConcurrentSkipListSet。

这不是真正的“隐藏功能”,也不是很有用,但在某些情况下可能非常有趣: 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);
        }
    };
}

一种可以为基于Java控制台的应用程序显示启动画面的功能。

使用带有-splash选项的命令行工具java或javaw

eg:

java -splash:C:\myfolder\myimage.png -classpath myjarfile.jar com.my.package.MyClass

C:\myfolder\myimage.png的内容将显示在你的屏幕中央,每当你执行类"com.my.package.MyClass"

这是我的清单。

我最喜欢的(也是最可怕的)隐藏特性是,您可以从没有声明抛出任何东西的方法中抛出检查异常。

import java.rmi.RemoteException;

class Thrower {
    public static void spit(final Throwable exception) {
        class EvilThrower<T extends Throwable> {
            @SuppressWarnings("unchecked")
            private void sneakyThrow(Throwable exception) throws T {
                throw (T) exception;
            }
        }
        new EvilThrower<RuntimeException>().sneakyThrow(exception);
    }
}

public class ThrowerSample {
    public static void main( String[] args ) {
        Thrower.spit(new RemoteException("go unchecked!"));
    }
}

此外,你可能想知道你可以抛出'null'…

public static void main(String[] args) {
     throw null;
}

猜猜这打印了什么:

Long value = new Long(0);
System.out.println(value.equals(0));

猜猜这返回什么:

public int returnSomething() {
    try {
        throw new RuntimeException("foo!");
    } finally {
        return 0;
    }
}

优秀的开发人员不应该对上述情况感到惊讶。


在Java中,你可以用以下几种有效的方式来声明数组:

String[] strings = new String[] { "foo", "bar" };
// the above is equivalent to the following:
String[] strings = { "foo", "bar" };

所以下面的Java代码是完全有效的:

public class Foo {
    public void doSomething(String[] arg) {}

    public void example() {
        String[] strings = { "foo", "bar" };
        doSomething(strings);
    }
}

是否有任何有效的理由说明下面的代码不应该是有效的?

public class Foo {

    public void doSomething(String[] arg) {}

    public void example() {
        doSomething({ "foo", "bar" });
    }
}

我认为,上述语法可以有效地替代Java 5中引入的可变参数。并且,与之前允许的数组声明更加一致。