jdk1.5 新特性 4静可拆枚泛注

 jdk1.5 新特性         4静可拆枚泛注
 
增强for循环  
1、格式:  
        for(数据类型变量名 :被遍历的集合(collection)或者数组)
            {执行语句}  
 
2、说明  
        a、对集合进行遍历。只能获取集合元素。但是不能对集合进行操作。可以看作是迭代器的简写形式。
        b、迭代器除了遍历,还可以进行remove集合中元素的动作。如果使用ListIterator,
                还可以在遍历过程中对集合进行增删改查的操作。  
 
3、传统for和高级for的区别:  
       高级for有一个局限性。必须有被遍历的目标(集合或数组)。  
       传统for遍历数组时有索引。  
 
建议在遍历数组的时候,还是希望使用传统for。因为传统for可以定义角标。  
 
注意:变量类型前可加修饰符,如final(可被局部内部类访问到)。  
示例:   

class For    
{    
    public static void main(String[] args){    
        //定义一个ArrayList集合    
        ArrayList<String> al = new ArrayList<String>();    
        al.add("abc1");    
        al.add("abc2");    
        al.add("abc3");    
    
        for(String s : al){    
            System.out.println(s);//用高级for遍历集合    
        }    
    
        //传统for与高级for遍历数组    
        int[] arr = {3,5,1};    
    
        for(int x=0; x<arr.length; x++){    
            System.out.println(arr[x]);    
        }    
        for(int i : arr){    
            System.out.println("i:"+i);    
        }    
    
        //定义一个HashMap集合    
        HashMap<Integer,String> hm = new HashMap<Integer,String>();    
    
        hm.put(1,"a");    
        hm.put(2,"b");    
        hm.put(3,"c");    
    
        //keySet取出方式的高级for遍历    
        Set<Integer> keySet = hm.keySet();    
        for(Integer i : keySet){    
            System.out.println(i+"::"+hm.get(i));    
        }    
    
        //entrySet取出方式的高级for遍历    
        for(Map.Entry<Integer,String> me : hm.entrySet()){    
            System.out.println(me.getKey()+"------"+me.getValue());    
        }    
     }    
}    

可变参数(...):

      1.用到函数的参数上,当要操作的同一个类型元素个数不确定的时候,可以用这个方式,这个参数可以接受任意
个数的同一类型的数据。

     
2.和以前接收数组不一样的是:

  以前定义数组类型,需要先创建一个数组对象,再将这个数组对象作为参数传递给函数。现在,直接将数组中的元素作为参数传递即可。底层其实是将这些元素进行数组的封装,而这个封装动作,是在底层完成的,被隐藏了。所以简化了用户的书写,少了调用者定义数组的动作。
 

     3.如果在参数列表中使用了可变参数,可变参数必须定义在参数列表结尾(也就是必须是最后一个参数,否则编译会失败。)。
 

     4.如果要获取多个int数的和呢?可以使用将多个int数封装到数组中,直接对数组求和即可。

class  ParamMethodDemo{    

    public static void main(String[] args){    

        show("haha",2,3,4,5,6);    

    }    

    public static void show(String str,int... arr){  //   ...   就表示可变参数

        System.out.println(arr.length);    

    }    

}   

静态导入 
 

1、写法:

        import static java.util.Arrays.*;   //导入的是Arrays这个类中的所以静态成员。
 

        import static java.lang.System.*    //导入了Ssytem类中所有静态成员。
 

        没加static导入的是类,加上static导入的全是某一个类中所有的静态成员。这样写在调用该类的静态方法时可以不用再写类名。
             如:   Arrays.sort(数组);
                       就可以直接写sort(数组);

2、注意:

         当导入的两个类中有同名成员时,需要在成员前加上相应的类名。

        当类名重名时,需要指定具体的包名。当方法重名时,指定具体所属的对象或者类。

示例:

import java.util.*;    

import static java.util.Arrays.*;        //导入的是Arrays这个类中的所以静态成员。

import static java.lang.System.*;    //导入了Ssytem类中所有静态成员。

    

class  StaticImport {

    public static void main(String[] args){    
 

        out.println("haha");  //打印输出时就可以直接省略书写System.    

        int[] arr = {3,1,5};    

    

        sort(arr);//使用Arrays工具类的方法sort时就可以省略书写Array.    

    

        int index = binarySearch(arr,1);//半分查找也是一样可以省略    

        out.println("Index="+index);    

    

        //当没有指定继承时,所以类默认继承了Object,    

       //因为toString方法都具备,所以为了区分,必须写上具体调用者    

       out.println(Arrays.toString(arr));    

    }    

}    


---------------------------------------------------

枚举:关键字 enum

    1. 
 枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,
    2. 
   枚举只有一个成员时,就可以作为一种单例的实现方式
    3.
   枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
    4. 
 枚举元素必须位于枚举体中的最开始部分,枚举元素之间用逗号隔开,枚举元素列表的后要有分号与其他成员分隔。如果把枚举中的成员方法或  变量 等放在枚举元素的前面,编译器报告错误。
    5. 
带构造方法的枚举
      
构造方法必须定义成私有的
      
枚举元素MONMON()的效果一样,都是调用默认的构造方法。
    6. 
 带方法的枚举
     
定义枚举TrafficLamp
     
实现普通的next方法
     
实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的
    方式进行定义。
   7.
增加表示时间的构造方法
  
采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。

public static void main(String[] args) {

           weekDay WE=weekDay.FRI;

           System.out.println(WE);

           System.out.println(WE.name());                 //自己的名字

           System.out.println(WE.ordinal());               //排行位置

           System.out.println(WE.getClass());             //得到自己的类名

           System.out.println(weekDay.valueOf("SUN"));   //输出SUN

           System.out.println(weekDay.values().length);

//得到weekDay的数组长度

}

public enum weekDay{  //枚举示例

           SUN,MON,TUE,WED,THI,FRI,SAT

}


自动拆装箱

    java中数据类型分为两种 : 基本数据类型   引用数据类型(对象)
 

在 java程序中所有的数据都需要当做对象来处理,针对8种基本数据类型提供了包装类,如下:

     byte            Byte                八位二进制
     
short         Short                十六个 二进制

     int           Integer                三十二个 二进制
     
long       Long                     六十四 二进制

     char --> Character

     double --> Double

     float --> Float

     boolean --> Boolean
 
int 变为Integer  char 变为Character 其他首字母大写 

jdk5以前基本数据类型和包装类之间需要互转:

基本---引用   Integer x = new Integer(x);

引用---基本   int num = x.intValue();

1)、Integer x = 1; x = x +1;  经历了什么过程?装箱 à 拆箱 à 装箱;

2)、为了优化,虚拟机为包装类提供了缓冲池,Integer池的大小 -128~127 一个字节的大小;

3)、String池:Java为了优化字符串操作 提供了一个缓冲池;


泛型:jdk1.5版本以后出现的一个安全机制。

    表现格式:< >
 

    好处:

        1:将运行时期的问题ClassCastException问题转换成了编译失败,体现在编译时期,程序员就可以解决问题。

        2:避免了强制转换的麻烦。
 

    只要带有<>的类或者接口,都属于带有类型参数的类或者接口,在使用这些类或者接口时,必须给<>中传递一个具体的引用数据类型。
 

    泛型技术:其实应用在编译时期,是给编译器使用的技术,到了运行时期,泛型就不存在了为什么? 

        泛型的擦除:也就是说,编辑器检查了泛型的类型正确后,在生成的类文件中是没有泛型的。
 

   在运行时,如何知道获取的元素类型而不用强转呢?
 

       泛型的补偿:因为存储的时候,类型已经确定了是同一个类型的元素,所以在运行时,只要获取到该元素的类型,在内部进行一次转换即可,所以使用者不用再做转换动作了。
 

   什么时候用泛型类呢?
 

      当类中的操作的引用数据类型不确定的时候,以前用的Object来进行扩展的,现在可以用泛型来表示。这样可以避免强转的麻烦,而且将运行问题转移到的编译时期。


泛型在程序定义上的体现:

//泛型类:将泛型定义在类上。

class Tool<Q> {

    private Q obj;

    public void setObject(Q obj) {

    this.obj = obj;

    }

    public Q getObject() {

        return obj;

    }

}

//当方法操作的引用数据类型不确定的时候,可以将泛型定义在方法上。

public <W> void method(W w) {

    System.out.println("method:"+w);

}

//静态方法上的泛型:静态方法无法访问类上定义的泛型。如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上。

public static <Q> void function(Q t){

    System.out.println("function:"+t);

}

//泛型接口.

interface Inter<T> {

    void show(T t);

}

class InterImpl<R> implements  Inter<R> {

    public void show(R r) {

        System.out.println("show:"+r);

    }

}


泛型中的通配符:
    可以解决当具体类型不确定的时候,这个通配符就是 ?  ;当操作类型时,不需要使用类型的具体功能时,只使用Object类中的功能。那么可以用 ? 通配符来表未知类型。
 

泛型限定:

    上限:?extends E:可以接收E类型或者E的子类型对象。

    下限:?super E:可以接收E类型或者E的父类型对象。
 

    上限什么时候用:
        往集合中添加元素时,既可以添加E类型对象,又可以添加E的子类型对象。为什么?因为取的时候,E类型既可以接收E类对象,又可以接收E的子类型对象。

    下限什么时候用:
         当从集合中获取元素进行操作的时候,可以用当前元素的类型接收,也可以用当前元素的父类型接收。
 

泛型的细节:

    1)、泛型到底代表什么类型取决于调用者传入的类型,如果没传,默认是Object类型;

    2)、使用带泛型的类创建对象时,等式两边指定的泛型必须一致;

        原因:编译器检查对象调用方法时只看变量,然而程序运行期间调用方法时就要考虑对象具体类型了;

    3)、等式两边可以在任意一边使用泛型,在另一边不使用(考虑向后兼容);
 

ArrayList<String> al =new ArrayList<Object>();  //错

//要保证左右两边的泛型具体类型一致就可以了,这样不容易出错。

ArrayList<? extends Object> al = new ArrayList<String>();

   al.add("aa");  //错

//因为集合具体对象中既可存储String,也可以存储Object的其他子类,所以添加具体的类型对象不合适,类型检查会出现安全问题。 ?extends  Object 代表Object的子类型不确定,怎么能添加具体类型的对象呢?

public static void  method(ArrayList<? extends Object> al) {

    al.add("abc");  //错

    //只能对al集合中的元素调用Object类中的方法,具体子类型的方法都不能用,因为子类型不确定。

}


注解  jdk1.5以后的新特性

System.runFinalizersOnExit(true); 方法过时了  删除线  压缩警告

@Deprecated  //标记此方法过时

      public static void sayHello(){

           System.out.println("hello world");

}

@Override   //覆盖 

//子类覆盖父类的方法   加上次标记 如果不是覆盖会有提示

总结:

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

java.lang包,可看到JDK中提供的最基本的annotation

注解的应用结构图


元注解  元信息   元数据

@Retention元注解的讲解,其三种取值

RetetionPolicy.SOURCE            java源文件、

RetetionPolicy.CLASS               class文件

RetetionPolicy.RUNTIME          内存中的字节码。

@Override                      编译器  java源文件

@SuppressWarnings      编译器 java源文件 

@Deprecated                内存中的字节码。

    Target的默认值为任何元素,设置Target等于ElementType.METHOD,原来加在类上的注解就报错了,改为用数组方式设置{ElementType.METHOD,ElementType.TYPE}就可以了

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

为注解增加属性

l     为属性指定缺省值:

Ø     String color() default "yellow";

l     数组类型的属性

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

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

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

l     枚举类型的属性

Ø     EnumTest.TrafficLamplamp() ;

Ø     @MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN)

l     注解类型的属性:

Ø     MetaAnnotation      annotationAttr() default @MetaAnnotation("xxxx");

Ø     @MyAnnotation(annotationAttr=@MetaAnnotation(yyy) )

Ø     可以认为上面这个@MyAnnotationMyAnnotaion类的一个实例对象,同样的道理,可以认为上面这个@MetaAnnotationMetaAnnotation类的一个实例对象,调用代码如下:

                                                                        MetaAnnotation  ma =  MyAnnotation.annotationAttr();

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

l     注解的详细语法可以通过看java语言规范了解,即看javalanguagespecification