Java的隐藏功能
看完CI的隐藏功能后,我想知道Java的一些隐藏功能是什么?
解决方案
回答
语言级别的assert关键字。
回答
我真的很喜欢Java 1.6中重写的Threading API。可调用项很棒。它们基本上是具有返回值的线程。
回答
静态导入可"增强"该语言,因此我们可以通过类型安全的方式完成出色的文字工作:
List<String> ls = List("a", "b", "c");
(也可以处理地图,数组,集合)。
http://gleichmann.wordpress.com/2008/01/13/building-your-own-literals-in-java-lists-and-arrays/
进一步说明:
List<Map<String, String>> data = List(Map( o("name", "michael"), o("sex", "male")));
回答
我认为Java的另一个"被忽略"功能是JVM本身。它可能是可用的最佳虚拟机。它支持许多有趣和有用的语言(Jython,JRuby,Scala,Groovy)。所有这些语言都可以轻松无缝地协作。
如果我们设计一种新的语言(例如在scala案例中),我们将立即拥有所有现有的库,因此语言从一开始就是"有用的"。
所有这些语言都使用HotSpot优化。 VM非常易于监视和调试。
回答
几个月前,Double Brace Initialization让我惊讶,以前从未听说过它。
ThreadLocals通常并不广为人知,它是一种存储每个线程状态的方法。
由于JDK 1.5 Java除了锁以外,还具有非常好的实现和健壮的并发工具,因此它们位于java.util.concurrent中,并且一个特别有趣的示例是java.util.concurrent.atomic子包,该子包包含实现比较的线程安全原语。 -and-swap操作,并且可以映射到这些操作的实际本机硬件支持的版本。
回答
并不是一个真正的功能,但是它使我发笑,goto
是一个保留字,除了提示javac戳我们一眼,它什么也没做。只是提醒我们,我们现在在OO地区。
回答
首先,我非常感谢Java 6中的JConsole监视软件,它已经为我解决了两个问题,我一直在寻找新的用途。
显然,Java 5中已经存在JConsole,但我认为它已经得到了改进,至少现在为止工作得更加稳定。
Java 5中的JConsole:
Java 5中的JConsole
Java 6中的JConsole:
Java 6中的JConsole
当我们使用它时,请看一下该系列中的其他工具:
Java 6故障排除工具
回答
它不是完全隐藏的,但是反射非常有用且功能强大。最好使用一个简单的Class.forName(" ...")。newInstance(),其中类类型是可配置的。编写这种工厂实现很容易。
回答
从JDK 1.5开始,协变量返回类型如何?由于它不是很性感,所以它的宣传很少,但是据我了解,泛型的工作是绝对必要的。
本质上,编译器现在允许子类将重写方法的返回类型缩小为原始方法的返回类型的子类。因此,这是允许的:
class Souper { Collection<String> values() { ... } } class ThreadSafeSortedSub extends Souper { @Override ConcurrentSkipListSet<String> values() { ... } }
我们可以调用子类的values方法,并获得String的排序线程安全Set,而不必向下转换为ConcurrentSkipListSet。
回答
函子非常酷。它们非常接近函数指针,通常每个人都很快说过,这在Java中是不可能的。
Java中的函子
回答
对于大多数人来说,我在Java开发人员职位上被标记为区块的面试非常令人惊讶。这是一个例子:
// code goes here getmeout:{ for (int i = 0; i < N; ++i) { for (int j = i; j < N; ++j) { for (int k = j; k < N; ++k) { //do something here break getmeout; } } } }
谁说Java中的goto只是一个关键字? :)
回答
我知道Java 6包含脚本支持,但是我最近才发现jrunscript,
它可以交互地解释和运行JavaScript(以及一个假定的其他脚本语言,例如Groovy),有点像Ruby中的Python shell或者irb
回答
动态代理(在1.3中添加)允许我们在运行时定义符合接口的新类型。它派上用场了很多次。
回答
类型参数方差的联合并集:
public class Baz<T extends Foo & Bar> {}
例如,如果我们想使用一个同时为Comparable和Collection的参数:
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的方法。
回答
我知道这是在1.5版中添加的,但是新的枚举类型是一个很棒的功能。不必使用旧的" int枚举模式"极大地帮助了我的代码。查看JLS 8.9,了解土豆上的甜汁!
回答
最终实例变量:
对于多线程代码确实有用,并且使争论实例状态和正确性变得容易得多。在行业环境中还没有看到很多东西,并且在Java类中通常也没有考虑到它。
静态{something;}:
用于初始化静态成员(我也更喜欢使用静态方法(因为它具有名称)。
回答
前几天,我对实例初始化器感到惊讶。我正在删除一些代码折叠的方法,并最终创建了多个实例初始化器:
public class App { public App(String name) { System.out.println(name + "'s constructor called"); } static { System.out.println("static initializer called"); } { System.out.println("instance initializer called"); } static { System.out.println("static initializer2 called"); } { System.out.println("instance initializer2 called"); } public static void main( String[] args ) { new App("one"); new App("two"); } }
执行main
方法将显示:
static initializer called static initializer2 called instance initializer called instance initializer2 called one's constructor called instance initializer called instance initializer2 called two's constructor called
我想如果我们有多个构造函数并需要通用代码,这些将很有用
他们还提供语法糖来初始化课程:
List<Integer> numbers = new ArrayList<Integer>(){{ add(1); add(2); }}; Map<String,String> codes = new HashMap<String,String>(){{ put("1","one"); put("2","two"); }};
回答
约书亚·布洛赫(Joshua Bloch)的新有效Java是很好的资源。
回答
- 本地课程。
- 从包含类的外部实例化Java内部类。
回答
枚举中允许方法和构造函数令我感到惊讶。例如:
enum Cats { FELIX(2), SHEEBA(3), RUFUS(7); private int mAge; Cats(int age) { mAge = age; } public int getAge() { return mAge; } }
我们甚至可以拥有一个"常量特定类主体",该主体允许特定的枚举值覆盖方法。
此处有更多文档。
回答
它并不是Java语言的真正组成部分,但Sun的JDK随附的javap反汇编程序并未广为人知或者使用。
回答
自绑定仿制药:
class SelfBounded<T extends SelfBounded<T>> { }
http://www.artima.com/weblogs/viewpost.jsp?thread=136394
回答
JDK 1.6_07 +包含一个名为VisualVM(bin / jvisualvm.exe)的应用程序,它是许多工具之上的漂亮GUI。似乎比JConsole更全面。
回答
泛型方法的类型参数可以显式指定,如下所示:
Collections.<String,Integer>emptyMap()
回答
他们花了足够长的时间来增加对此的支持,
系统托盘
回答
java.util.Arrays中的asList方法可以很好地结合使用varargs,通用方法和自动装箱:
List<Integer> ints = Arrays.asList(1,2,3);
回答
一些控制流技巧,最终是在return语句周围:
int getCount() { try { return 1; } finally { System.out.println("Bye!"); } }
明确分配的规则将检查是否始终通过简单的控制流分析来分配最终变量:
final int foo; if(...) foo = 1; else throw new Exception(); foo+1;
回答
JVisualVM来自JDK发行版中的bin目录。监视甚至分析任何Java应用程序,甚至是我们未使用任何特殊参数启动的Java应用程序。仅在Java 6SE JDK的最新版本中。
回答
在finally块中的控制权转移会丢弃任何异常。以下代码不会引发RuntimeException-它会丢失。
public static void doSomething() { try { //Normally you would have code that doesn't explicitly appear //to throw exceptions so it would be harder to see the problem. throw new RuntimeException(); } finally { return; } }
来自http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html
回答
在1.5中增加了for-each循环结构。我<3.
// 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文档
回答
" const"是一个关键字,但是我们不能使用它。
int const = 1; // "not a statement" const int i = 1; // "illegal start of expression"
我猜编译器作者认为将来可能会使用它,因此最好保留它。
回答
并不是真正的功能,而是我最近在某些网页中发现的有趣技巧:
class Example { public static void main(String[] args) { System.out.println("Hello World!"); http://Phi.Lho.free.fr System.exit(0); } }
是有效的Java程序(尽管会生成警告)。
如果我们不明白为什么,请参阅格雷戈里(Gregory)的答案! ;-)好吧,这里的语法高亮也给出了提示!
回答
我的最爱:将所有线程堆栈跟踪信息转储到标准输出中。
Windows:Java cmd /控制台窗口中的CTRL
-Break
Unix:kill -3 PID
回答
我们对垃圾收集器拥有的强大功能以及它如何管理对象收集非常强大,特别是对于长时间运行且对时间敏感的应用程序而言。它以java.lang.ref包中的弱引用,软引用和幻像引用开头。看一看,特别是对于构建缓存(已经有一个java.util.WeakHashMap)。现在,对ReferenceQueue进行更深入的研究,我们将开始获得更多控制权。最后,抓住垃圾收集器本身上的文档,我们将能够控制垃圾收集器运行的频率,不同收集区域的大小以及所用算法的类型(有关Java 5,请参见http://java.sun.com/docs /hotspot/gc5.0/gc_tuning_5.html)。
回答
使用此关键字从内部类访问包含类的字段/方法。在下面的示例中,我们想使用匿名内部类中容器类的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; } }
回答
这并不是完全"隐藏的功能",也不是很有用,但是在某些情况下可能非常有趣:
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); } }; }
回答
由于没有人说过(我认为),我最喜欢的功能是自动装箱!
public class Example { public static void main(String[] Args) { int a = 5; Integer b = a; // Box! System.out.println("A : " + a); System.out.println("B : " + b); } }
回答
我们选择的编码中的属性文件怎么样?过去,在加载属性时,我们提供了InputStream,而load()方法将其解码为ISO-8859-1. 我们实际上可以将文件存储为其他编码,但是在加载后必须使用类似的令人讨厌的技巧才能正确解码数据:
String realProp = new String(prop.getBytes("ISO-8859-1"), "UTF-8");
但是,从JDK 1.6开始,有一个使用读取器而不是InputStream的load方法,这意味着我们可以从一开始就使用正确的编码(还有一个使用Writer的store方法)。 。对我来说,这似乎是一件大事,但似乎根本没有大张旗鼓地溜进JDK。几周前,我才偶然发现它,随后Google对其进行了快速搜索,只是提及它而已。
回答
如果我们进行大量JavaBean开发并使用属性更改支持,那么通常会写很多这样的setter:
public void setFoo(Foo aFoo){ Foo old = this.foo; this.foo = aFoo; changeSupport.firePropertyChange("foo", old, aFoo); }
我最近偶然发现了一个博客,该博客建议对此进行更简洁的实现,从而使代码更容易编写:
public void setFoo(Foo aFoo){ changeSupport.firePropertyChange("foo", this.foo, this.foo = aFoo); }
实际上,它简化了事情,使我能够在Eclipse中调整setter模板,因此该方法可以自动创建。
回答
字符串参数化类工厂。
Class.forName( className ).newInstance();
从部署jar文件中加载资源(属性文件,xml,xslt,图像等)。
this.getClass().getClassLoader().getResourceAsStream( ... ) ;
回答
令我真正感到惊讶的是自定义序列化机制。
虽然这些方法是私有的!,但是在对象序列化过程中,JVM神秘地调用了它们。
private void writeObject(ObjectOutputStream out) throws IOException; private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
这样,我们可以创建自己的自定义序列化,使其更"随便"(安全,快速,罕见,简单等)。
如果必须通过节点传递大量信息,这是应该真正考虑的事情。可以更改串行化机制以发送一半的数据。很多时候,瓶颈不在平台中,但是通过网络发送的瓶颈数量可以为我们节省数千个硬件dll。
这是一篇文章。
http://java.sun.com/developer/technicalArticles/Programming/serialization/
回答
我们可以在方法中声明一个类:
public Foo foo(String in) { class FooFormat extends Format { public Object parse(String s, ParsePosition pp) { // parse stuff } } return (Foo) new FooFormat().parse(in); }
回答
Java 6的注释处理API看起来非常适合代码生成和静态代码验证。
回答
最终的初始化可以推迟。
它确保即使在逻辑流程复杂的情况下,也始终会设置返回值。遗漏案例并意外返回null太容易了。它不会使返回null成为不可能,只是显而易见的是它是有目的的:
public Object getElementAt(int index) { final Object element; if (index == 0) { element = "Result 1"; } else if (index == 1) { element = "Result 2"; } else { element = "Result 3"; } return element; }
回答
几年前,当我不得不做Java(1.4.x)时,我想要一个eval()方法,而Suns javac是用Java编写的,所以它只是链接tools.jar并将其与一些胶水代码一起使用它。
回答
如果不使用默认的初始化程序,则Java处理会对变量定义进行巧妙的处理。
{ int x; if(whatever) x=1; if(x == 1) ... }
这将在编译时给我们一个错误,我们有一个未正确定义X的路径。这对我有所帮助,并且我考虑了如下的默认初始化:
int x=0; String s=null;
会成为不好的模式,因为它会阻止此有用的检查。
就是说,有时候很难绕开-当必须将= null设置为默认值时,我不得不回过头来进行编辑,但我再也没有将其放在第一遍了。
回答
我们可以在局部类的初始化块和方法中访问最终的局部变量和参数。考虑一下:
final String foo = "42"; new Thread() { public void run() { dowhatever(foo); } }.start();
有点像关闭,不是吗?
回答
的价值:
new URL("http://www.yahoo.com").equals(new URL("http://209.191.93.52"))
是" true"。
(来自Java Puzzlers)
回答
有人发布了有关实例初始化程序的信息,这是一个很好的用法:
Map map = new HashMap() {{ put("a key", "a value"); put("another key", "another value"); }};
如果我们只是在做快速简单的事情,这是一种初始化地图的快速方法。
或者使用它来创建快速摆架原型:
JFrame frame = new JFrame(); JPanel panel = new JPanel(); panel.add( new JLabel("Hey there"){{ setBackground(Color.black); setForeground( Color.white); }}); panel.add( new JButton("Ok"){{ addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent ae ){ System.out.println("Button pushed"); } }); }}); frame.add( panel );
当然可以滥用它:
JFrame frame = new JFrame(){{ add( new JPanel(){{ add( new JLabel("Hey there"){{ setBackground(Color.black); setForeground( Color.white); }}); add( new JButton("Ok"){{ addActionListener( new ActionListener(){ public void actionPerformed( ActionEvent ae ){ System.out.println("Button pushed"); } }); }}); }}); }};
回答
从Java 1.5开始,Java现在具有更简洁的语法来编写可变Arity函数。因此,现在我们不仅可以传递数组,还可以执行以下操作
public void foo(String... bars) { for (String bar: bars) System.out.println(bar); }
条会自动转换为指定类型的数组。不是一个巨大的胜利,但是仍然是一个胜利。
回答
正确编写Javadoc(不幸的是,某些开发人员并非总是如此),它为我们提供了一个清晰,连贯的描述,说明应该执行什么代码,而不是实际执行什么。然后可以将其变成一组漂亮的HTML文档。如果我们使用持续集成等,则可以定期生成,因此所有开发人员都可以看到最新更新。
回答
SwingWorker可轻松管理来自后台线程的用户界面回调。
回答
相同类的实例可以访问其他实例的私有成员:
class Thing { private int x; public int addThings(Thing t2) { return this.x + t2.x; // Can access t2's private value! } }
回答
显然,对于某些调试版本,有一个选项可以从HotSpot转储本机(JIT)汇编代码:http://weblogs.java.net/blog/kohsuke/archive/2008/03/deep_dive_into.html
不幸的是,如果有人可以找到更精确的URL,我将无法通过该文章中的链接找到该版本,我很乐意使用它。
回答
我的投票投给java.util.concurrent及其并发集合和灵活的执行程序,这些执行程序除其他外还允许线程池,计划任务和协调任务。 DelayQueue是我个人的最爱,其中元素在指定的延迟后可用。
java.util.Timer和TimerTask可以安全地停下来。
同样,不是完全隐藏,而是与其他与日期和时间有关的类位于不同的包中。在纳秒,微秒,毫秒和秒之间进行转换时,java.util.concurrent.TimeUnit非常有用。
它的读取结果比通常的someValue * 1000或者someValue / 1000好得多。
回答
strictfp关键字。 (尽管我从未见过它在实际的应用程序中使用过:)
我们可以使用以下符号获取原始类型的类:int.class,
float.class等。进行反射时非常有用。
最终数组可用于从匿名内部类中"返回"值(警告,以下无用的示例):
final boolean[] result = new boolean[1]; SwingUtilities.invokeAndWait(new Runnable() { public void run() { result[0] = true; } });
回答
尚未见任何人提到instanceof以不需要检查null的方式实现。
代替:
if( null != aObject && aObject instanceof String ) { ... }
只需使用:
if( aObject instanceof String ) { ... }
回答
我喜欢
- javadoc的标签和doclet,使我们能够自定义javadoc输出。
- JDK工具:jstat,jstack等。
回答
Java 1.6 Update 10和更高版本中提供的下一代Java插件具有一些非常简洁的功能:
- 传递java_arguments参数,以将参数传递给所创建的JVM。这使我们可以控制分配给applet的内存量。
- 为每个小程序创建单独的类加载器,甚至创建单独的JVM。
- 指定要使用的JVM版本。
- 如果只需要部分Java库功能的一部分,则安装部分Java内核。
- 更好的Vista支持。
- 支持(实验性),可将小程序从浏览器中拖出,并在我们离开时使其继续运行。
此处记录了许多其他内容:http://jdk6.dev.java.net/plugin2/
此版本提供了更多信息:http://jdk6.dev.java.net/6u10ea.html
回答
我们可以使用String.format()构建sprintf样式的字符串。
String w = "world"; String s = String.format("Hello %s %d", w, 3);
当然,我们也可以使用特殊的说明符来修改输出。
此处更多内容:http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html#syntax
回答
使用静态导入,我们可以做一些很酷的事情,例如:
List<String> myList = list("foo", "bar"); Set<String> mySet = set("foo", "bar"); Map<String, String> myMap = map(v("foo", "2"), v("bar", "3"));
回答
我喜欢静态导入方法。
例如,创建以下util类:
package package.name; public class util { private static void doStuff1(){ //the end } private static String doStuff2(){ return "the end"; } }
然后像这样使用它。
import static package.name.util.*; public class main{ public static void main(String[] args){ doStuff1(); // wee no more typing util.doStuff1() System.out.print(doStuff2()); // or util.doStuff2() } }
静态导入适用于任何类,甚至包括数学...
import static java.lang.Math.*; import static java.lang.System.out; public class HelloWorld { public static void main(String[] args) { out.println("Hello World!"); out.println("Considering a circle with a diameter of 5 cm, it has:"); out.println("A circumference of " + (PI * 5) + "cm"); out.println("And an area of " + (PI * pow(5,2)) + "sq. cm"); } }
回答
List.subList返回原始列表的视图
列表中有记载但鲜为人知的功能。这样,我们就可以处理列表中具有原始列表中所反映的更改的部分。
列表subList(int fromIndex,int toIndex)
"This method eliminates the need for explicit range operations (of the sort that commonly exist for arrays). Any operation that expects a list can be used as a range operation by passing a subList view instead of a whole list. For example, the following idiom removes a range of elements from a list: list.subList(from, to).clear(); Similar idioms may be constructed for indexOf and lastIndexOf, and all of the algorithms in the Collections class can be applied to a subList."
回答
我很晚才亲自发现java.lang.Void
-与泛型一起提高了代码的可读性,例如Callable <Void>
回答
我们可以使用枚举来实现接口。
public interface Room { public Room north(); public Room south(); public Room east(); public Room west(); } public enum Rooms implements Room { FIRST { public Room north() { return SECOND; } }, SECOND { public Room south() { return FIRST; } } public Room north() { return null; } public Room south() { return null; } public Room east() { return null; } public Room west() { return null; } }
编辑:几年后....
我在这里使用此功能
public enum AffinityStrategies implements AffinityStrategy {
https://github.com/peter-lawrey/Java-Thread-Affinity/blob/master/src/main/java/vanilla/java/affinity/AffinityStrategies.java
通过使用界面,开发人员可以定义自己的策略。使用"枚举"意味着我可以定义一个内置的集合(五个)。
回答
交集类型允许我们(有点儿排序)进行具有继承层次结构的枚举。我们不能继承实现,但是可以将其委派给帮助器类。
enum Foo1 implements Bar {} enum Foo2 implements Bar {} class HelperClass { static <T extends Enum<T> & Bar> void fooBar(T the enum) {} }
当我们有许多实现某种模式的枚举时,这很有用。例如,许多具有父子关系的枚举对。
enum PrimaryColor {Red, Green, Blue;} enum PastelColor {Pink, HotPink, Rockmelon, SkyBlue, BabyBlue;} enum TransportMedium {Land, Sea, Air;} enum Vehicle {Car, Truck, BigBoat, LittleBoat, JetFighter, HotAirBaloon;}
我们可以编写通用方法,说"好吧,如果给定枚举值是某些其他枚举值的父级,那么该子类型的所有可能子枚举中有多少百分比将此特定父级值作为其父级?",然后全部使用类型安全,无需转换即可完成。 (例如:"海上"占所有可能的车辆的33%,"绿色"占所有可能的粉彩的20%)。
代码看起来像这样。这很讨厌,但是有一些方法可以使它更好。特别要注意的是,"叶子"类本身非常整洁,泛型类具有非常丑陋的声明,但我们只能将它们编写为onece。一旦通用类存在,使用它们就很容易了。
import java.util.EnumSet; import javax.swing.JComponent; public class zz extends JComponent { public static void main(String[] args) { System.out.println(PrimaryColor.Green + " " + ParentUtil.pctOf(PrimaryColor.Green) + "%"); System.out.println(TransportMedium.Air + " " + ParentUtil.pctOf(TransportMedium.Air) + "%"); } } class ParentUtil { private ParentUtil(){} static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> // float pctOf(P parent) { return (float) parent.getChildren().size() / // (float) EnumSet.allOf(parent.getChildClass()).size() // * 100f; } public static <P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> // EnumSet<C> loadChildrenOf(P p) { EnumSet<C> cc = EnumSet.noneOf(p.getChildClass()); for(C c: EnumSet.allOf(p.getChildClass())) { if(c.getParent() == p) { cc.add(c); } } return cc; } } interface Parent<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> { Class<C> getChildClass(); EnumSet<C> getChildren(); } interface Child<P extends Enum<P> & Parent<P, C>, C extends Enum<C> & Child<P, C>> { Class<P> getParentClass(); P getParent(); } enum PrimaryColor implements Parent<PrimaryColor, PastelColor> { Red, Green, Blue; private EnumSet<PastelColor> children; public Class<PastelColor> getChildClass() { return PastelColor.class; } public EnumSet<PastelColor> getChildren() { if(children == null) children=ParentUtil.loadChildrenOf(this); return children; } } enum PastelColor implements Child<PrimaryColor, PastelColor> { Pink(PrimaryColor.Red), HotPink(PrimaryColor.Red), // Rockmelon(PrimaryColor.Green), // SkyBlue(PrimaryColor.Blue), BabyBlue(PrimaryColor.Blue); final PrimaryColor parent; private PastelColor(PrimaryColor parent) { this.parent = parent; } public Class<PrimaryColor> getParentClass() { return PrimaryColor.class; } public PrimaryColor getParent() { return parent; } } enum TransportMedium implements Parent<TransportMedium, Vehicle> { Land, Sea, Air; private EnumSet<Vehicle> children; public Class<Vehicle> getChildClass() { return Vehicle.class; } public EnumSet<Vehicle> getChildren() { if(children == null) children=ParentUtil.loadChildrenOf(this); return children; } } enum Vehicle implements Child<TransportMedium, Vehicle> { Car(TransportMedium.Land), Truck(TransportMedium.Land), // BigBoat(TransportMedium.Sea), LittleBoat(TransportMedium.Sea), // JetFighter(TransportMedium.Air), HotAirBaloon(TransportMedium.Air); private final TransportMedium parent; private Vehicle(TransportMedium parent) { this.parent = parent; } public Class<TransportMedium> getParentClass() { return TransportMedium.class; } public TransportMedium getParent() { return parent; } }
回答
阅读约书亚·布洛赫(Joshua Bloch)撰写的" Java Puzzlers",我们将被启发和震惊。
回答
源代码URL。例如。这是一些合法的Java源代码:
http://google.com
(是的,这是在Java Puzzlers中。我笑了……)
回答
当人们意识到可以调用私有方法并使用反射来访问/更改私有字段时,有时会有些惊讶。
考虑以下类别:
public class Foo { private int bar; public Foo() { setBar(17); } private void setBar(int bar) { this.bar=bar; } public int getBar() { return bar; } public String toString() { return "Foo[bar="+bar+"]"; } }
正在执行此程序...
import java.lang.reflect.*; public class AccessibleExample { public static void main(String[] args) throws NoSuchMethodException,IllegalAccessException, InvocationTargetException, NoSuchFieldException { Foo foo=new Foo(); System.out.println(foo); Method method=Foo.class.getDeclaredMethod("setBar", int.class); method.setAccessible(true); method.invoke(foo, 42); System.out.println(foo); Field field=Foo.class.getDeclaredField("bar"); field.setAccessible(true); field.set(foo, 23); System.out.println(foo); } }
...将产生以下输出:
Foo[bar=17] Foo[bar=42] Foo[bar=23]
回答
部分功能,部分麻烦:Java的String处理以使其"出现"本机Type(在其上使用运算符,+,+ =)
能够写:
String s = "A"; s += " String"; // so s == "A String"
非常方便,但仅是语法糖(即被编译为):
String s = new String("A"); s = new StringBuffer(s).append(" String").toString();
ergo一个对象实例化和2个方法调用以进行简单的串联。想象一下以这种方式在循环内构建一个长字符串!并且所有StringBuffer的方法都声明为已同步。幸运的是,在(我认为)Java 5中,他们引入了StringBuilder,它与没有同步的StringBuffer相同。
循环如下:
String s = ""; for (int i = 0 ; i < 1000 ; ++i) s += " " + i; // Really an Object instantiation & 3 method invocations!
可以(应该)在代码中重写为:
StringBuilder buf = new StringBuilder(); // Empty buffer for (int i = 0 ; i < 1000 ; ++i) buf.append(' ').append(i); // Cut out the object instantiation & reduce to 2 method invocations String s = buf.toString();
并且比原始循环的运行速度快80%以上!
(在我运行的某些基准测试中,最高可达180%)
回答
也许最令人惊讶的隐藏功能是sun.misc.Unsafe类。
http://www.docjar.com/html/api/ClassLib/Common/sun/misc/Unsafe.java.html
你可以;
- 创建一个对象而不调用构造函数。
- 抛出任何异常甚至Exception,而不必担心方法上的throws子句。 (我知道还有其他方法可以做到)
- 在不使用反射的情况下获取/设置对象中的随机访问字段。
- 分配/释放/复制/调整大小的内存块,该内存块可以很长(64位)。
- 获取对象中字段或者类中静态字段的位置。
- 独立锁定和解锁对象锁定。 (例如同步无障碍)
- 从提供的字节码中定义一个类。而不是由类加载器确定字节码应该是什么。 (我们也可以通过反射来执行此操作)
顺便说一句:错误使用此类将杀死JVM。我不知道哪些JVM支持此类,因此它不可移植。
回答
我们可以定义一个匿名子类并直接在其上调用方法,即使该类未实现任何接口也是如此。
new Object() { void foo(String s) { System.out.println(s); } }.foo("Hello");
回答
一种优化技巧,使代码更易于维护,并且较少受到并发错误的影响。
public class Slow { /** Loop counter; initialized to 0. */ private long i; public static void main( String args[] ) { Slow slow = new Slow(); slow.run(); } private void run() { while( i++ < 10000000000L ) ; } }
$时间java慢
真正的0m15.397s
$时间java慢
真正的0m20.012s
$时间java慢
真正的0m18.645s
平均:18.018s
public class Fast { /** Loop counter; initialized to 0. */ private long i; public static void main( String args[] ) { Fast fast = new Fast(); fast.run(); } private void run() { long i = getI(); while( i++ < 10000000000L ) ; setI( i ); } private long setI( long i ) { this.i = i; } private long getI() { return this.i; } }
$时间Java快速
真正的0m12.003s
$时间Java快速
真正的0m9.840s
$ time java快速
真正的0m9.686s
平均:10.509秒
与方法范围变量相比,它需要更多的字节码来引用类范围变量。在关键循环之前添加方法调用几乎不会增加开销(而且无论如何,编译器都可以内联该调用)。
该技术(始终使用访问器)的另一个优点是,它消除了Slow类中的潜在错误。如果第二个线程连续将i的值重置为0(例如,通过调用slow.setI(0)
),则Slow类将永远无法结束其循环。调用访问器并使用局部变量消除了这种可能性。
在Linux 2.6.27-14上使用J2SE 1.6.0_13测试。
回答
Java Bean属性访问器方法不必以" get"和" set"开头。
甚至Josh Bloch在有效Java中也都犯了这个错误。
回答
我今天刚刚(重新)了解到$是Java中方法或者变量的合法名称。与静态导入结合使用,可以使代码更具可读性,具体取决于我们对可读性的看法:
http://garbagecollected.org/2008/04/06/dollarmaps/
回答
已经提到,可以使用最终数组将变量从匿名内部类中传递出去。
另一个可以说是更好且不太丑陋的方法是使用java.util.concurrent.atomic包中的AtomicReference(或者AtomicBoolean / AtomicInteger /)类。
这样做的好处之一是,这些类还提供了诸如" compareAndSet"之类的方法,如果要创建多个可以修改同一变量的线程,这些方法可能会很有用。
另一个有用的相关模式:
final AtomicBoolean dataMsgReceived = new AtomicBoolean(false); final AtomicReference<Message> message = new AtomicReference<Message>(); withMessageHandler(new MessageHandler() { public void handleMessage(Message msg) { if (msg.isData()) { synchronized (dataMsgReceived) { message.set(msg); dataMsgReceived.set(true); dataMsgReceived.notifyAll(); } } } }, new Interruptible() { public void run() throws InterruptedException { synchronized (dataMsgReceived) { while (!dataMsgReceived.get()) { dataMsgReceived.wait(); } } } });
在此特定示例中,我们可能只是等待消息使其变为非null,但是null通常可能是有效值,然后我们需要使用单独的标志来完成等待。
上面的waitMessageHandler()
是另一个有用的模式:它在某个地方设置了一个处理程序,然后开始执行可能会引发异常的Interruptible,然后将其删除,如下面这样:
private final AtomicReference<MessageHandler> messageHandler = new AtomicReference<MessageHandler>(); public void withMessageHandler(MessageHandler handler, Interruptible logic) throws InterruptedException { synchronized (messageHandler) { try { messageHandler.set(handler); logic.run(); } finally { messageHandler.set(null); } } }
在这里,我假设在收到消息时,另一个线程调用了messageHandler的(如果不为null)handleMessage()方法。 messageHandler不能仅仅是MessageHandler类型:这样,我们将在一个不断变化的变量上进行同步,这显然是一个错误。
当然,它不需要是InterruptedException,它可以是类似IOException的东西,或者在特定代码段中有意义的东西。
回答
逗号和数组。这是合法的语法:String s [] = {
" 123",
" 234",
};
回答
大多数人不知道他们可以克隆一个数组。
int[] arr = {1, 2, 3}; int[] arr2 = arr.clone();
回答
当我们不需要StringBuilder中包含的同步管理时,请使用StringBuilder而不是StringBuffer。它将提高应用程序的性能。
Java 7的改进甚至比任何隐藏的Java功能都更好:
- 菱形语法:链接
实例化时不要使用那些无限的<>语法:
Map<String, List<String>> anagrams = new HashMap<String, List<String>>(); // Can now be replaced with this: Map<String, List<String>> anagrams = new HashMap<>();
- 开关中的字符串:链接
在开关中使用String,而不是old-C int:
String s = "something"; switch(s) { case "quux": processQuux(s); // fall-through case "foo": case "bar": processFooOrBar(s); break; case "baz": processBaz(s); // fall-through default: processDefault(s); break; }
- 自动资源管理链接
这个旧代码:
static void copy(String src, String dest) throws IOException { InputStream in = new FileInputStream(src); try { OutputStream out = new FileOutputStream(dest); try { byte[] buf = new byte[8 * 1024]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } finally { out.close(); } } finally { in.close(); } }
现在可以用以下更简单的代码代替:
static void copy(String src, String dest) throws IOException { try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dest)) { byte[] buf = new byte[8192]; int n; while ((n = in.read(buf)) >= 0) out.write(buf, 0, n); } }
回答
我们可以在枚举类的方法定义内进行切换。让我喊"呜呜!"当我发现这确实有效时,大声说道。
回答
实际上,我对Java的爱好是隐藏的技巧很少。这是一种非常明显的语言。如此之多,以至于15年后,我能想到的几乎每一本书都已经列在这几页中。
也许大多数人都知道Collections.synchronizedList()将同步添加到列表中。除非我们阅读文档,否则我们不会知道的是,可以通过在列表对象本身上进行同步来安全地迭代该列表的元素。
CopyOnWriteArrayList对于某些人可能是未知的,并且Future表示一种抽象多线程结果访问的有趣方法。
我们可以添加到VM(本地或者远程),通过各种管理,代理和添加API获取有关GC活动,内存使用,文件描述符甚至对象大小的信息。
尽管TimeUnit可能比长时更好,但我更喜欢Wicket的Duration类。
回答
哦,我差点忘了这个小宝石。在任何正在运行的Java进程上尝试以下操作:
jmap -histo:实时PID
我们将获得给定VM中活动堆对象的直方图。作为解决某些类型的内存泄漏的快速方法,它非常有用。我用来阻止它们的另一种技术是创建和使用所有集合类的大小限制子类。这会导致易于识别的失控集合快速失败。
回答
我们可以使用此功能显示基于Java控制台的应用程序的初始屏幕。
使用带有-splash
选项的命令行工具java
或者javaw
。
例如:
java -splash:C:\myfolder\myimage.png -classpath myjarfile.jar com.my.package.MyClass
每当我们执行" com.my.package.MyClass"类时," C:\ myfolder \ myimage.png"的内容就会显示在屏幕中央。
回答
在Swing中工作时,我喜欢隐藏的Ctrl + Shift + F1功能。
它转储当前窗口的组件树。
(假设我们尚未将该按键绑定到其他东西。)
回答
一个接口可以扩展多个接口,但类只能扩展一个类,这让我感到惊讶。
回答
自Java 6起的类路径通配符。
java -classpath ./lib/* so.Main
代替
java -classpath ./lib/log4j.jar:./lib/commons-codec.jar:./lib/commons-httpclient.jar:./lib/commons-collections.jar:./lib/myApp.jar so.Main
参见http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html
回答
关机挂钩。这允许注册将立即创建但仅在JVM结束时才启动的线程!因此,它是某种"全局jvm终结器",我们可以在此线程中做一些有用的事情(例如,关闭Java资源,例如嵌入式hsqldb服务器)。这适用于System.exit()或者CTRL-C / kill -15(当然,不适用于unix上的kill -9)。
此外,它很容易设置。
Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { endApp(); } });;
回答
标识符可以包含外语字符,如变音符号:
而不是写:
String title="";
有人可以写:
String überschrift="";
回答
Java 6(来自Sun)带有嵌入式JavaScrip解释器。
http://java.sun.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html#jsengine
回答
没看过这个
Integer a = 1; Integer b = 1; Integer c = new Integer(1); Integer d = new Integer(1); Integer e = 128; Integer f = 128; assertTrue (a == b); // again: this is true! assertFalse(e == f); // again: this is false! assertFalse(c == d); // again: this is false!
通过搜索Java的整数池(从-128到127的内部"缓存"以进行自动装箱)来了解有关此内容的更多信息,或者查看Integer.valueOf
回答
我们可以重写方法并让超类构造函数对其进行调用(这可能会使C ++程序员感到惊讶。)
例子
回答
这是我的清单。
我最喜欢的(也是最可怕的)隐藏功能是,我们可以从未声明抛出任何东西的方法中抛出检查异常。
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中引入的varargs的有效替代。而且,与以前允许的数组声明更加一致。
回答
每个类文件均以十六进制值0xCAFEBABE开头,以将其标识为有效的JVM字节码。
(解释)
回答
我们可以使用Class <T>对象添加泛型类型的运行时检查,当在某个配置文件中的某个地方创建一个类并且无法为该类的泛型类型添加编译时检查时,这非常方便班级。如果应用程序配置错误,我们不希望该类在运行时崩溃,并且我们不希望所有类都被检查实例弄得一团糟。
public interface SomeInterface { void doSomething(Object o); } public abstract class RuntimeCheckingTemplate<T> { private Class<T> clazz; protected RuntimeChecking(Class<T> clazz) { this.clazz = clazz; } public void doSomething(Object o) { if (clazz.isInstance(o)) { doSomethingWithGeneric(clazz.cast(o)); } else { // log it, do something by default, throw an exception, etc. } } protected abstract void doSomethingWithGeneric(T t); } public class ClassThatWorksWithStrings extends RuntimeCheckingTemplate<String> { public ClassThatWorksWithStrings() { super(String.class); } protected abstract void doSomethingWithGeneric(T t) { // Do something with the generic and know that a runtime exception won't occur // because of a wrong type } }
回答
当我第一次注意到三元运算符等于一个简单的if-then-else语句时,我感到很惊讶:
minVal = (a < b) ? a : b;
回答
我可以添加扫描仪对象。这是最适合解析的。
String input = "1 fish 2 fish red fish blue fish"; Scanner s = new Scanner(input).useDelimiter("\s*fish\s*"); System.out.println(s.nextInt()); System.out.println(s.nextInt()); System.out.println(s.next()); System.out.println(s.next()); s.close();
回答
我们可以在匿名内部类上定义和调用方法。
好吧,它们并不是那么隐蔽,但是很少有人知道他们可以用来在类中定义新方法并像这样调用它:
(new Object() { public String someMethod(){ return "some value"; } }).someMethod();
可能不是很常见,因为它也不是很有用,我们只能在定义方法时(或者通过反射)调用该方法
回答
这并不是真正的隐藏功能,但是当我看到编译好的时候,确实给了我一个很大的惊喜:
public int aMethod(){ http://www.google.com return 1; }
之所以进行编译,是因为编译器将http://www.google.com的" http:"部分视为标签,其余部分为注释。
因此,如果我们想编写一些奇怪的代码(或者混淆的代码),只需在其中放置很多http地址即可。 ;-)
回答
C样式printf():)
System.out.printf("%d %f %.4f", 3,Math.E,Math.E);
输出:
3 2.718282 2.7183
二进制搜索(它是返回值)
int[] q = new int[] { 1,3,4,5}; int position = Arrays.binarySearch(q, 2);
与C#相似,如果在数组中未找到" 2",它将返回一个负值,但是如果我们对返回值取1的补码,则实际上会获得可以插入" 2"的位置。
在上面的示例中,position = -2,〜position = 1,这是应在其中插入2的位置...它还使我们可以找到数组中"最接近"的匹配项。
我认为它非常漂亮... :)
回答
不是那么隐藏,但是很有趣。
我们可以不使用main方法就拥有一个" Hello,world"(它抛出NoSuchMethodError思想)
最初由RusselW发表于最奇怪的语言功能
public class WithoutMain { static { System.out.println("Look ma, no main!!"); System.exit(0); } } $ java WithoutMain Look ma, no main!!