"黑马程序员"张老师Java高新技术学习(注解、类加载器)

原文地址为: "黑马程序员"张老师Java高新技术学习(注解、类加载器)

 
 

 ----------------- android培训java培训、期待与您交流! ----------------------


注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
自定义注解及其应用:
定义一个最简单的注解:public @interface MyAnnotation {}
把它加在某个类上:@MyAnnotation public class AnnotationTest{}
@Retention元注解的讲解,其三种取值:RetetionPolicy.SOURCE、RetetionPolicy.CLASS、RetetionPolicy.RUNTIME;分别对应:java源文件-->class文件-->内存中的字节码。
演示和讲解@Target元注解
Target的默认值为任何元素,设置Target等于ElementType.METHOD,原来加在类上的注解就报错了,改为用数组方式设置{ElementType.METHOD,ElementType.TYPE}就可以了。

定义基本类型的属性和应用属性:
在注解类中增加String color();
@MyAnnotation(color="red")
用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(a.color());
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象
为属性指定缺省值:
String color() default "yellow";
value属性:
String value() default "zxx"; 
如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你只有一个value属性),那么可以省略value=部分,例如:@MyAnnotation("lhm")。

以下是注解的代码实现:

@Retention(RetentionPolicy.RUNTIME)//定义注解的生命周期,在运行期
@Target(ElementType.TYPE)//定义注解的作用范围,在类声明上
public @interface subAnnotation {//通过@interface进行申明注解
   String value();//注解的默认属性
}


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE )
public @interface testAnnotation {
       String color();
       String value() default "abc";//通过default来为注解声明默认的属性值
       String[] arrays();//类型可以使数组
       subAnnotation annotation() default @subAnnotation("bbbb");//属性类型可以是注解
       test.weekday emnuAttr();//属性类型也可以是枚举
}


@testAnnotation(color="red",arrays={"aa","bb","cc"},emnuAttr=test.weekday.sun)//为注解增添属性值
public class test {
public static void main(String[] args)throws Exception {
if(test.class.isAnnotationPresent(testAnnotation.class)){//判断test有没有注解进行标识
testAnnotation annotation=test.class.getAnnotation(testAnnotation.class);//通过反射得到testAnnotation注解
System.out.println(annotation.color());//打印注解的值
System.out.println(annotation.value());
System.out.println(Arrays.asList(annotation.arrays()));
System.out.println(annotation.annotation().value());
System.out.println(annotation.emnuAttr().index);//获得枚举的值
}

/*

一下是枚举的定义

*/

 public enum weekday{
sun(1),sat,mon;//通过括号来调用构造方法
public int index;
private weekday(int index){//构造方法修饰词必须是私有的,而且必须在枚举实例的后面
this.index=index;
}
private weekday(){}
public void print(String s){
System.out.println(s);
}
}

关于类加载器的小结:

Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。
Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。

类加载器的委托机制:
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
首先当前线程的类加载器去加载线程中的第一个类。
如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。 
还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给其上级类加载器。
当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?
对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。

一下代码是调用自己自定义的类加载器:

public class myClassLoad extends ClassLoader {//自定义的类加载器必须继承ClassLoader


public void addSecretFile(InputStream inputStream, OutputStream out) {//该方法将输入流字节进行解密后输出到输出流中
int b = -1;
try {
while ((b = inputStream.read()) != -1) {
out.write(b ^ 0xff);//将每个b进行解密
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
FileInputStream inputStream = new FileInputStream("folder\\" + name+".class");//得到加密的class文件流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();//字节数组流,用于接受class文件的字节
this.addSecretFile(inputStream, byteArrayOutputStream);//进行解密到字节数组
byte[] bytes = byteArrayOutputStream.toByteArray();//得到字节数组
System.out.println("aa");
return defineClass(bytes, 0, bytes.length);//调用父类的defineClass方法返回Class类
} catch (Exception e) {
e.printStackTrace();
}
return super.findClass(name);
}


public myClassLoad() {
}
}


public class myclassLoadTest {
   public static void main(String[] args) throws Exception {
Class clazz=new myClassLoad().loadClass("Demo");
Date demo=(Date) clazz.newInstance();//注意,这里必须返回Demo类的父类来指向它,因为Demo类进行了加密,编译器是不认识的
}
}

  ---------------------- android培训java培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net/heima


转载请注明本文地址: "黑马程序员"张老师Java高新技术学习(注解、类加载器)

猜你喜欢

转载自blog.csdn.net/wcqlwyt/article/details/80327400
今日推荐