Java中一些常被忽视的特性

说明:

1 参考自stackoverflow上的一个帖子以及广大网友的回复: http://stackoverflow.com/questions/15496/hidden-features-of-java?page=4&tab=votes#tab-top

2 在这些回复中,我选择了一些写到这篇博客中,当然也有很多回复我认为没有必要翻译出来.

3 在翻译的过程中,为了快速完成,主要把代码贴过来,只要是对Java比较熟悉的, 看到代码基本上就能理解这个特性.对其他解释性的文字翻译的比较少, 如果感兴趣可以查看原文, 原文地址在上面已经给出.

正文:

1 使用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
  }
}

2 整数自动装箱

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!

3 格式化字符串

String w = "world";
String s = String.format("Hello %s %d", w, 3);

4 匿名内部类中可以访问final类型的局部变量

    final String foo = "42";
    new Thread() {
        public void run() {
             dowhatever(foo);
        }
    }.start();

5 数组类型的对象调用clone方法可以复制一个数组

int[] arr = {1, 2, 3};
int[] arr2 = arr.clone();

6 通过反射可以访问私有成员

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]

7 使用Scanner解析字符串

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();

8 可以使用非英文给标示符命名

String Überschrift="";
译者注: 中文也可以.

9 访问局部变量比访问成员变量快

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 )
      ;
  }
}

以上代码平均耗时 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;
  }
}

以上代码平均耗时 10.509s

10 const是一个关键字, 但是你不能使用它

int const = 1;   // "not a statement"
const int i = 1; // "illegal start of expression"

11 C风格的打印语句

System.out.printf("%d %f %.4f", 3,Math.E,Math.E);

12 匿名内部类可以直接调用子类中定义的方法

(new Object() {
    public String someMethod(){ 
        return "some value";
    }
}).someMethod();
new Object() {
  void foo(String s) {
    System.out.println(s);
  }
}.foo("Hello");

尽管创建的匿名内部类实例并没有实现一个独立的接口, 但是能直接调用不在父类Object中的方法

13 List.subList()创建原有list的一个视图

操作一个list的一部分, 并且对subList的修改会反映到原有list中
list.subList(from, to).clear();
以上代码删除原有list中从from到to位置的元素.

译者注: 可查看jdk中ArrayList的源码来验证这一结论.下面贴出部分源码:
public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

SubList作为ArrayList的一个内部类:
private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;
        private final int parentOffset;
        private final int offset;
        int size;

        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }
// ......

        public void add(int index, E e) {
            rangeCheckForAdd(index);
            checkForComodification();
            parent.add(parentOffset + index, e);
            this.modCount = parent.modCount;
            this.size++;
        }

        public E remove(int index) {
            rangeCheck(index);
            checkForComodification();
            E result = parent.remove(parentOffset + index);
            this.modCount = parent.modCount;
            this.size--;
            return result;
        }

// ......

从add和remove方法可以看出, 对subList的修改反映到了原有list(parent)中.

14 自限定泛型

class SelfBounded<T extends SelfBounded<T>> {
}

15 可以在方法中定义一个内部类

public Foo foo(String in) {
    class FooFormat extends Format {
        public Object parse(String s, ParsePosition pp) { // parse stuff }
    }
    return (Foo) new FooFormat().parse(in);

}

16 Java中可以使用标号

public int aMethod(){
    http://www.google.com
    return 1;
}
上面的http:是一个标号, //是注释

17 没有main方法的HelloWorld

public class WithoutMain {
    static {
        System.out.println("Look ma, no main!!");
        System.exit(0);
    }
}

运行结果:
$ java WithoutMain
Look ma, no main!!

18 Shutdown钩子

在虚拟机停掉之前被调用:
Runtime.getRuntime().addShutdownHook(new Thread() {
                  public void run() {
                      endApp();
                  }
            });;

19 URL类的equals方法

new URL("http://www.yahoo.com").equals(new URL("http://209.191.93.52"))

上述代码结果为true

20 在没有声明抛出任何异常的方法中抛出受检查异常

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!"));
    }
}

21 可以抛出null

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

22 自动装箱中的一些规则

Long value = new Long(0);
		System.out.println(value.equals(0));  //false
		
		Integer i = 0;
		System.out.println(i.equals(0));     //true
		
		Integer j = new Integer(0);
		System.out.println(j.equals(0));	//true
		System.out.println(j.equals(i));	//true
		System.out.println(i == j);			//false
		
		Integer m = 0;
		System.out.println(i.equals(m));	//true
		System.out.println(i == m);			//true
		
		Integer x = 128;
		Integer y = 128;
		Integer z = new Integer(128);
		System.out.println(x.equals(y));	//true
		System.out.println(x == y);			//fasle
		System.out.println(x.equals(z));	//true
		System.out.println(x == z);		//false

23 在finally块中返回

	@SuppressWarnings("finally")
	public static int returnSomething() {
	    try {
	        throw new RuntimeException("foo!");
	    } finally {
	        return 1;
	    }
	    
	    //在这里可以不写return语句
	}
	
	public static void main(String[] args) {
		System.out.println(returnSomething());   // 返回1
	}

24 数组初始化的误区

以下代码是正确的:
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" });
    }
}

25 内部类中使用this访问外部类成员

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;
}
}

26 final局部变量可以不再声明的同时初始化

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;
}

27 使用初始化块快速创建对象

Map map = new HashMap() {{
    put("a key", "a value");
    put("another key", "another value");
}};

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");
                        }
                     });
                 }});
        }});
    }};

28 java1.5中引入可变参数

public void foo(String... bars) {
   for (String bar: bars)
      System.out.println(bar);
}

29 枚举可以实现一个接口

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; }
}

30 泛型方法可以显示指定类型参数

Collections.<String,Integer>emptyMap()

31 枚举中可以有构造方法和普通方法

enum Cats {
  FELIX(2), SHEEBA(3), RUFUS(7);

  private int mAge;
  Cats(int age) {
    mAge = age;
  }
  public int getAge() {
    return mAge;
   }
}

32 finally块中的return语句阻止try中异常的抛出

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;
    }
  }

33 instanceof关键字不用判断null

if( null != aObject && aObject instanceof String )
{
    ...
}

可以使用以下代码代替(不用判断null)
if( aObject instanceof String )
{
    ...
}

34 java1.5中引入的协变返回类型

如果子类覆盖了父类的方法, 子类中的方法可以返回父类中方法的返回值类型或其子类型
class Souper {
    Collection<String> values() {
        ...
    }
}

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

35 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;
            }
        }
    }
}

36 初始化块和静态初始化块

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");
  }
}
打印结果如下:
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



37 在泛型的类型限定中使用&限定接口

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

意为:T是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);
}

在foo方法中, 可以使用Comparable接口中的compareTo方法



  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值