Effective Java

第37条:用标记接口定义类型

2017-06-28  本文已影响0人  NekoJiang

定义

标记接口(marker interface):没有包含方法声明的接口,而只是指明一个类实现了具有某种属性的接口。例如,Serializable接口。
标记注解(marker annotation):特殊类型的注解,其中不包含成员。标记注解的唯一目的就是标记声明。例如,@Override。

优缺点对比

标记接口的优点:

pic2.jpg pic1.jpg

Set接口就可以说是这种有限制的标记接口。他只是用与Collection子类型,但是他不会添加除了Collection定义之外的方法。一般情况下,不把它当作标记接口,因为他改进了几个Collection的方法的契约,比如add、equals和hashCode。但是很容易想象只适用于某种特殊接口的子类型的标记接口,他没有改进接口的任何方法的契约。这种标记接口可以描述整个对象的某个约束条件,或者表明实例能够利用其他某个类的方法进行处理(就像Serializable接口表明实例可以通过ObjectOutputStream进行处理一样)。

声明set注解:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Set {

}
@Set
public class HashSet {
}

set接口:

public interface Set<E> extends Collection<E> {
    // Query Operations
/** @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     *         element
     * @throws UnsupportedOperationException if the <tt>add</tt> operation
     *         is not supported by this set
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this set
     * @throws NullPointerException if the specified element is null and this
     *         set does not permit null elements
     * @throws IllegalArgumentException if some property of the specified element
     *         prevents it from being added to this set
     */
    boolean add(E e);
}
public interface Collection<E> extends Iterable<E> {
/** @param e element whose presence in this collection is to be ensured
     * @return <tt>true</tt> if this collection changed as a result of the
     *         call
     * @throws UnsupportedOperationException if the <tt>add</tt> operation
     *         is not supported by this collection
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this collection
     * @throws NullPointerException if the specified element is null and this
     *         collection does not permit null elements
     * @throws IllegalArgumentException if some property of the element
     *         prevents it from being added to this collection
     * @throws IllegalStateException if the element cannot be added at this
     *         time due to insertion restrictions
     */
    boolean add(E e);
}

标记注解的优点

import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
 * Created by Jiang Meiwei on 2017/6/27.
 */

@Retention(RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptinTest{
Class<? extends Exception> value();
}
package com.thunisoft.yilian.lafx.server.ajsc;

/**
 * Created by Jiang Meiwei on 2017/6/28.
 */
public class Sample {
    
    @ExceptinTest(ArithmeticException.class)
    public static void m1(){
        int i = 0;
        i = i/i;
    }
    @ExceptinTest(ArithmeticException.class)
    public static void m2(){
        int[] a = new int[0];
        int i = a[1];
    }

    @ExceptinTest(ArithmeticException.class)
    public static void m3(){
    }
}
package com.thunisoft.yilian.lafx.server.ajsc;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Created by Jiang Meiwei on 2017/6/28.
 */
public class RunTests {
    public static void main(String[] args) throws ClassNotFoundException{
        int tests = 0;
        int passed = 0;
        Class testClass = Class.forName("com.thunisoft.yilian.lafx.server.ajsc.Sample");
        for (Method m: testClass.getDeclaredMethods()) {
            if(m.isAnnotationPresent(ExceptinTest.class)){
                tests++;
                try {
                    m.invoke(null);
                }catch (InvocationTargetException wrappedEx) {
                    Throwable exc = wrappedEx.getCause();
                    Class<? extends Exception> excType = m.getAnnotation(ExceptinTest.class).value();
                    if(excType.isInstance(exc)){
                        passed++;
                    } else {
                        System.out.printf("Test %s failed: exppected %s, got %s%n", m, excType.getName(), exc);
                        
                    }
                } catch(Exception exc){
                    System.out.printf("Test %s failed: on exception%n", m);
                }
            }
        }

    }
}

输出结果:

pic3.jpg

做了如下更改:

pic4.jpg

标记注解和标记接口的选择

总结:从某种意义上说,本条目与第19条中“如果不想定义类型就不要使用接口”的说法相反。本条目接近的意思是说:如果想要定义类型,一定要使用接口

上一篇 下一篇

猜你喜欢

热点阅读