Java的反射机制


1.反射不受到public,private,protected等的限制,
可以随意创建,修改,读取private(等)类的private(等)函数或者成员变量
2.
Class clz = Class.forName("类名")

Method mtd = clz.getMethod("函数名",new Class[]{参数类型列表})
这种方法只能获取到clz类中public的函数,private的函数无法获取到

Method mtd = clz.getDeclaredMethod("函数名",new Class[]{参数类型列表})
这种方法能够获取到clz类的所有声明的函数,无论是public的,private的还是protected的

Field,同样有clz.getField和clz.getDeclaredField之分(与Method同理)

mtd.invoke(obj,new Object[]{参数列表})
如果是一个实例函数的调用(非static的函数), 则obj应该是该类的实例
如果调用的是static函数,obj = null即可

常用的写法:

                Class DexFileClz = Class.forName("dalvik.system.DexFile");
		
		Class[] paratype = new Class[1];
		paratype[0] = byte[].class;   //注意 数组的类型 如何表示
				
		Object[] paraobj = new Object[1];
		paraobj[0] = dexContent;//dexContent是byte[]
		
		Method openDexFilemtd = DexFileClz.getDeclaredMethod("openDexFile", paratype);
		openDexFilemtd.setAccessible(true);    //不管是否private,protected,在该程序中都设为可见.
		int retv = (Integer) openDexFilemtd.invoke(null, paraobj);

3.如果反射返回的object是一个数组类型,

例如:
		Object dexElements = RefInvoke.getFieldOjbect("dalvik.system.DexPathList", pthList, "dexElements");

其中dexElements是一个final的protected类, 对当前的程序员来说是不可见的, 所以无法进行强制类型转换. 那么如果想要操作其中的每个
元素就需要使用Array类型:

		int length = Array.getLength(dexElements); //获取数组的长度

		Object ele = Array.get(dexElements, i); //获取数组的第i个元素,i从0开始 (i即数组index)

以上都能明白, Java的反射再无困难

==== === === =天使般的分割线 = = = == = = == = = = = =

以下为反射常用函数集合,若用到反射,下类基本够用!



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

public class RefInvoke {
	
	public static  Object invokeStaticMethod(String class_name, String method_name, Class[] pareTyple, Object[] pareVaules){
		
		try {
			Class obj_class = Class.forName(class_name);
			Method method = obj_class.getMethod(method_name,pareTyple);
			return method.invoke(null, pareVaules);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		}  catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static  Object invokeMethod(String class_name, String method_name, Object obj ,Class[] pareTyple, Object[] pareVaules){
		
		try {
			Class obj_class = Class.forName(class_name);
			Method method = obj_class.getMethod(method_name,pareTyple);
			return method.invoke(obj, pareVaules);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		}  catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static Object getFieldOjbect(String class_name,Object obj, String filedName){
		try {
			Class obj_class = Class.forName(class_name);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			return field.get(obj);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static Object getStaticFieldOjbect(String class_name, String filedName){
		
		try {
			Class obj_class = Class.forName(class_name);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			return field.get(null);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}
		return null;
		
	}
	
	public static void setFieldOjbect(String classname, String filedName, Object obj, Object filedVaule){
		try {
			Class obj_class = Class.forName(classname);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			field.set(obj, filedVaule);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}	
	}
	
	public static void setStaticOjbect(String class_name, String filedName, Object filedVaule){
		try {
			Class obj_class = Class.forName(class_name);
			Field field = obj_class.getDeclaredField(filedName);
			field.setAccessible(true);
			field.set(null, filedVaule);
		} catch (SecurityException e) {
			
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			
			e.printStackTrace();
		}		
	}


}

jad批量反编译的用法

jad -o -r -sjava -dc:/src com/**/*.class

其中src是反编译后的文件夹路径,com/**/*.class是目标反编译路径。使用该方法后,会把整个
com文件夹下的*.class反编译到c:/src文件夹下。

Python动态创建类[总结]

1. globals()
全局变量那就 globals().update(dic).这样就可以将一个字典变量弄成全局变量.
创建动态类两种方式:
from new import classobj
myClass = classobj(‘className’,(baseClass,),{dictAttr:dictValue,…})
参数说明:
classobj(类名,基类列表–必须是tuple,属性字典)
这个时候类的名字不等于类的索引,上面创建的类需要通过myClass来使用。
如果想要把类自己的名字来引用,就像传统的class关键字定义那样,则需要把类的名字加入到全局作用域globals()
globals()[‘className’] = type(‘className’,(baseClass,),{dictAttr:dictValue,…})
2. 来看示例

点击(此处)折叠或打开

  1. class Base(object):
  2.     name = “yao”
  3.     age = 23
  4.     def setUp(self):
  5.         if hasattr(self, “name”):
  6.             print “setUp, %s” % getattr(self, “name”)
  7. from new import classobj
  8. myClass= classobj(“HelloClass”, (Base, ), {“***”:”boy”, “school”:”hn”})
  9. myobject = myClass()
  10. myobject.setUp()
  11. print myobject.*** + ” ->” + str(myobject.age)
  12. # >>>
  13. print getattr(myobject, “school”)
  14. def initParent():
  15.     globals()[‘MyChildClass’]=type(“MyChildClass”, (Base, ), {“***”:”girl”,
  16.         “school”:”nn”})
  17. initParent()
  18. myobject = MyChildClass()
  19. myobject.newAttr = “hello”  #动态创建属性
  20. print myobject.***, myobject.school
  21. print getattr(myobject, “newAttr”)
  22. class A(MyChildClass):      #MyChildClass就是动态创建的类。
  23.     def testup(self):
  24.         if hasattr(self, “***”):
  25.             print ” have *** attritue, %s” % getattr(self, “***”)
  26.         if hasattr(self, “newAttr”):  #这样的属性就没有了
  27.             print “HAVEing!”
  28. a = A()
  29. a.testup()
输出:
setUp, yao
boy ->23
hn
girl nn
hello
have *** attritue, girl

一种应用的场景:

比如在CMDB里面会有多种manfiest设备类型,会有多种类型会有各种不一样的child方法。
这样如果 需要创建多个父类的话可以传递一个变量进去就可以生成多个类。然后就可以继承
可以节省不少的代码量.

 

Java 之 Executors + ExecutorService + 可变参数 + 类反射机制 综合代码实例分析

…. 省略许多代码

private ExecutorService threads;

@Override
public void init(IMContext context) throws IMException {
super.init(context);
//threads = Executors.newCachedThreadPool();
//threads = Executors.newSingleThreadExecutor();
threads = Executors.newFixedThreadPool(2);
}

…… 省略许多代码

@Override

public void submit(final Object target, final String method,final Object… args) {

threads.submit(new Runnable() {
public void run() {
for(Method m: target.getClass().getDeclaredMethods()){
if(m.getName().equals(method)){
try {
if(!m.isAccessible()){
m.setAccessible(true);
}
m.invoke(target, args);
return;
} catch (Throwable e) {
LOG.warn(“invoke method error!!”, e);
}
}
}
}

 

ava.util.concurrent
类 Executors

java.lang.Object
  继承者 java.util.concurrent.Executors

public class Executors
extends Object

此包中所定义的?ExecutorExecutorServiceScheduledExecutorServiceThreadFactory?和?Callable?类的工厂和实用方法。此类支持以下各种方法:

  • 创建并返回设置有常用配置字符串的?ExecutorService?的方法。
  • 创建并返回设置有常用配置字符串的?ScheduledExecutorService?的方法。
  • 创建并返回“包装的”ExecutorService 方法,它通过使特定于实现的方法不可访问来禁用重新配置。
  • 创建并返回?ThreadFactory?的方法,它可将新创建的线程设置为已知的状态。
  • 创建并返回非闭包形式的?Callable?的方法,这样可将其用于需要?Callable?的执行方法中。

 

 

从以下版本开始:
1.5

方法摘要
static?Callable<Object> callable(PrivilegedAction?action)
返回?Callable?对象,调用它时可运行给定特权的操作并返回其结果。
static?Callable<Object> callable(PrivilegedExceptionAction?action)
返回?Callable?对象,调用它时可运行给定特权的异常操作并返回其结果。
static?Callable<Object> callable(Runnable?task)
返回?Callable?对象,调用它时可运行给定的任务并返回?null
static

<T>?Callable<T>
callable(Runnable?task, T?result)
返回?Callable?对象,调用它时可运行给定的任务并返回给定的结果。
static?ThreadFactory defaultThreadFactory()
返回用于创建新线程的默认线程工厂。
static?ExecutorService newCachedThreadPool()
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。
static?ExecutorService newCachedThreadPool(ThreadFactory?threadFactory)
创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们,并在需要时使用提供的 ThreadFactory 创建新线程。
static?ExecutorService newFixedThreadPool(int?nThreads)
创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。
static?ExecutorService newFixedThreadPool(int?nThreads,?ThreadFactory?threadFactory)
创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程,在需要时使用提供的 ThreadFactory 创建新线程。
static?ScheduledExecutorService newScheduledThreadPool(int?corePoolSize)
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
static?ScheduledExecutorService newScheduledThreadPool(int?corePoolSize,?ThreadFactory?threadFactory)
创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。
static?ExecutorService newSingleThreadExecutor()
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。
static?ExecutorService newSingleThreadExecutor(ThreadFactory?threadFactory)
创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程,并在需要时使用提供的 ThreadFactory 创建新线程。
static?ScheduledExecutorService newSingleThreadScheduledExecutor()
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
static?ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory?threadFactory)
创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
static

<T>?Callable<T>
privilegedCallable(Callable<T>?callable)
返回?Callable?对象,调用它时可在当前的访问控制上下文中执行给定的?callable?对象。
static

<T>?Callable<T>
privilegedCallableUsingCurrentClassLoader(Callable<T>?callable)
返回?Callable?对象,调用它时可在当前的访问控制上下文中,使用当前上下文类加载器作为上下文类加载器来执行给定的?callable?对象。
static?ThreadFactory privilegedThreadFactory()
返回用于创建新线程的线程工厂,这些新线程与当前线程具有相同的权限。
static?ExecutorService unconfigurableExecutorService(ExecutorService?executor)
返回一个将所有已定义的?ExecutorService?方法委托给指定执行程序的对象,但是使用强制转换可能无法访问其他方法。
static?ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService?executor)
返回一个将所有已定义的?ExecutorService?方法委托给指定执行程序的对象,但是使用强制转换可能无法访问其他方法。

 

接口 ExecutorService

方法摘要
?boolean awaitTermination(long?timeout,?TimeUnit?unit)
请求关闭、发生超时或者当前线程中断,无论哪一个首先发生之后,都将导致阻塞,直到所有任务完成执行。
<T>?List<Future<T>>
invokeAll(Collection<Callable<T>>?tasks)
执行给定的任务,当所有任务完成时,返回保持任务状态和结果的 Future 列表。
<T>?List<Future<T>>
invokeAll(Collection<Callable<T>>?tasks, long?timeout,?TimeUnit?unit)
执行给定的任务,当所有任务完成或超时期满时(无论哪个首先发生),返回保持任务状态和结果的 Future 列表。
<T> T
invokeAny(Collection<Callable<T>>?tasks)
执行给定的任务,如果某个任务已成功完成(也就是未抛出异常),则返回其结果。
<T> T
invokeAny(Collection<Callable<T>>?tasks, long?timeout,?TimeUnit?unit)
执行给定的任务,如果在给定的超时期满前某个任务已成功完成(也就是未抛出异常),则返回其结果。
?boolean isShutdown()
如果此执行程序已关闭,则返回?true
?boolean isTerminated()
如果关闭后所有任务都已完成,则返回?true
?void shutdown()
启动一次顺序关闭,执行以前提交的任务,但不接受新任务。
?List<Runnable> shutdownNow()
试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
<T>?Future<T>
submit(Callable<T>?task)
提交一个返回值的任务用于执行,返回一个表示任务的未决结果的 Future。
?Future<?> submit(Runnable?task)
提交一个 Runnable 任务用于执行,并返回一个表示该任务的 Future。
<T>?Future<T>
submit(Runnable?task, T?result)
提交一个 Runnable 任务用于执行,并返回一个 Future,该 Future 表示任务一旦完成后即返回给定的结果。

 

 

Java类反射机制之Method, 定义一个方法对象, getName()获取该方法的方法名。 Class定义一个类对象,Class的对象的getDeclaredMethods获取在该类中定义的方法的集合:

类 Class<T>

方法摘要
<U>?Class<? extends U>
asSubclass(Class<U>?clazz)
强制转换该?Class?对象,以表示指定的 class 对象所表示的类的一个子类。
?T cast(Object?obj)
将一个对象强制转换成此?Class?对象所表示的类或接口。
?boolean desiredAssertionStatus()
如果要在调用此方法时,将要初始化该类,则返回将分配给该类的断言状态。
static?Class<?> forName(String?className)
返回与带有给定字符串名的类或接口相关联的?Class?对象。
static?Class<?> forName(String?name, boolean?initialize,?ClassLoader?loader)
使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的?Class?对象。
<A extends?Annotation>
A
getAnnotation(Class<A>?annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
?Annotation[] getAnnotations()
返回此元素上存在的所有注释。
?String getCanonicalName()
返回《Java Language Specification》中所定义的基础类的规范化名称。
?Class[] getClasses()
返回一个包含某些?Class?对象的数组,这些对象表示属于此?Class?对象所表示的类的成员的所有公共类和接口,包括从超类和公共类继承的以及通过该类声明的公共类和接口成员。
?ClassLoader getClassLoader()
返回该类的类加载器。
?Class<?> getComponentType()
返回表示数组组件类型的?Class。
?Constructor<T> getConstructor(Class…?parameterTypes)
返回一个?Constructor?对象,它反映此?Class?对象所表示的类的指定公共构造方法。
?Constructor[] getConstructors()
返回一个包含某些?Constructor?对象的数组,这些对象反映此?Class?对象所表示的类的所有公共构造方法。
?Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注释。
?Class[] getDeclaredClasses()
返回?Class?对象的一个数组,这些对象反映声明为此?Class?对象所表示的类的成员的所有类和接口,包括该类所声明的公共、保护、默认(包)访问及私有类和接口,但不包括继承的类和接口。
?Constructor<T> getDeclaredConstructor(Class…?parameterTypes)
返回一个?Constructor?对象,该对象反映此?Class?对象所表示的类或接口的指定构造方法。
?Constructor[] getDeclaredConstructors()
返回?Constructor?对象的一个数组,这些对象反映此?Class?对象表示的类声明的所有构造方法。
?Field getDeclaredField(String?name)
返回一个?Field?对象,该对象反映此?Class?对象所表示的类或接口的指定已声明字段。
?Field[] getDeclaredFields()
返回?Field?对象的一个数组,这些对象反映此?Class?对象所表示的类或接口所声明的所有字段,包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段。
?Method getDeclaredMethod(String?name,?Class…?parameterTypes)
返回一个?Method?对象,该对象反映此?Class?对象所表示的类或接口的指定已声明方法。
?Method[] getDeclaredMethods()
返回?Method?对象的一个数组,这些对象反映此?Class?对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
?Class<?> getDeclaringClass()
如果此?Class?对象所表示的类或接口是另一个类的成员,则返回的?Class?对象表示该对象的声明类。
?Class<?> getEnclosingClass()
返回基础类的立即封闭类。
?Constructor<?> getEnclosingConstructor()
如果该?Class?对象表示构造方法中的一个本地或匿名类,则返回?Constructor?对象,它表示基础类的立即封闭构造方法。
?Method getEnclosingMethod()
如果此?Class?对象表示某一方法中的一个本地或匿名类,则返回?Method?对象,它表示基础类的立即封闭方法。
?T[] getEnumConstants()
如果此 Class 对象不表示枚举类型,则返回枚举类的元素或 null。
?Field getField(String?name)
返回一个?Field?对象,它反映此?Class?对象所表示的类或接口的指定公共成员字段。
?Field[] getFields()
返回一个包含某些?Field?对象的数组,这些对象反映此?Class?对象所表示的类或接口的所有可访问公共字段。
?Type[] getGenericInterfaces()
返回表示某些接口的?Type,这些接口由此对象所表示的类或接口直接实现。
?Type getGenericSuperclass()
返回表示此?Class?所表示的实体(类、接口、基本类型或 void)的直接超类的?Type
?Class[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
?Method getMethod(String?name,?Class…?parameterTypes)
返回一个?Method?对象,它反映此?Class?对象所表示的类或接口的指定公共成员方法。
?Method[] getMethods()
返回一个包含某些?Method?对象的数组,这些对象反映此?Class?对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共?member?方法。
?int getModifiers()
返回此类或接口以整数编码的 Java 语言修饰符。
?String getName()
以?String?的形式返回此?Class?对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
?Package getPackage()
获取此类的包。
?ProtectionDomain getProtectionDomain()
返回该类的?ProtectionDomain。
?URL getResource(String?name)
查找带有给定名称的资源。
?InputStream getResourceAsStream(String?name)
查找具有给定名称的资源。
?Object[] getSigners()
获取此类的标记。
?String getSimpleName()
返回源代码中给出的基础类的简称。
?Class<? super?T> getSuperclass()
返回表示此?Class?所表示的实体(类、接口、基本类型或 void)的超类的?Class。
?TypeVariable<Class<T>>[] getTypeParameters()
按声明顺序返回?TypeVariable?对象的一个数组,这些对象表示用此?GenericDeclaration?对象所表示的常规声明来声明的类型变量。
?boolean isAnnotation()
如果此?Class?对象表示一个注释类型则返回 true。
?boolean isAnnotationPresent(Class<? extends?Annotation>?annotationClass)
如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
?boolean isAnonymousClass()
当且仅当基础类是匿名类时返回?true
?boolean isArray()
判定此?Class?对象是否表示一个数组类。
?boolean isAssignableFrom(Class<?>?cls)
判定此?Class?对象所表示的类或接口与指定的?Class?参数所表示的类或接口是否相同,或是否是其超类或超接口。
?boolean isEnum()
当且仅当该类声明为源代码中的枚举时返回 true。
?boolean isInstance(Object?obj)
判定指定的?Object?是否与此?Class?所表示的对象赋值兼容。
?boolean isInterface()
判定指定的?Class?对象是否表示一个接口。
?boolean isLocalClass()
当且仅当基础类是本地类时返回?true
?boolean isMemberClass()
当且仅当基础类是成员类时返回?true
?boolean isPrimitive()
判定指定的?Class?对象是否表示一个基本类型。
?boolean isSynthetic()
如果此类是复合类,则返回?true,否则?false
?T newInstance()
创建此?Class?对象所表示的类的一个新实例。
?String toString()
将对象转换为字符串。

 

Java 可变参数

 

Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。注意:可变参数必须位于最后一项。当可变参数个数多余一个时,必将有一个不是最后一项,所以只支持有一个可变参数。因为参数个数不定,所以当其后边还有相同类型参数时,java无法区分传入的参数属于前一个可变参数还是后边的参数,所以只能让可变参数位于最后一项。

可变参数的特点:

(1)、只能出现在参数列表的最后;

(2)、…位于变量类型和变量名之间,前后有无空格都可以;

(3)、调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中一数组的形式访问可变参数。

public class Varable {
public static void main(String [] args){
System.out.println(add(2,3));
System.out.println(add(2,3,5));
}
public static int add(int x,int …args){
int sum=x;
for(int i=0;i<args.length;i++){
sum+=args[i];
}
return sum;
}
}

[Java]Annotation元数据的几个应用||Java使用Annotation实现I18N

Tiger出笼以后, Annotation成了一个小小的亮点,虽然有抄袭.net之嫌疑,毕竟让Java开发者方便了许多。EJB3.0和Hibernate Annotation版都是基于这个东西了。下面是结合Spring的自动Log/鉴权/国际化应用:

public interface SessionService extends Service {
    @Anonymous //允许未登录用户调用
    @OperationLog //自动log
    @Name(zh = “登录”)
    public String login(
            @Name(en=”user”,zh = “用户”)String user,
            @OperationLog(false)String password); //不log密码

    @OperationLog
    @Name(zh=”注销”)
    public void logout();

@Anonymous用于鉴权,允许匿名访问。通过ThreadLocal的变量保存当前用户的Session信息。
@OperationLog 用于标记是否自动Log, 可以作用于类、方法、参数
@Name用于i18n国际化支持。Java里面常见的国际化解决方法是.properties文件,个人认为这个方案不好,适合大型项目开发。小项目中这个标记一下足矣。如果要添加一种语言,只要在@Name中多一个参数,利用Eclipse的reference很容易知道有哪些地方要翻译。

同样@Name还可以加在Bean上,自动构造多语言的Table/List,方便之极。

@Name(zh=”安全事件”,en=”Security Event”)
public class SecurityEvent extends AbstractEmsEvent{
    String cause;
    @Name(zh=”原因”)
    public String getCause() {
        return cause;
    }
    
}

附上我的I18nUtil工具类:

/**
 * @author steeven
 */
public class I18nUtil {
    public static String getName(Method method) {
        return getI18n(method,Name.class);
    }
    public static String getTip(Method method) {
        return getI18n(method,Tip.class);
    }
    public static String getI18n(Method method,Class<? extends Annotation> i18nClass) {
        Annotation i18n = method.getAnnotation(i18nClass);
        return getProperty(i18n,method.getName());
    }

    public static String getProperty(Annotation i18n, String defaultValue) {
        if (i18n==null)
            return defaultValue;
        Class<? extends Annotation> clz = i18n.annotationType();
        try {
            Method method = clz.getMethod(getI18nMethodName());
            assert method!=null;
            String r = (String) method.invoke(i18n);
            return r==null || r.length()==0?defaultValue:r;
        } catch (Exception e) {
            assert false;
            return defaultValue;
        }
    }

    private static String getI18nMethodName() {
        return Locale.getDefault().getLanguage();
    }

    @SuppressWarnings(“unchecked”)
    public static <T extends Annotation> T getAnnotation(Annotation[] argAnnotations, Class<T> clz) {
        for(Annotation anno:argAnnotations)
            if (clz.isInstance(anno))
                return (T) anno;
        return null;
    }
}

元数据的结构似乎有些简单,有时候要加很多@Name,@Tip,@Help好像没办法一个Tag搞定。

另外,还可以通过Annotation加上验证、输入界面描述,等等。程序很容易自动化,再多的画面也用不了多少代码。

Jdk5.0提供了这么好用的原数据机制,你有什么好的用法呢?

From: http://www.cnblogs.com/steeven/archive/2005/07/28/201684.html

java自定义注解

Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。

1、元注解

元注解是指注解的注解。包括  @Retention @Target @Document @Inherited四种。
1.1、@Retention: 定义注解的保留策略

@Retention(RetentionPolicy.SOURCE)   //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME)  // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
1.2、@Target:定义注解的作用目标
其定义的源码为:
复制代码
1 @Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target(ElementType.ANNOTATION_TYPE)
4 public @interface Target {
5     ElementType[] value();
6 }
复制代码

@Target(ElementType.TYPE)   //接口、类、枚举、注解

@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR)  //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
 由以上的源码可以知道,他的elementType 可以有多个,一个注解可以为类的,方法的,字段的等等
1.3、@Document:说明该注解将被包含在javadoc中
1.4、@Inherited:说明子类可以继承父类中的该注解
2、java 注解的自定义
      下面是自定义注解的一个例子
复制代码
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Yts {
    public enum YtsType{util,entity,service,model};
   public YtsType classType() default YtsType.util;
}
复制代码

 

复制代码
1 @Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target(ElementType.METHOD)
4 @Inherited
5 public @interface HelloWorld {
6    public String name()default "";
7 }
复制代码

 

@Retention(RetentionPolicy.RUNTIME)

定义的这个注解是注解会在class字节码文件中存在,在运行时可以通过反射获取到。

@Target({ElementType.TYPE,ElementType.METHOD})

因此这个注解可以是类注解,也可以是方法的注解

这样一个注解就自定义好了,当然注解里面的成员可以为基本的数据类型,也可以为数据,Object等等

 

3 注解是定义好了,那么怎么来得到,解析注解呢?

java的反射机制可以帮助,得到注解,代码如下:

复制代码
 1 public class ParseAnnotation {
 2 
 3      public void parseMethod(Class clazz) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException{
 4   Object obj = clazz.getConstructor(new Class[]{}).newInstance(new Object[]{});
 5     for(Method method : clazz.getDeclaredMethods()){
 6         HelloWorld say = method.getAnnotation(HelloWorld.class);
 7         String name = "";
 8         if(say != null){
 9            name = say.name();
10            method.invoke(obj, name);
11         }
12        Yts yts = (Yts)method.getAnnotation(Yts.class);
13        if(yts != null){
14           if(YtsType.util.equals(yts.classType())){
15           System.out.println("this is a util method");
16         }else{
17             System.out.println("this is a other method");
18             }
19         }
20       }
21     }
22     @SuppressWarnings("unchecked")
23     public void parseType(Class clazz) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException{
24         Yts yts = (Yts) clazz.getAnnotation(Yts.class);
25         if(yts != null){
26             if(YtsType.util.equals(yts.classType())){
27                 System.out.println("this is a util class");
28             }else{
29                 System.out.println("this is a other class");
30             }
31         }
32     }
33     
34 }
复制代码

 

前一个方法是解析得到方法注解的,后一个方法是得到类注解的

以下是测试方法类

复制代码
 1 @Yts(classType =YtsType.util)
 2 public class SayHell {
 3 
 4     @HelloWorld(name = " 小明 ")
 5     @Yts
 6     public void sayHello(String name){
 7         if(name == null || name.equals("")){
 8             System.out.println("hello world!");
 9         }else{
10             System.out.println(name + "say hello world!");
11         }
12     }
13 }
复制代码

 

 

复制代码
1 public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException {
2         ParseAnnotation parse = new ParseAnnotation();
3         parse.parseMethod(SayHell.class);
4         parse.parseType(SayHell.class);
5     }
复制代码

http://blog.csdn.net/yixiaogang109/article/details/7328466

 

 

1、Annotation的工作原理:

JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型。该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的class文件和一个注解处理工具组成。

Annotation并不直接影响代码的语义,但是他可以被看做是程序的工具或者类库。它会反过来对正在运行的程序语义有所影响。

Annotation可以冲源文件、class文件或者在运行时通过反射机制多种方式被读取。

2、@Override注解:
java.lang
注释类型 Override
@Target(value=METHOD)
@Retention(value=SOURCE)
public @interface Override

表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。

@Override注解表示子类要重写父类的对应方法。

Override是一个Marker annotation,用于标识的Annotation,Annotation名称本身表示了要给工具程序的信息。

下面是一个使用@Override注解的例子:

class A {
    private String id;
    A(String id){
        this.id = id;
    }
    @Override
    public String toString() {
        return id;
    }
}
3、@Deprecated注解:
java.lang
注释类型 Deprecated
@Documented
@Retention(value=RUNTIME)
public @interface Deprecated

用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告。

@Deprecated注解表示方法是不被建议使用的。

Deprecated是一个Marker annotation。

下面是一个使用@Deprecated注解的例子:

class A {
    private String id;
    A(String id){
        this.id = id;
    }
    @Deprecated
    public void execute(){
        System.out.println(id);
    }
    public static void main(String[] args) {
        A a = new A("a123");
        a.execute();
    }
}
4、@SuppressWarnings注解:
java.lang
注释类型 SuppressWarnings
@Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
@Retention(value=SOURCE)
public @interface SuppressWarnings

指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。注意,在给定元素中取消显示的警告集是所有包含元素中取消显示的警告的超集。例如,如果注释一个类来取消显示某个警告,同时注释一个方法来取消显示另一个警告,那么将在此方法中同时取消显示这两个警告。

根据风格不同,程序员应该始终在最里层的嵌套元素上使用此注释,在那里使用才有效。如果要在特定的方法中取消显示某个警告,则应该注释该方法而不是注释它的类。

@SuppressWarnings注解表示抑制警告。

下面是一个使用@SuppressWarnings注解的例子:

@SuppressWarnings("unchecked")
public static void main(String[] args) {
    List list = new ArrayList();
    list.add("abc");
}
5、自定义注解:

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。

自定义最简单的注解:

public @interface MyAnnotation {

}

使用自定义注解:

public class AnnotationTest2 {

    @MyAnnotation
    public void execute(){
        System.out.println("method");
    }
}
5.1、添加变量:
public @interface MyAnnotation {

    String value1();
}

使用自定义注解:

public class AnnotationTest2 {

    @MyAnnotation(value1="abc")
    public void execute(){
        System.out.println("method");
    }
}

当注解中使用的属性名为value时,对其赋值时可以不指定属性的名称而直接写上属性值接口;除了value意外的变量名都需要使用name=value的方式赋值。

5.2、添加默认值:
public @interface MyAnnotation {

    String value1() default "abc";
}
5.3、多变量使用枚举:
public @interface MyAnnotation {

    String value1() default "abc";
    MyEnum value2() default MyEnum.Sunny;
}
enum MyEnum{
    Sunny,Rainy
}

使用自定义注解:

public class AnnotationTest2 {

    @MyAnnotation(value1="a", value2=MyEnum.Sunny)
    public void execute(){
        System.out.println("method");
    }
}
5.4、数组变量:
public @interface MyAnnotation {

    String[] value1() default "abc";
}

使用自定义注解:

public class AnnotationTest2 {

    @MyAnnotation(value1={"a","b"})
    public void execute(){
        System.out.println("method");
    }
}
6、设置注解的作用范围:
@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)
public @interface Retention

指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。

只有元注释类型直接用于注释时,Target 元注释才有效。如果元注释类型用作另一种注释类型的成员,则无效。

public enum RetentionPolicy
extends Enum<RetentionPolicy>

注释保留策略。此枚举类型的常量描述保留注释的不同策略。它们与 Retention 元注释类型一起使用,以指定保留多长的注释。

CLASS
编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。
RUNTIME
编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
SOURCE
编译器要丢弃的注释。

@Retention注解可以在定义注解时为编译程序提供注解的保留策略。

属于CLASS保留策略的注解有@SuppressWarnings,该注解信息不会存储于.class文件。

6.1、在自定义注解中的使用例子:
@Retention(RetentionPolicy.CLASS)
public @interface MyAnnotation {

    String[] value1() default "abc";
}
7、使用反射读取RUNTIME保留策略的Annotation信息的例子:
java.lang.reflect
        接口 AnnotatedElement
所有已知实现类:
        AccessibleObject, Class, Constructor, Field, Method, Package

表示目前正在此 VM 中运行的程序的一个已注释元素。该接口允许反射性地读取注释。由此接口中的方法返回的所有注释都是不可变并且可序列化的。调用者可以修改已赋值数组枚举成员的访问器返回的数组;这不会对其他调用者返回的数组产生任何影响。

如果此接口中的方法返回的注释(直接或间接地)包含一个已赋值的 Class 成员,该成员引用了一个在此 VM 中不可访问的类,则试图通过在返回的注释上调用相关的类返回的方法来读取该类,将导致一个 TypeNotPresentException。

isAnnotationPresent
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。此方法主要是为了便于访问标记注释而设计的。

参数:

annotationClass – 对应于注释类型的 Class 对象

返回:

如果指定注释类型的注释存在于此对象上,则返回 true,否则返回 false

抛出:

NullPointerException – 如果给定的注释类为 null

从以下版本开始:

1.5

getAnnotation
<T extends Annotation> T getAnnotation(Class<T> annotationClass)

如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。

参数:

annotationClass – 对应于注释类型的 Class 对象

返回:

如果该元素的指定注释类型的注释存在于此对象上,则返回这些注释,否则返回 null

抛出:

NullPointerException – 如果给定的注释类为 null

从以下版本开始:

1.5

getAnnotations
Annotation[] getAnnotations()

返回此元素上存在的所有注释。(如果此元素没有注释,则返回长度为零的数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

返回:

此元素上存在的所有注释

从以下版本开始:

1.5

getDeclaredAnnotations
Annotation[] getDeclaredAnnotations()

返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

返回:

直接存在于此元素上的所有注释

从以下版本开始:

1.5


下面是使用反射读取RUNTIME保留策略的Annotation信息的例子:

自定义注解:

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String[] value1() default "abc";
}

使用自定义注解:

public class AnnotationTest2 {

    @MyAnnotation(value1={"a","b"})
    @Deprecated
    public void execute(){
        System.out.println("method");
    }
}

读取注解中的信息:

public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    AnnotationTest2 annotationTest2 = new AnnotationTest2();
    //获取AnnotationTest2的Class实例
    Class<AnnotationTest2> c = AnnotationTest2.class;
    //获取需要处理的方法Method实例
    Method method = c.getMethod("execute", new Class[]{});
    //判断该方法是否包含MyAnnotation注解
    if(method.isAnnotationPresent(MyAnnotation.class)){
        //获取该方法的MyAnnotation注解实例
        MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
        //执行该方法
        method.invoke(annotationTest2, new Object[]{});
        //获取myAnnotation
        String[] value1 = myAnnotation.value1();
        System.out.println(value1[0]);
    }
    //获取方法上的所有注解
    Annotation[] annotations = method.getAnnotations();
    for(Annotation annotation : annotations){
        System.out.println(annotation);
    }
}
8、限定注解的使用:

限定注解使用@Target。

@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)
public @interface Target

指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。 例如,此元注释指示该声明类型是其自身,即元注释类型。它只能用在注释类型声明上:

@Target(ElementType.ANNOTATION_TYPE)
    public @interface MetaAnnotationType {
        ...
    }

此元注释指示该声明类型只可作为复杂注释类型声明中的成员类型使用。它不能直接用于注释:

@Target({}) 
    public @interface MemberType {
        ...
    }

这是一个编译时错误,它表明一个 ElementType 常量在 Target 注释中出现了不只一次。例如,以下元注释是非法的:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
    public @interface Bogus {
        ...
    }
public enum ElementType
extends Enum<ElementType>

程序元素类型。此枚举类型的常量提供了 Java 程序中声明的元素的简单分类。

这些常量与 Target 元注释类型一起使用,以指定在什么情况下使用注释类型是合法的。

ANNOTATION_TYPE
注释类型声明
CONSTRUCTOR
构造方法声明
FIELD
字段声明(包括枚举常量)
LOCAL_VARIABLE
局部变量声明
METHOD
方法声明
PACKAGE
包声明
PARAMETER
参数声明
TYPE
类、接口(包括注释类型)或枚举声明


注解的使用限定的例子:

@Target(ElementType.METHOD)
public @interface MyAnnotation {

    String[] value1() default "abc";
}
9、在帮助文档中加入注解:

要想在制作JavaDoc文件的同时将注解信息加入到API文件中,可以使用java.lang.annotation.Documented。

在自定义注解中声明构建注解文档:

@Documented
public @interface MyAnnotation {

    String[] value1() default "abc";
}

使用自定义注解:

public class AnnotationTest2 {

    @MyAnnotation(value1={"a","b"})
    public void execute(){
        System.out.println("method");
    }
}
10、在注解中使用继承:

默认情况下注解并不会被继承到子类中,可以在自定义注解时加上java.lang.annotation.Inherited注解声明使用继承。

@Documented
@Retention(value=RUNTIME)
@Target(value=ANNOTATION_TYPE)
public @interface Inherited

指示注释类型被自动继承。如果在注释类型声明中存在 Inherited 元注释,并且用户在某一类声明中查询该注释类型,同时该类声明中没有此类型的注释,则将在该类的超类中自动查询该注释类型。此过程会重复进行,直到找到此类型的注释或到达了该类层次结构的顶层 (Object) 为止。如果没有超类具有该类型的注释,则查询将指示当前类没有这样的注释。

注意,如果使用注释类型注释类以外的任何事物,此元注释类型都是无效的。还要注意,此元注释仅促成从超类继承注释;对已实现接口的注释无效。

除了文章中有特别说明,均为IT宅原创文章,转载请以链接形式注明出处。
本文链接:http://www.itzhai.com/java-based-notebook-annotation-annotation-introduction-and-use-custom-annotations.html