·jdk1.5(Tiger)

1、自动装箱与拆箱

每当需要一种类型的对象时,这种基本类型就自动地封装到与它相同类型的包装中;自动装箱,只需将该值赋给一个类型包装器引用,java会自动创建一个对象。

每当需要一个值时,被装箱对象中的值就被自动地提取出来,没必要再去调用intValue()和doubleValue()方法。自动拆箱,只需将该对象值赋给一个基本类型即可。

java提供的基本包装类型有:Double,Float,Long,Integer,Short,Character和Boolean

举个例子说明一下:


Integer a=3;//这是自动装箱

其实编译器调用的是static Integer valueOf(int i)这个方法,valueOf(int i)返回一个表示指定int值的Integer对象,那么就变成这样: 


Integer a=3;   =>    Integer a=Integer.valueOf(3);

下面是自动拆箱:


int i = new Integer(2);//这是拆箱

编译器内部会调用int intValue()返回该Integer对象的int值



需要明确的是:自动装箱和拆箱是由编译器来完成的,编译器会在编译期根据语法决定是否进行装箱和拆箱动作。

2、枚举

就是把集合里的对象元素一个一个提取出来。

枚举类型使代码更具可读性,理解清晰,易于维护。

枚举类型是强类型的,从而保证了系统安全性。而以类的静态字段实现的类似替代模型,不具有枚举的简单性和类型安全性。
简单的用法:JavaEnum简单的用法一般用于代表一组常用常量,可用来代表一类相同类型的常量值。
复杂用法:Java为枚举类型提供了一些内置的方法,同时枚举常量还可以有自己的方法。可以很方便的遍历枚举对象。

下面是我从网上找的一个例子,非常典型,跟大家共享一下:

public class TestEnum {
    /*最普通的枚举*/
    public enum ColorSelect {
        red, green, yellow, blue;    
    }

    /* 枚举也可以象一般的类一样添加方法和属性,你可以为它添加静态和非静态的属性或方法,这一切都象你在一般的类中做的那样. */
    public enum Season {
        // 枚举列表必须写在最前面,否则编译出错
        winter, spring, summer, fall;

        private final static String location = "Phoenix";        

        public static Season getBest() {
            if (location.equals("Phoenix"))
                return winter;
            else
                return summer;
        }
    }
    /*还可以有构造方法*/
    public enum Temp {
        /*通过括号赋值,而且必须有带参构造器和一属性跟方法,否则编译出错
         * 赋值必须是都赋值或都不赋值,不能一部分赋值一部分不赋值
         * 如果不赋值则不能写构造器,赋值编译也出错*/
        absoluteZero(-459), freezing(32),boiling(212), paperBurns(451);
        
        private final int value;
        public int getValue() {
            return value;
        }
        //构造器默认也只能是private, 从而保证构造函数只能在内部使用
        Temp(int value) {
            this.value = value;
        }
    }

    public static void main(String[] args) {
        /*
         * 枚举类型是一种类型,用于定义变量,以限制变量的赋值 赋值时通过"枚举名.值"来取得相关枚举中的值
         */
        ColorSelect m = ColorSelect.blue;
        switch (m) {
        /*注意:枚举重写了ToString(),说以枚举变量的值是不带前缀的
          *所以为blue而非ColorSelect.blue
          */
   case red:
            System.out.println("color is red");
            break;
        case green:
            System.out.println("color is green");
            break;
        case yellow:
            System.out.println("color is yellow");
            break;
        case blue:
            System.out.println("color is blue");
            break;
        }
        System.out.println("遍历ColorSelect中的值");
        /*通过values()获得枚举值的数组*/
        for (ColorSelect c : ColorSelect.values()) {
            System.out.println(c);
        }   
   System.out.println("枚举ColorSelect中的值有:"+ColorSelect.values().length+"个");
   /*ordinal()返回枚举值在枚举中的索引位置,从0开始*/
  System.out.println(ColorSelect.red.ordinal());//0
  System.out.println(ColorSelect.green.ordinal());//1
  System.out.println(ColorSelect.yellow.ordinal());//2
  System.out.println(ColorSelect.blue.ordinal());//3

  /*枚举默认实现了java.lang.Comparable接口*/ 
  System.out.println(ColorSelect.red.compareTo(ColorSelect.green));

  System.out.println(Season.getBest());
        
        for(Temp t:Temp.values()){
            /*通过getValue()取得相关枚举的值*/
            System.out.println(t+"的值是"+t.getValue());
        }

    }
}

3、静态导入

要使用静态成员(方法和变量)必须给出提供这个静态成员的类。

使用静态导入可以使被导入类的静态变量和静态方法在当前类直接可见。使用这些静态成员无需再给出他们的类名。

看下面一个实例:

先在包中定义一个Common类


package com.example.learnjava;

public class Common
{

    public static final int AGE = 10;
    public static void output()
    {
        System.out.println("Hello World!");
    }
}

在另外一个包中使用时,如果不用静态导入,是这样用的:


package com.example.learnjava2;

import com.example.learnjava.Common;

public class StaticImportTest
{
    public static void main(String[] args)
    {
        int a = Common.AGE;
        System.out.println(a);
        
        Common.output();
    }

}

使用静态导入:

首先应该明确静态导入的语法是:

import static 包名.类名.静态成员变量

import static 包名.类名.静态成员函数

package com.example.learnjava2;

import static com.example.learnjava.Common.AGE;
import static com.example.learnjava.Common.output;

public class StaticImportTest
{
    public static void main(String[] args)
    {
        int a = AGE;
        System.out.println(a);
        
        output();
    }

}



但是使用静态导入也是存在一定的缺点:过度地使用静态导入在一定程度上降低了代码的可读性。

4、可变参数

适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。注意:可变参数必须位于最后一项。当可变参数个数多余一个时,必将有一个不是最后一项,所以只支持有一个可变参数。因为参数个数不定,所以当其后边还有相同类型参数时,java无法区分传入的参数属于前一个可变参数还是后边的参数,所以只能让可变参数位于最后一项。

可变参数的特点:
(1)、只能出现在参数列表的最后; 
(2)、...位于变量类型和变量名之间,前后有无空格都可以;
(3)、调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中一数组的形式访问可变参数。

public class Varable {
 public static void main(String [] args){
  System.out.println(add(2,3));
  System.out.println(add(2,3,5));
 }
 public static int add(int x,int ...args){
  int sum=x;
  for(int i=0;i<args.length;i++){
   sum+=args[i];
  }
  return sum;
 }
}

5、内省

为了让程序员们更好的操作Java对象的属性,SUN公司开发了一套API,被业界内称为:内省;内省的出现有利于了对类对象属性的操作,减少了代码的数量。

内省访问JavaBean有两种方法:
一、通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。
二、通过PropertyDescriptor来操作Bean对象

6、泛型

泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

在使用泛型类时,虽然传入了不同的泛型实参,但并没有真正意义上生成不同的类型,传入不同泛型实参的泛型类在内存上只有一个,即还是原来的最基本的类型(本实例中为Box),当然,在逻辑上我们可以理解成多个不同的泛型类型。究其原因,在于Java中的泛型这一概念提出的目的,导致其只是作用于代码编译阶段,在编译过程中,对于正确检验泛型结果后,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。泛型信息不会进入到运行时阶段。
对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。

7、遍历循环(foreach)

在遍历数组、集合方面,foreach为开发人员提供了极大的方便。 
foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本。 
foreach并不是一个关键字,习惯上将这种特殊的for语句格式称之为“foreach”语句。从英文字面意思理解foreach也就是“for 每一个”的意思。实际上也就是这个意思。 
foreach的语句格式: 
for(元素类型t 元素变量x : 遍历对象obj){ 
     引用了x的java语句; 

8、注解

1. 注解的原理与使用
阅读了《Java编程思想》讲注解的一章,整理笔记如下:
1.1 定义注解
使用元注解定义注解,元注解有四种:
    @Target(ElementType.[type])
    [type]={METHOD, FIELD, TYPE(类、接口、枚举声明), CONSTRUCTOR, LOCAL_VARIABLE, PARAMETER}
    @Retention(RetentionPolicy.[policy])
    [policy]={SOURCE, CLASS, RUNTIME(反射机制可读取)}
    @Documented 表示将此注解包含到Javadoc中
    @Inherited 表示允许子类继承父类的注解
例子:

//:annotations/UserCase.java
import java.lang.annotation.*;


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCases {
    public int value() default 0;
    public int id() default 0;
    public String description() default "no description";
}

1.2使用注解


@UserCase(id=10, description="my desccription")


注意:


注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定


非基本类型的注解元素的值不可为null


注解快捷方式: 如果注解元素声明为value(),则在使用注解时如果只声明value,可以只写值,不必写名值对。例如可写为@UseCase(10)


1.3编写注解处理器


通过反射机制获取注解元素的值: Method.getAnnotation(), Field.getDeclaredAnnotations()等方法


1.4注解的使用场景


统计系统用例实现情况    


由JavaBean自动生成数据库建表SQL


1.5 JDK提供的注解工具apt


1.6 基于注解的单元测试     


2. Java提供的标准注解分析。


@Override
/*
 * @(#)Override.java    1.5 04/02/09
 *
 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package java.lang;

import java.lang.annotation.*;

/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a superclass.  If a method is annotated with
 * this annotation type but does not override a superclass method,
 * compilers are required to generate an error message.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

注解@Override的代码非常简单,可用于注解类的方法,并在Source级别可用。  


 @Deprecated级别为Runtime    


 @SuppressWarnings级别为source,经常的使用方式为@SuppressWarnings("unchecked")


3. Spring与Junit的常用注解分析。


 @Test   


4. 如何合理的设计和使用注解


使用注解标记字段和方法,可通过反射的手段截取注解及其标记的字段和方法的元数据,并根据需求对元数据进行处理。


它赋予了字段和方法额外的意义,提供了一种统一处理字段和方法的优雅的方式。


注解更多的意义是提供了一种设计模式,在本质上它没有增强Java的能力,使用注解实现的功能都可以以非注解的方式实现,只是代码可能不是很好看而已。