黑马程序员-学习日记23(java高新技术 3 )

来源:互联网 发布:iphone4 ios7越狱优化 编辑:程序博客网 时间:2024/05/21 20:49

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

 

.对JavaBean的复杂内省操作

 1.接口 BeanInfo(java.beans 包)
  1)public interface BeanInfo希望提供有关其 bean 的显式信息的 bean 实现者可以提供某个 BeanInfo 类,
     该类实现此 BeanInfo 接口并提供有关其 bean 的方法、属性、事件等显式信息。
  请参见 SimpleBeanInfo 类,它提供了用于 BeanInfo 类的一个便捷 "noop" 基类,
  可以为那些想要返回显式信息的特定位置重写该基类。
  2)方法摘要
   MethodDescriptor[] getMethodDescriptors()
   获得 beans MethodDescriptor。
  PropertyDescriptor[] getPropertyDescriptors()
   获得 beans PropertyDescriptor。
 2.类 Introspector(java.beans)
  1)public class Introspectorextends Object
  Introspector 类为通过工具学习有关受目标 Java Bean
  支持的属性、事件和方法的知识提供了一个标准方法。

  对于这三种信息,Introspector 将分别分析 bean 的类和超类,寻找显式或隐式信息,
  使用这些信息构建一个全面描述目标 bean 的 BeanInfo 对象。
  2)方法摘要
  static BeanInfo getBeanInfo(Class<?> beanClass)
          在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件。
  static BeanInfo getBeanInfo(Class<?> beanClass, Class<?> stopClass)
          在给定的“断”点之下,在 Java Bean 上进行内省,了解其所有属性和公开的方法。
  static BeanInfo getBeanInfo(Class<?> beanClass, int flags)
          在 Java Bean 上进行内省,了解其所有属性、公开的方法和事件,并将结果用一些控制标记表示。
32.使用BeanUtils工具包操作JavaBean

 1.下载BeanUtils工具包(以jar包形式存在)
   下载commons-beanutils-current.zip-->解压-->查看API-->查看README.txt(可放在编辑器中查看)
 2.安装jar包
   工程上右键-->New-->Folder-->输入名称:lib-->将commons-beanutils.jar 拷贝到lib中
   -->在该jar包上右击-->Build Path-->Add to Build Path(此时该jar包变成了一个小奶瓶的形状)

   注意:在没有将jar包拷到工程中的lib中以前,不可以直接工程右击-->Build Path --> configure-->
   Build Path -->Add External JARS(增加外部的项)
   因为这样的话,jar包还在电脑上,而不在工程当中,此时发给别人用的时候,别人就找不到该jar包。

 3.报错:System.out.println(BeanUtils.getProperty(pt1,"x");代码报错:NoClassDefFoundError
  原因是缺少logging日志开发包。
 4.下载commos-logging-1.1-ide.zip以同样的道理,解压,拷到lib中,再增加到工程当中。

 5.java7的新特性:
  Map map = {name:"lisi",age:18};
  BeanUtils.setProperty(map,"name","zhangsan");

 6.PropertyUtils和BeanUtils的区别;
  BeanUtils接收返回的都是String类型,可自动完成属性的类型转换。
  PropertyUtils是以属性本身的类型进行操作。
33.了解和入门注解的应用

 1.java提供的几个基本注解
  1)@SuppressWarnings压制警告注解
   使提示不再出现。如:@SuppressWarnings("deprecation")//不再提示过时
  2)@Deprecated使过时注解
   标识某个方法或类等已过时,以告诉新人以后尽量不要再使用该方法,同时又
   不会影响以前的老程序。
  3)@Override覆盖注解
   在了类覆盖父类方法时,将非法的覆盖标识出来(或使不正确的覆盖报错),以便修正。

 2.过时的两种表现方式演示:
  1)在eclipse中会直接用删除线标识出来。
  2)命令行的演示:
  <1>普通演示  F:\lx\heima\practice\javaenhance>javac AnnotationTest.java
   注意:AnnotationTest.java 使用或覆盖了已过时的 API。
   注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译。
  <2>显示具体位置  F:\lx\heima\practice\javaenhance>javac -Xlint:deprecation AnnotationTest.java
   AnnotationTest.java:8: 警告:[deprecation] java.lang.System 中的 runFinalizersOn
   Exit(boolean) 已过时
                System.runFinalizersOnExit(true);
                      ^
   1 警告
 3.注解的定义和作用
   1)注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记。java编译器,开发工具,
  和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应
  的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
   2)一个注解就是一个类,使用一个注解就相当于创建了一个注解类的实例对象。
34.注解的定义与反射调用

 1.注解的应用结构图
  注解类
  @interface A
  {
  }

  应用了"注解类"的类
  @A
  class B
  {
  }

  对"应用了注解类的类"进行反射操作的类
  class C
  {
   B.class.isAnnotionPresent(A.class);
   A a = B.class.getAnnotion(A.class);
  }
 2.eclipse使用技巧之创建注解
  1)包上右键-->New -->other-->java-->Annotation
  2)切换到java视图-->包上右键-->New-->Annotation-->输入名字:ItcastAnnotation-->finish
 3.添加元注解的原因分析:
  1)javac 将源文件编译成字节码文件的时候,会将一些不太重要(包括注解在内)的东西去掉。
  2)也可能注解保留到class文件中,类加载器将class文件调到内存过程中也有转换,把class文件
  里面的注解去掉,最终得到的才是字节码文件。(class文件中的东西不是字节码,处理以后才是)
 4.注解的生命周期
   java源文件--->class文件--->内存中的字节码

   @Retention元注解可定义注解的存在阶段。其取值有三个:
   RetetionPolicy.SOURCE,RetetionPolicy.CLASS,Retetionpolicy.RUNTIME(保留到运行期间)

   几个基本注解对应的阶段:
   SuppressWarnings --- SOURCE
   Override --- SOURCE
   Deprecated --- RUNTIME

   注:
    Annotation Type Deprecated
    @Retention(value=RUNTIME)

    RUNTIME的类型为:Enum RetentionPolicy的字段
 5.JDK1.5以后出现的类型TYPE定义包括:
  class,interface,@interface,Enum等

  Type比class更加精准
  Class的父类是interface Type(java.lang.reflect包)

 6.枚举ElementType(java.lang.annotation )
  1)程序元素类型。此枚举类型的常量提供了 Java 程序中声明的元素的简单分类。

  这些常量与 Target 元注释类型一起使用,以指定在什么情况下使用注释类型是合法的
  2)枚举常量摘要
  ANNOTATION_TYPE
      注释类型声明
  CONSTRUCTOR
      构造方法声明
  FIELD
      字段声明(包括枚举常量)
  LOCAL_VARIABLE
      局部变量声明
  METHOD
      方法声明
  PACKAGE
      包声明
  PARAMETER
      参数声明
  TYPE
      类、接口(包括注释类型)或枚举声明


 7.元注解Target()指定注解应用的位置
   @Target(ElementType.METHOD):应用在方法上
   @Target({ElementType.METHOD,ElementType.TYPE}):应用在方法和类上
 8.代码演示:
  
  import java.lang.annotation.ElementType;
  import java.lang.annotation.Retention;
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;


  @Retention(RetentionPolicy.RUNTIME)
  @Target({ElementType.METHOD,ElementType.TYPE})
  public @interface ItcastAnnotation
  {

  }

  详见ItcastAnnotation.java和AnnotationTest.java
35.为注解增加各种属性

 1.什么是注解的属性
  一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,否则,就不是。
  如果还想区分出是传智播客哪个班的学生,这时候可以为胸牌再增加一个属性来进行区分。
  加了属性的标记效果为:@MyAnnotation(color="red")
 2.定义属性的几种方式
  1)定义基本属性和应用属性
  String color();---->@MyAnnotation(color="red");
  2)数组类型的属性
  int[] arrayAttr() default {1,5,2};--->@MyAnnotation(arrayAttr={5,8,9});
  若数组属性中只有一个元素,属性值部分可以省略大括号
  3)枚举类型的属性
  EnumTest.TrafficLamp lamp();--->@MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN);
  4)注解类型的属性:
  MetaAnnotation annotationAttr() default @MetaAnnotation("xxxx");--->
  @MyAnnotation(annotationAttr=@MetaAnnotation("yyy"));

  可以认为@MyAnnotation是MyAnnotation类的一个实例对象,@MetaAnnotation是MetaAnnotation类的一个实
  例对象,调用代码为:
      MetaAnnotation ma = myAnnotation.annotationAttr();
      System.out.priintln(ma.value());

 3.为属性指定缺省值:
  String color() default "yellow";//就是在不赋值情况下默认的值
 4.value属性:
  String value() default "zxx";
  如果注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你
  只有一个value属性),那么可以省略value=部分,如:@MyAnnotation("1hm");
 5.用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
  MyAnnotation a = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
  System.out.println(a.color());
  可以认为上面这个@MyAnnotation是MyAnnotation类的一个实例对象
 6.注:
  枚举和注解都是特殊的类,不能用new创建它们的实例对象,创建枚举的实例对象就是在其中增加元素。
  在程序中创建注解的实例对象,就是直接用@放上一个标记即可。
36.入门泛型的基本应用

 1.eclipse使用技巧之统一改动变量
  选中变量-->右键-->Refactor(alt+shift+T)-->Rename-->改动一处即可
 2.理解泛型
   没有使用泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中。使用泛型集合,可以将一个
   集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全,并且当从集合获到一个
   对象时,编译器也可以知道这个对象的类型,不需要对对象进行强制类型转换,这样更方便。

   注:在JDK1.5中,若按原来的方式将各种不同类型的数据装到一个集合中,编译器会报告unchecked警告。
 3.深解泛型
   泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,
   编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的
   泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型
   信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如:用反射得到集合,
   再调用其add方法即可。
 4.泛型适用的范围:
  只在是支持类型的类都可。<T>
  如:类Constructor<T>(在java.lang.reflect包中)声明构造方法的类
37.泛型的内部原理及更深应用

 1.了解泛型:
  1)ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
     <1>整个ArrayList<E>称为泛型类型
  <2>ArrayList<E>中的E称为类型变量或类型参数
  <3>整个ArrayList<Integer>称为参数化的类型
  <4>ArrayList<Integer>中的integer称为类型参数的实例或实际类型参数
  <5>ArrayList<Integer>中的<>念type of
  <6>ArrayList称为原始类型
  2)参数化类型与原始类型的兼容性:
  参数化类型可以引用一个原始类型的对象,编译报告警告,如:
  Collection<String> c = new Vector();//可不可以,就是编译器一句话的事。
  原始类型可以引用一个参数化类型的对象,编译报告警告,如:
  Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去。
  3)参数化类型不考虑类型参数的继承关系:
  Vector<String> v = new Vector<Object>();//错误//不写<Object>没错,写了就是明知故犯
  Vector<Object> v = new Vector<String>();//也错误观点
  4)在创建数组实例时,数组的元素不能使用参数化的类型,如,以下语句就有错误
  Vector<Integer> vectorList[] = new Vector<Integer>[10];
  5)思考题:下面的代码会报错吗?
  Vector v1 = new Vector<String>();
  Vector<Object> v = v1;

38.泛型的通配符扩展应用

 1.问题:
  定义一个方法,该方法用于打印出任意参数化类型的集合中的所有数据,如何定义?
 2.总结:
  使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以
  调用与参数化无关的方法,不能调用与参数化有关的方法。
 3.两种方式的比较:
  1)
  public static void printCollection(Collection<Object> cols)
  {
  for(Object obj: cols)
  {
   System.out.pritnln(obj);
  }
  cols.add("string");//正确
  cols=new HashSet<Date>();//报错
  }
  2)
  public static void printCollection(Collection<?> cols)
  {
  for(Object obj:cols)
  {
   System.out.println(obj);
  }
  cols.add("string");//错误,因为它不知道自己未来匹配的就一定是String
  cols.size();//正确,此方法与类型参数没有关系
  cols=new HashSet<Date>();//正确

  }

  注意:
  Cols<Object>中的Object只是说明Cols<Object>实例对象中的方法接受的参数是Object
  Cols<Object>是一种具体类型,new HashSet<Date>()也是一种具体类型,两者不兼容。

  Collection<?> a可以与任意参数化的类型匹配,但到底匹配的是什么类型,只有以后才知道,
  所以a=new ArrayList<Integer>和a=new ArrayList<String>都可以,但a.add(new Date())
  或a.add("abc")都不行。
 4.泛型中的?通配符的扩展
  1)限定通配符的上边界:------Number及其子类
  Vector<? extends Number> x = new Vector<Integer>();//正确//Number指八种基本类型类
  Vector<? extends Number> x = new Vector<String>();//错误//String不属于基本类型
  2)限定通配符的下边界:-------Integer及其父类
  Vector<? super Integer> x = new Vector<Number>();//正确
  Vector<? super Integer> x = new Vector<Byte>();//错误

  注意:
  限定通配符总是包括自己。
 5.代码演示:
  public static void printCollection(Collection<?> collection)
  {
   //collection.add(1);
   System.out.println(collection.size());
   for(Object obj : collection)
   {
    System.out.println(obj);
   }
  }
39.泛型集合的综合应用案例
 1.在jsp页面中也经常要对Set或Map集合进行迭代:
  <c:forEach items="${map}"var="entry">
    ${entry.key}:${entry.value}
  </c:forEach>
 2.java的泛型集合类的应用练习:
  见GenericTest.java

  HashMap<String,Integer> maps = new HashMap<String,Integer>();
  maps.put("zxx", 28);
  maps.put("1hm", 35);
  maps.put("flx", 30);
  
  Set<Map.Entry<String,Integer>> entrySet = maps.entrySet();
  for(Map.Entry<String, Integer> entry : entrySet)
  {
   System.out.println(entry.getKey()+":"+entry.getValue());
  }

40.自定义泛型方法及其应用

 1.java的泛型是由C++借鉴而来的
  1)结构相似,类型不同的函数:
  int add(int x,int y)
  {
   return x+y;
  }
  float add(float x,float y)
  {
   return x+y;
  }
  double add(double x,double y)
  {
   return x+y;
  }
  2)C++用模板函数解决,只写一个通用的方法,以适应各种类型:
  template<class T>
  <T>T add(T x,T y)
  {
   return(T)(x+y);
  }

  注意:这些代码在java中则无法通过编译。
 2.java中的泛型没有C++强大的原因分析:
  java语言中的泛型基本上完全是在编译器中实现,用于编译器执行类型检查和类型推断,然后生成普通的非
  泛型的字节码,这种实现技术叫擦除(erasure)(编译器使用泛型类型信息保证类型安全,然后在生成
  字节码之前将其清除)。这是因为扩展虚拟机指令集来支持泛型被认为是无法接受的,这会为java厂商
  升级其JVM造成难以逾越的障碍,所以,java的泛型采用了可以完全在编译器中实现的擦除方法。
 3.泛型的位置规范:
  用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回类型之前,
  也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。
 4.泛型要点:
  1)除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符,例如:
  Class.getAnnotation()方法的定义。并且可以用&来指定多个边界,如:<V extends Serializable &
  cloneable> void method(){}
  2)普通方法,构造方法和静态方法中都可以使用泛型。编译器不允许创建类型变量的数组。
  3)只有引用类型才能作为泛型方法的实际参数,对于add方法,使用基本类型的数据进行测试没问题,是因为
  自动装箱和拆箱了。而swap(new int[3],3,5);报告编译错误,是因为编译器不会对new int[3]中的int
  自动拆箱和装箱了,new int[3]本身已经是对象了,也许你想要的就是int数组呢,它装箱便会弄巧成拙。
  4)在泛型中可以同时有多个类型参数,在定义它们的尖括号中用逗号分开,如:
  public static <K,V> V getValue(K key)
  {
   return map.get(key);
  }
  5)也可以用类型变量表示异常,称为参数化的异常,可以用于方法的throws列表中,
  但是不能用于catch子句中。
   
  异常中采用泛型
  private static <T extends Exception> sayHello() throws T
  {
   try
   {
   }
   catch(Exception e)
   {
    throw (T)e;
   }
  }

 

 

/*
枚举:就是规定好了指定的取值范围,所有的内容只能从指定的范围上取得。
 也就是说一个类只能产生固定的几个对象。如果想完成这样的功能,
 则我肯定要让构造方法私有化,限制别人来new对象,并我在内部产生
 几个固定的对象,并交给外面去使用,
 它最大的作用在于限定类中元素范围。!

 

JDK1.5之后,又模仿C把C/C++里面的很多东西又引进来了。

 

1 ,枚举就相当于一个类,其中也可以定义构造方法,成员变量,普通方法和
 抽象方法。
2 ,枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有做分号
 与其它成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器
 会报错。
3 ,带构造方法的枚举:
 1 ,构造方法必须定义成私有的,作用是:不让在其它类中创建该类对象,只能在本类中创建。
 2 ,如果有多个构造方法,该如何选择哪个构造方法?
 3 ,枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
 4 ,只要用到枚举类,因它里的静态变量都需要随着类的加载而默认调用无参的构造方法来初始化,
  所以构造方法会执行多次,在枚举元素的后面跟上一对括号来指定参数,就表示创建这个元素对象
  时要调用那个构造方法,枚举有自己默认的构造方法,你自己也可指定有参的。
4 ,带方法的枚举:
 1 ,定义枚举TrafficLamp
 2 ,实现普通的next方法。
 3 ,实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类
 4 ,采用类似内部类的方式进行定义。
5 ,枚举只有一个成员时,就可以作为一种单例的实现方式。(要创建单例可以用枚举。)
6 ,

 


枚举 ElementType

static ElementType valueOf(String name)
          返回带有指定名称的该类型的枚举常量。
static ElementType[] values()
          Returns an array containing the constants of this enum type, in the order they are declared.

*/


//用普通类的java类方式来模拟实现一个枚举的功能。
//一个类所定义出来的变量的值只能是这里规定的那么几个,
//但是这个值不是普通类型的值,而是本类对象类型的值,
class EnumDemo1{
 public static void main(String args[]){
  //定义了一个新的类型,这个类型的对象只能指向
  //我固定的几个值,
  //MON是一个WeekDay类型的常量对象并赋给一个引用变量
  //WeekDay1 weekday = WeekDay1.MON;
  //System.out.println(weekday.nextDay());
  WeekDay2 weekday2 = WeekDay2.MON;
  System.out.println(weekday2.nextDay());
 }
}
//这个类创建的对象只能是我规定的几个值。
class WeekDay1{
 //首先把构造方法搞成私有的,作用是:不能在其它类中创建该类对象
 //只能在本类中创建。
 private WeekDay1(){}
 //该类中有几个变量都是常量,用final修饰,
 public final static WeekDay1 SUN = new WeekDay1();
 public final static WeekDay1 MON = new WeekDay1();
 //枚举是一个类里面也可以有方法 ,
 public WeekDay1 nextDay(){
  if(this == SUN){
   return MON;
  }else{
   return SUN;
  }
 }
 //对于每个枚举想打印它的值,需覆写toString方法。
 public String toString(){
  return this == SUN?"SUN":"MON";
 }
}

//另一种实现方式:
//采用抽象方法(类)定义nextDay将大量if.else语句转成一个个独立的类来完成。
//由于上例方法中有大量的if.else语句,有的人想让每一个
//本类对象都用自己独立的方法去写应这样完成。
abstract class WeekDay2{
 private WeekDay2(){}
 //个这父类有两个子类了。
 //在这里写上子类的具体代码,这是个内部类,这个
  //类没有名称,但我可以知道它WeekDay的子类,这
  //表示定义了一个WeekDay的子类,并且用这个子类
  //创建了一个对象,那这个子类的代码就得实现父类
  //中的抽象方法,由于这个内部类对象是SUN,所以
  //方法的返回值应为MON.
 public final static WeekDay2 SUN = new WeekDay2(){
  public WeekDay2 nextDay(){
   return MON;
  }
 };
 public final static WeekDay2 MON = new WeekDay2(){
  public WeekDay2 nextDay(){
   return SUN;
  }
 };
 //由于方法是抽象的,所以本类也得是抽象的。
 //那么我就不能用WeekDay来new对象了,因为抽象的类
 //是不能实例化对象的,我必须用它的子类来new对象,
 //在它的后面写上一个大括号就表示用它的子类来
 //实例化对象,它的这个子类没有名字,所以称为匿名
 //类,这个子类的具体代码,写在后面的大括号中
 public abstract WeekDay2 nextDay();
 public String toString(){
  return this == SUN?"SUN":"MON";
 }
}

 

 

 


class EnumDemo3{
 public static void main(String args[]){
  WeekDay3 weekday3 = WeekDay3.FRI;
  System.out.println(weekday3);
  System.out.println(weekday3.name());
  System.out.println(weekday3.ordinal());
  //返回带有指定名称的该类型的枚举常量。
  System.out.println(WeekDay3.valueOf("SUN"));
  //把枚举中的每一个元素,一个个逐一的装到数组中。
  //当要迭代枚举中的元素时,可用此法,得到数组在遍历。
  System.out.println(WeekDay3.values().length);
 }
}
//定义了一个枚举,里面有三个元素,每一个元素都是枚举
//的一个实例对象,对象可调用的方法有:toString,name,ordinal
//
enum WeekDay3{
 //元素后可打分号,也可不打,如它后,还有内容,则打。
 SUN,MON,TUE,WED,THI,FRI,SAT;
}

 

 

//枚举是一个类,它没有构造方法,我们想为它定义构造方法
//定义非默认的构造方法,也就是带有参数的构造方法,怎么做?
//
enum WeekDay4{
 //枚举元素必须位于枚举中所有成分之前,如果它后有内容加;,
 //枚举的构造方法修饰符必须也是私有的。
 //只要用到枚举类,因它里的静态变量都需要随着类的加载而默认
 //调用无参的构造方法来初始化,所以构造方法都会执行一次。
 //在枚举元素的后面跟上一对括号来指定参数,就表示创建这个元素对象
 //时会调用那个构造方法,
 //枚举有自己默认的构造方法,你自己也可指定有参的。
 SUN(1),MON,TUE,WED,THI,FRI,SAT;
 private WeekDay4(){System.out.println("无参的");}
 private WeekDay4(int day){System.out.println("有参的");}
 public static void main(String args[]){
  
 }
}

 

//new Data(){};这表示new Data类的子类对象,大括号中写子类实现的代码,
//子类构造方法是调用父类中无参的构造方法,我希望子类的
//构造方法调用父类有参的构造方法,是可以的,用 new Data(300){}
//就表示调用父类有参的构造方法。
//new 子类的实例对象,调用父类有参的构造方法。
//外部类前面可加两个修饰符,一个是默认的,一个是public。
//内部类前面可加四个修饰符,因为内部类和成员的关系是平级的。
enum TrafficLamp{
 //每个元素都是这个类的子类的一个实例对象,因这个类
 //中有抽象的方法,说明得通过本类的子类创建对象,
 //三个元素每个元素都是由它的子类来
 RED(30){
  public TrafficLamp nextLamp(){
   return GREEN;
  }
 },
 GREEN(45){
  public TrafficLamp nextLamp(){
   return YELLOW;
  }
 },
 YELLOW(5){
  public TrafficLamp nextLamp(){
   return RED;
  }
 };
 public abstract TrafficLamp nextLamp();
 private int time;
 private TrafficLamp(int time){this.time = time;}
 public static void main(String args[]){}
}