码迷,mamicode.com
首页 > 编程语言 > 详细

java强化篇(四)---注解、泛型。类加载器.线程

时间:2014-10-15 10:54:50      阅读:294      评论:0      收藏:0      [点我收藏+]

标签:泛型      线程   classloader   

Java的三个基本注解

@Deprecated :标记此程序元素已过时,通常是因为它很危险或存在更好的选择。

@SuppressWarnings :取消显示指定的编译器警告。

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

元注解@Retention--定义注解类的存在区域,有三种取值:RetentionPolicy.SOURCE、RetentionPolicy.CLASS、 RetentionPolicy.RUNTIME,分别对应java源文件、class文件、内存中的字节码。

元注解@Target:确定注解类可用范围,取值ElementType.METHOD...

 

定义基本类型的属性
在注解类中增加String color();
引用:@MyAnnotation(color=“red”)

用反射获得注解对应的实例对象后,再通过对象调用属性对应的方法。
MyAnnotation a=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation)
System.out.println(a.color);

为属性定义缺省值String color()default “red”;

Value属性  String value();
如果一个 注解只有一个名称为value的属性,且你只想设置value的属性,可以省略,@MyAnnotation(“red”);

 

泛型

ArrayList<E>类定义和ArrayList<Integer>类引用中涉及的术语:
  1、 整个ArrayList<E>称为泛型类型
  2、ArrayList<E>中E称为类型变量或类型参数
  3、整个ArrayList<Integer>称为参数化的类型
  4、ArrayList<Integer>中的Integer叫类型参数的实例或实际类型参数
  5、ArrayList<Integer>中的<>念typeof
  6、ArrayList称为原始类型

参数化类型与原始类型的兼容性-编译警告
Collection<String> = new Vector();
Collection = new Vector<String >();

参数化类型不考虑类型参数的继承关系
Vector<String> v = new Vector<Object>(); //错!
Vector<Object> v = new Vector<String>();//错!

在创建数组实例时,数组的元素不能使用参数化的类型。

 

定义泛型类

类中的多个方法要使用同一个泛型参数,此时要定义类级别的泛型。
public class GenericDao<T>{
       private T field1;
       public void save<T obj>{}
       public T getById(int ID){}
}

类级别的泛型是根据引用类名指定的泛型信息来参数化变量的.
GenericDao<String> dao=null;
new GenericDao<String>();

注意
1、在对泛型参数化时,必须是引用类型,不能是基本类型。
2、当一个类被声明为泛型时,只能被实例变量和方法调用(还有内嵌类),而不能被静态变量和静态方法调用。因为类静态成员是被所有参数化的类所共享的,所以静态成员不应该拥有类级别的类型参数。

 

通过反射获得泛型的参数化类型

Vector<Date> v = newVector<Date>();
通过v.getClass()是无法获得泛型的参数化类型的。

将其传递给一个方法,可实现此功能。
public static void applyVector(Vector<Date> v){}

Method applyMethod =GenericTest.class.getMethod("applyVector",        Vector.class);

       Type[] types = applyMethod.getGenericParameterTypes();

       ParameterizedType pType = (ParameterizedType)types[0];

       System.out.println(pType.getRawType());//Vector

       System.out.println(pType.getActualTypeArguments()[0]);//Date

 

类加载器之间的父子关系和管辖范围图

当java虚拟机加载类时,到底用哪个类加载器?
 ◇首先当前线程的类加载器去加载线程中的第一个类
 ◇如果类A引用了类B,那么java虚拟机将使用加载类A的类加载器去加载类B
 ◇还可以直接调用ClassLoader.loaderClass()方法来指定某个类加载器去加载

每个类加载器加载时,又委托给其上级的类加载器。
当所有祖宗类加载器没有加载到该类,则回到发起者类加载器,还加载不到,则抛出ClassNoFoundException,不是再找发起者类加载器和儿子,因为没有getChild方法。——从上到下的加载。

 

自定义类加载器

工作机制
父类——>loadClass/findClass()/得到class文件的内容转换成字节码—>difineClass()/将一个 byte 数组转换为 Class 类的实例

实现步骤
 ◇自定义的类加载器必须继承ClassLoader
 ◇覆盖findClass方法
 ◇覆盖difineClass()方法

 

传统线程机制的回顾

创建线程的两种传统方式

在Thread子类覆盖的run方法中编写运行代码

涉及一个以往知识点:能否在run方法声明上抛出InterruptedException异常,以便省略run方法内部对Thread.sleep()语句的try…catch处理?

在传递给Thread对象的Runnable对象的run方法中编写代码

总结:查看Thread类的run()方法的源代码,可以看到其实这两种方式都是在调用Thread对象的run方法,如果Thread类的run方法没有被覆盖,并且为该Thread对象设置了一个Runnable对象,该run方法会调用Runnable对象的run方法。

问题:如果在Thread子类覆盖的run方法中编写了运行代码,也为Thread子类对象传递了一个Runnable对象,那么,线程运行时的执行代码是子类的run方法的代码?还是Runnable对象的run方法的代码?

涉及到的一个以往知识点:匿名内部类对象的构造方法如何调用父类的非默认构造方法。

定时器的应用

Timer类

TimerTask类

 

多个线程访问共享对象和数据的方式

如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做。

如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享:

将共享数据封装在另外一个对象中,然后将这个对象逐一传递给各个Runnable对象。每个线程对共享数据的操作方法也分配到那个对象身上去完成,这样容易实现针对该数据进行的各个操作的互斥和通信。

将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。

上面两种方式的组合:将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable对象作为外部类中的成员内部类或局部内部类。

总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥和通信。

极端且简单的方式,即在任意一个类中定义一个static的变量,这将被所有线程共享。



java强化篇(四)---注解、泛型。类加载器.线程

标签:泛型      线程   classloader   

原文地址:http://blog.csdn.net/u012301841/article/details/40106657

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!