如何读取注解
要读取注解的内容,就需要使用反射的技术。
注意:要想使用反射得到注释信息,必须用@Retention(RetentionPolicy.RUNTIME)进行注解。
/** * 分别读取类上的@MyAnno注解 和 方法上的@MyAnno注解 */ @Test public void readAnno(){ //※※注意:MyAnno注解定义时,必须指定它的保持性为 RUNTIME,否则下面是读取不出注解的 //以下方式是读取“声明在类上的”MyAnno注解 Class c = UserModel.class; //boolean boo = c.isAnnotationPresent(cn.hncu.anno.MyAnno.class); //boolean boo = c.isAnnotationPresent(MyAnno.class); boolean boo = (c.getAnnotation(MyAnno.class)!=null); System.out.println(boo); //以下方式是读取“声明在方法上的”MyAnno注解 Method ms[] = c.getDeclaredMethods(); for(Method m:ms){ if(m.isAnnotationPresent(MyAnno.class)){ System.out.println(m.getName()+"方法上有@MyAnno注解"); } } }
结果:
true getAge方法上有@MyAnno注解 getId方法上有@MyAnno注解
类加载器
Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:
BootStrap, ExtClassLoader, AppClassLoader @Test public void systemLoaderDemo(){ ClassLoader loader = Person.class.getClassLoader(); System.out.println(loader);//AppClassLoader loader = loader.getParent(); System.out.println(loader);//ExtClassLoader loader = loader.getParent(); System.out.println(loader);//null }
因为BootStrap是最底层,用C写的,我们不能访问到,我们没有权限,所以输出就是null了。
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap。
Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。
☆类加载器的委托机制
通过API认识ClassLoader类
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果为ExtClassLoader的原因。
演示不是classpath下的类,系统类加载器是无法加载的
Person类:
package cn.hncu; /** * * @author 陈浩翔 * * @version 1.0 2016-5-4 */ public class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
@Test public void loaderLocalClassDemo() throws ReflectiveOperationException{ Class c = Class.forName("cn.hncu.Person"); System.out.println(c); Object obj = c.newInstance(); System.out.println(obj); }
运行结果:
class cn.hncu.Person
Person [name=null, age=0]
再看:
我把Person.class移到d:\cn\hncu
//不是classpath下的类,系统类加载器是无法加载的---如果要加载,得自己写类加载器 @Test public void loaderRemoteClassDemo() throws ReflectiveOperationException{ Class c = Class.forName("d:\\cn\\hncu\\Person.class"); System.out.println(c); Object obj = c.newInstance(); System.out.println(obj); }
结果:
挂了,不能运行了。
因为没有配置classpath。
对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果为ExtClassLoader
必须是压.class文件,不要压缩.java文件。!!!!
package cn.hncu; /** * * @author 陈浩翔 * * @version 1.0 2016-5-4 */ public class LoaderDemo { public static void main(String[] args) { LoaderDemo a = new LoaderDemo(); System.out.println(a); } @Override public String toString() { return "随便演示。。。chx"; } }
先按照这个命令打包这个.java
package cn.hncu; /** * * @author 陈浩翔 * * @version 1.0 2016-5-4 */ public class LoaderDemo { public static void main(String[] args) { LoaderDemo a = new LoaderDemo(); System.out.println(a); } @Override public String toString() { return "湖南城院。。。随便演示...chx"; } //改了没用。已经不会运行这里的代码了。 }
结果:
对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果还是为ExtClassLoader。
也就是那三层从上到下,如果上面已经有那个类了,就不会运行下面的那个类:
BootStrap—>ExtClassLoader—>AppClassLoader(System classLoader)
大家再看看这个图,是不是感觉容易理解一些了: