java--加强之 jdk1.5简单新特性,枚举,注解

时间:2022-05-06 19:40:41

转载请申明出处:http://blog.csdn.net/xmxkf/article/details/9944041

 

Jdk1.51新特性(静态导入,可变参数,加强for循环,自动拆装箱)

08.java5的静态导入与编译器语法设置

Jdk1.5后的新语法,如果用新语法了,eclipse中配置的javacjava必须也是新版本。

 

1静态导入import语句可以导入一个类或某个包中的所有类;

          Import static语句导入一个类中的某个静态方法或所有静态方法。

      //import static java.lang.Math.max;  //导入Math类中的静态方法max();

importstatic java.lang.Math.*;   //静态导入  导入Math类中所有静态成员

 

 

09.可变参数与OverLoad相关面试题分析

2可变参数

    Overload   重载    override   覆盖  

   问题:一个方法接受的参数个数不固定,例如:System.out.println(add(2,3,4));

                                             System.out.println(add(2,3,4,5));

   可变参数特点:A、只能出现在参数列表的最后;

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

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

//求和

       publicstaticint add(int x, int... args)   //可变参数int ...args

       {

              int sum = x;

              for(int i=0;i<args.length;i++)

              {

                     sum+=args[i];

              }

              return sum;

       }

 

10.java5的增加for循环

3增强for循环

   语法:for(type变量名:集合变量名){}    遍历集合或数组

   注意事项:迭代变量必须在()中定义;

             集合变量可以是数组或实现了Iterable接口的集合类。

              for(int arg : args)

              {

                     sum+=arg;

              }

11.基本数据的自动拆装箱及享元设计模式

  4基本数据类型的自动拆箱与装箱

     自动装箱:Integer num = 12;              

     自动拆箱:System.out.println(num + 18);   对象拆箱为基本数据类型

 

     基本数据类型的对象缓存:

              Integer i1 = 12; 

              Integer i2 = 12; 

              System.out.println(i1 == i2);    //true

              Integer i3 = 132; 

              Integer i4 = 132; 

              System.out.println(i3 == i4);    //false

 

              Integer i5 = Integer.valueOf(55);

              Integer i6 = Integer.valueOf(55);

              System.out.println(i5 == i6);   //true

             

              String s1 = new String("abc");

              String s2 = new String("abc");

              String s3 ="abc";

              System.out.println(s1==s2);  // false

当将一个基本数据类型的整数装箱成Integer对象时,如果被装箱的这个整数在一个字节之内(-128 ~ 127),会将装箱后的对象缓存起来(认为会常用),当下次要装箱时,会看看这个池子中有没有这个对象,有的话就直接从池子里拿,不用重新创建对象,节省内存。

 

享元设计模式:(flyweight

有很多个小的对象,它们有很多属性都相同(对象的内部状态),把它们变成一个对象,那些不同的属性作为方法的参数(对象的外部状态)

理解:比如在一个word文档中到处都有abc等字母,只要封装26个字母对象,当哪里用到a时,只要改变a的坐标就可以。a.display(int x, int y);

 

*****************************************************************************Java5——枚举****************************************************************************

12.枚举的作用介绍

枚举:也是jdk1.5中新增的一个新特性。

1、为什么要用枚举?

   问题:要定义星期几或者性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;

   枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可让编译器在编译时就可以控制源程序中填写的非法值。普通变量的方式在开发阶段无法实现这一目标。

 

13.用普通类模拟枚举的实现原理

2、用普通类如何实现枚举功能,定义一个Weekday1的类来模拟枚举功能

     A、私有的构造方法;

B、每个元素分别用一个公有的静态成员变量表示;可以有若干公有方法或抽象方法,例如,要提供nextDay方法必须是抽象的。

         采用抽象方法定义nextDay就将大量的if else语句转移成了一个个独立的类

C、具有抽象方法的枚举类,在创建枚举元素时,都是用其子类创建。编译后bin目录下会产生枚举子类class文件(匿名),有几个元素就会产生几个。

abstractclass WeekDay1

{

       //将构造函数设为私有,不让外类创建枚举类对象

       private WeekDay1(){}

      

       //元素分别用一个公有的静态成员变量表示

       publicfinalstatic WeekDay1SUN =new WeekDay1()

       {

              public WeekDay1 nextDay()

              {

                     returnMON;

              }

       };

       publicfinalstatic WeekDay1MON =new WeekDay1()

       {

              public WeekDay1 nextDay()

              {

                     returnSUN;

              }

       };

      

/*    public final static WeekDay TUE = new WeekDay();

       public final static WeekDay WED = new WeekDay();

       public final static WeekDay THU = new WeekDay();

       public final static WeekDay FRI = new WeekDay();

       public final static WeekDay SAT = new WeekDay();*/

      

       //采用抽象方法定义nextDay就将大量的if else语句转移成了一个个独立的类

       publicabstract WeekDay1 nextDay();

      

       //(星期几)对象来调用

       /*public WeekDay nextDay()

       {     

              if(this == SUN)

                     return MON;

              else if(this == MON)

                     return TUE;

              else if(this == TUE)

                     return WED;

              else if(this == WED)

                     return THU;

              else if(this == THU)

                     return FRI;

              else if(this == FRI)

                     return SAT;

              else

                     return SUN;

       }*/

      

       public String toString()

       {

              returnthis==SUN?"SUM":"MON";

       }

}

 

14.java5的枚举的基本应用

3、枚举的基本应用

   举例:定义一个WeekDay的枚举;

   扩展:枚举类的valuesvalueOfnametoStringordinal等方法;

总结:枚举就是一种特殊的类,其中的每个元素都是该类的一个实例对象。

      例如可以调用WeekDay.SUN.getClass().getName()WeekDay.class,getName()

如果想在一个类中编写完各个枚举类和测试调用类,

那么可以将枚举类定义成调用类的内部类。

 

publicstaticvoid main(String[] args)

       {

              WeekDay1 weekDay1 = WeekDay1.MON;

              sop(weekDay1.nextDay());

             

              WeekDay weekDay = WeekDay.FRIDAY;

              sop(weekDay);      //FRIDAY   

              sop(weekDay.name());     //返回此枚举常量的名称FRIDAY

              sop(weekDay.ordinal());     //5  返回枚举常量的序数 0开始

               //静态方法valueOf返回带指定名称的枚举常量SUNDAY

              sop(WeekDay.valueOf("SUNDAY"));   

              //静态方法values()返回此枚举所有的元素的数组

              sop(WeekDay.values().length);             //7

       }

      

       publicenum WeekDay

       {

              SUNDAY,MONDAY,TUESDAYWEDNESDAY,

              THURSDAY,FRIDAY,SATURDAY

       }

 

15.实现带有构造方法的枚举

1、枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。

2、枚举元素必须位于枚举体中最开始的部分,枚举元素列表后要用分号与其他成员分隔。把枚举的成员方法或变量等放在枚举元素的前面,编译时会报错。

3、带构造方法的枚举:枚举的构造方法必须是私有的;

4、枚举元素初始化时默认调用空参数的构造方法;   MONMON()效果一样

当想要它调用自定义带参数构造方法时,可将元素写成  MON(参数列表)

       publicenum WeekDay

       {

              SUNDAY(1),MONDAY(),TUESDAYWEDNESDAY,

              THURSDAY,FRIDAY,SATURDAY ;

              private WeekDay(){System.out.println("first");}

              private WeekDay(int day){System.out.println("second");}

     //除了第一个元素初始化时调用带参数构造函数,其余都调用无参数构造函数

       }

 

16.实现带有抽象方法的枚举

理解:

1、具有抽象方法的枚举,在创建枚举元素时,都是用其子类创建。编译后bin目录下会产生枚举子类class文件(匿名),有几个元素就会产生几个。

2、带方法的枚举:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。

3枚举只有一个成员时,就可以作为一种单例的实现方式。

 

//交通灯枚举

       publicenum TrafficLamp

       {

// new子类的实例对象,调用父类有参的构造方法。

              RED(30){     //每一个元素都是此抽象枚举的匿名子类创建

                     public TrafficLamp nextLamp(){

                            returnGREEN;

                     }

              },

              GREEN(45){

                     public TrafficLamp nextLamp(){

                            returnYELLOW;

                     }

              },

              YELLOW(5){

                     public TrafficLamp nextLamp()   {

                            returnRED;

                     }

              };

             

              privateinttime;

              //自带时间的构造方法

              private TrafficLamp(int trime)    

              {

                     this.time =time;

              }

              //返回下一个灯的抽象方法

              publicabstract TrafficLamp nextLamp();

       }

 

****************************************************************Java5——注解************************************************************

33.了解和入门注解的应用

Java.lang包中:注释类型、

注释类型 SuppressWarnings 指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告

注释类型 Deprecated     @Deprecated注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择

注释类型 Override     表示一个方法声明打算重写超类中的另一个方法声明

 

总结:注解相当于一种标记,加了注解就等于打上了某种标记,没加,则等于没有某种标记。

      以后,javac编译器、开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记;看你有什么标记,就去干相应的事。标记可以加在包、类、字段、方法、方法参数及局部变量上。

 

//加了注解,编译时不提示警告(doc命令用javac编译)

       @SuppressWarnings("deprecation")  

       publicstaticvoid main(String[] args)

       {

              System.runFinalizersOnExit(true);   //过时的方法

       }

 

        //说明这个方法过时了,调用此方法时,会画上横线

       @Deprecated   

       publicstaticvoidsayHello()

       {

              System.out.println("hi,传智播客");

       }

      

       //加了此注释,说明下面方法是覆盖Object的方法,

       //如果方法参数、方法名或返回类型写错会报错

       @Override

       public String toString()

       {

              return"复写Object中的toString";

       }

 

34.注解的定义与反射调用

注解的应用结构图:

  注解类             应用了“注解类”的类        对应用了注解类的类

                      @A                       进行反射操作的类

  @interface A <------------class Bß-------------------------class C {  

  {}                   {}                       B.class.isAnnotionPressent(A.class);

                                                A a = B.class.getAannotion(A.class);}

 

类加载器将类(class)文件加载进内存时,会考虑是否把里面的注释也加载进来,这时他会看哪些注释对象所对应的注释接口上标有元注释@Retention(RetentionPolicy.RUNTIME)

加了这个元注释的注释对象才能被加载到内存中,才能通过反射获取到注释接口的class对象。

 

自定义注解及其应用:

步骤:

1、定义一个最简单的注解:public @interface MyAnnotation{}

2、把它加在某个类上:@ MyAnnotation   public class AnnotationTest{}

3、用反射进行测试AnnotationTest的定义上是否有@ MyAnnotation

根据反射测试的问题,引出@Retention元注解的讲解:

java.lang.annotation
注释类型 Retention 指示注释类型的注释要保留多久。如果注释类型声明中不存在

                   Retention注释,则保留策略默认为RetentionPolicy.CLASS

三种取值:RetentionPolicy .SOURCE \ CLASS  \  RUNTIME(枚举)

分别对应:java源文件--------àclass文件----------à内存中的字节码(Class

思考:@Override@SuppressWarnings@ Deprecated这三个注解的属性值分别是什么?

@Override @Retention(value=SOURCE)

让程序员看覆盖方法有没有写错,错误编译时就知道,不用存入编译后class文件。

@SuppressWarnings  @Retention(value=SOURCE)

       编译时是否取消显示的警告,只在编译时有用,编译后不用了就不要存进class文件。

@ Deprecated      @Retention(value=RUNTIME)

      当一个方法被标记上警告,在别的类中调用此方法时会发出警告。首先要通过这个方法所属的类,看看这个方法是否存在,有没有打上注释标记,是检查调到内存中检查二进制。

 

@ Target  元注解的讲解:

java.lang.annotation
注释类型 Target 指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在

                Target元注释,则声明的类型可以用在任一程序元素上。

     属性value有几种取值,是枚举ElementType

 

元注解以及枚举属性值不用记,只要会看jdk提供的那几个基本注解的API帮助文档的定义或其源代码,按图索骥即可查到,或者直接看java.lang.annotation包下面的类。

 

// 用于说明此注解保留到程序的那个周期,这里是运行期在,字节码

@Retention(RetentionPolicy.RUNTIME)

//用于标明此注释可以加在程序的哪些成分上(注解, 类、接口、枚举)

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

public@interfaceItcastAnnotation

{

 

}

 

35.为注解增加各种属性

1、什么是注解的属性?

     一个注解相当于一个胸牌,如果为胸前贴上了胸牌,就是传智播客的学生,否则就不是。如果还想区分出是传智播客哪个班的学生,这时可以为胸牌再增加一个属性来进行区分。加了属性的标记效果为:@MyAnnotation(color=”red”)

2、定义基本类型的属性和应用属性:

      在注解中增加String color();

      @MyAnnotation(color=”red”)

3、用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法

      MyAnnotation a

 = (MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);

      System.out.println(a.color());

      可以认为上面这个@MyAnnotationMyAnnotation类的一个实例对象。

4、为属性指定缺省值:

      String color() default “yellow”;

5value属性:

      String value() default “Zxx”;

      如果注解中还有一个名称为value的属性,且你只想设置value的属性(其他属性都在用默认值或者)

6、数组类型的属性:

     Int[] arrayAttr() default {1,2,3};

     @MyAnnotation(arrayAttr{2,3,4})

     如果数组属性只有一个元素,这时属性值部分可以省略大括号。

通过反射获取数组属性的值System.out.println(arrayAttr()[0]);

7、枚举类型的属性:

     EnumTest.TrafficLamp lamp();

     @MyAnnotation(lamp = EnumTest.TrafficLamp.GREEN)

8、注解类型的属性:

     MetaAnnotation annotationAttr() default  @ MetaAnnotation(“xxxx”);

     @MyAnnotation(annotationAttr=@ MetaAnnotation(“yyy”))

     可以认为上面两个@ MetaAnnotationMetaAnnotation类的一个实例对象,代码如下: //通过反射获取注解MyAnnotation的对象,然后获取此对象的注释属性,此属性值也是注解

      MetaAnnotation ma = myAnnotation.annotationAttr();

     //获取注解属性的value属性值

      System.out.println(ma.value());

注意:注解的属性类型可以是 8中基本类型,数组,类(Class对象),枚举,注解。

   注解的详细语法可以通过看java语言规范了解。即看javalanguage specification

// 用于说明此注解保留到程序的那个周期,这里是运行期在,字节码

@Retention(RetentionPolicy.RUNTIME)

//用于标明此注释可以加在程序的哪些成分上(注解, 类、接口、枚举)

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

public@interfaceItcastAnnotation

{

       //为注释添加属性

        //加了缺省,在使用该注释时可以不为此属性设置值

       String color() default"blue"

        //如果在使用注释时只设置value的值,value可以省略不写,直接写上值

       String value();    

       int [] arrayAttr()default {3,4,5};

       EnumTest.TrafficLamp lamp()default EnumTest.TrafficLamp.RED;

       //注释属性

       MetaAnnotation annotationAttr()default@MetaAnnotation("hlm");

       Class clazz() defaultMetaAnnotation.class;    //类属性

}  

将自定义注解加在类上,然后通过反射获取注释对象,并获取其属性值。

@ItcastAnnotation(annotationAttr=@MetaAnnotation("xm"),

       color="red",value="haha",arrayAttr={1,2},lamp=EnumTest.TrafficLamp.GREEN)  

publicclass AnnotationTest

{

       //加了注解,编译时不提示警告(doc命令用javac编译)

       @SuppressWarnings("deprecation")  

       publicstaticvoid main(String[] args)

       {

              System.runFinalizersOnExit(true);   //过时的方法

              //通过一个类的字节码对象检查这个类中是否存在一个注释类的对象

              if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class))

              {

                     //获取此注释的对象

                     ItcastAnnotation annotation =

                     (ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);

                     System.out.println(annotation);

//@cn.itcast.day2.ItcastAnnotation(color=red, value=haha)

                     //打印此注解的属性值

                     System.out.println(annotation.color());  //haha

                     System.out.println(annotation.value());  //haha

                     System.out.println(annotation.arrayAttr());  //[I@c0f1ec

                     System.out.println(annotation.arrayAttr()[0]);  //1

                     System.out.println(annotation.lamp().nextLamp().name());  //YELLOW

                     System.out.println(annotation.annotationAttr().value()); //xm

              }

       }