JDK 1.5 新特性

静态导入(static import)

静态导入的形式:import static 包路径.类;

与普通的导入方式相比仅多了个static,还有就是ClassName(类名)后面多了个 .星号 ,意思是导入这个类里的所有静态方法。当然也可以只导入某个静态方法,只要把.星号 换成静态方法名就行了。

静态导入之后在类中就可以直接用方法名调用静态方法,而不必用 类名.方法名 的方式调用,同样静态的变量也可以直接使用。

注意:这样的写法虽然可以简化代码的书写,但是代码的可读性下降。

自动装箱与拆箱(Autoboxing and unboxing)

For-Each循环

For-Each语句语法:for ( variable : collection ) statement

这是一种循环结构,可以用来依次处理数组中的每个元素而不必为指定下标值而分心。

我们需要定义一个变量(variable)用于暂存集合或数组中的每个元素,并执行相应的语句(statement),collection这个集合表达式必须是一个数组/集合或者是一个实现了Iterable接口的类对象。

  • 优点:与传统的循环相比语句更加简洁、更不易出错(不必为下标的起始位置和终止值而操心)。
  • 缺点:for-each结构会遍历集合中的所有元素,如果希望遍历部分元素或者在循环内部需要使用下标值,就力不从心了,传统的循环就显示出优势了。
// 遍历数组
int arr[] = { 253 };
for (int x : arr) {
    System.out.print(x + " ");
}
// 遍历二维数组
int arr[][] = { { 12 }, { 34 } };
for (int[] x : arr) {
    for (int e : x) {
        System.out.print(e + " ");
    }
    System.out.println();// 换行
}
// 遍历集合
List<String> list = new ArrayList<String>();
list.add("1");
list.add("2");
list.add("5");
for (String x : list) {
    System.out.println(x + " ");
}
// 集合转换为集合并遍历
Object[] obj = list.toArray();
for (Object x : obj) {
    System.out.print(x.toString() + " ");
}

枚举(enum)

枚举类型的定义:enum <枚举类型名> {<枚举表>};

可变长度参数(Varargs)

在编写功能相同,但是参数数量不同的函数的时候,作为一名程序员,我是有想偷懒的想法,可变长度参数便是为此提供的一种简化的方式。

我们只需要编写内部的方法即可,函数可以接收数量未知的参数。

可变长度参数定义格式:Object...

此处的Object可以是任何类型只不过在后面添加三个点就可以了,表明可以接收任意数量的该对象,上面的Object...参数类型与Object[]完全一样。

//计算若干个数值的最大值
public static double max(double... values){
    double largest = Double.MIN_VALUE;
    for(double v : values){
        if (v>largest) {
            largest=v;
        }
    }
    return largest;
}

注意:当多个参数时,可变参数必须是参数列表的最后一个参数

避免模糊重载

// Varargs, overloading, and ambiguity. 
// 
// This program contains an error and will 
// not compile! 
class VarArgs4 { 

  static void vaTest(int ... v) { 
    System.out.print("vaTest(Integer ...): " + 
                     "Number of args: " + v.length + 
                     " Contents: "); 

    for(int x : v) 
      System.out.print(x + " ");  
    System.out.println(); 
  } 

  static void vaTest(boolean ... v) { 
    System.out.print("vaTest(boolean ...) " + 
                     "Number of args: " + v.length + 
                     " Contents: "); 

    for(boolean x : v) 
      System.out.print(x + " ");  
    System.out.println(); 
  } 


  public static void main(String args[]){ 
    vaTest(1, 2, 3);  // OK 
    vaTest(true, false, false); // OK 

    vaTest(); // Error: Ambiguous! 
  } 
}

上面代码的出错原因是在参数为空的情况下,两个重载的vaTes方法都可以匹配。

另一种类似的模糊情况是:

static void vaTest(int... v);
static void vaTest(int n,int... v)
// 调用
vaTest(1);

内省(Introspector)

内省是Java对Bean类属性、事件的一种缺省处理方法。例如类A中有属性name,那我们可以通过getNamesetName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。

Java中提供了一套API用来访问某个属性的getter /setter方法,通过这些API可以使你不需要了解这个规则(但你最好还是要搞清楚),这些API存放于包java.beans中。

一般的做法是通过类Introspector来获取某个对象的BeanInfo信息,然后通过BeanInfo来获取属性的描述器 (PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后我们就可以通过反射机制来调用这些方法。

内省与反射的区别:

  • 反射可以操作各种类的属性,而内省只是通过反射来操作JavaBean的属性
  • 内省设置属性值肯定会调用setter方法,反射可以不用
// JavaBean类
public class User {
    private String name;
    private int age;
    private Date birthday;
    // 省略getName/setName方法
    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + ", birthday=" + birthday + "]";
    }
}

通过反射机制操作name属性:

User user = new User();
Field f = user.getClass().getDeclaredField("name");
f.setAccessible(true);
f.set(user, "mld");// 设置属性值
String name = (String) f.get(user);// 获取属性值

通过内省操作name属性:

User user = new User();
// 操作单个属性
PropertyDescriptor pd = new PropertyDescriptor("name", User.class);
Method w = pd.getWriteMethod();// 获取属性的setter方法
w.invoke(user, "winclpt");
Method r = pd.getReadMethod();// 获取属性的getter方法
r.invoke(user, null);

// 操作所有属性
BeanInfo bi = Introspector.getBeanInfo(User.class);
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (PropertyDescriptor p : pds) {

}

其它示例:

/**
 * @Description: JavaBean属性操作工具类
 */
public class MyBeanUtils {
    /**
     * @Description: 根据指定的属性名称获取属性值
     * @Parameters: @param propertyName 属性名称
     * @Parameters: @param bean bean实例对象
     * @Return: Object 返回getter方法的返回值,即属性值
     */
    public static Object getPropertyValue(String propertyName, Object bean) {
        Object propertyValue = null;
        try {
            PropertyDescriptor pd = new PropertyDescriptor(propertyName, bean.getClass());
            Method method = pd.getReadMethod();
            propertyValue = method.invoke(bean);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return propertyValue;
    }

    /**
     * @Description: 设置/修改属性的内容
     * @Parameters: @param bean Bean实例对象
     * @Parameters: @param name 属性名
     * @Parameters: @param value 修改内容
     */
    public static void setProperty(Object bean, String name, Object value) {
        try {
            PropertyDescriptor pd = new PropertyDescriptor(name, bean.getClass());
            Method method = pd.getWriteMethod();
            method.invoke(bean, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @Description: 
     *      将Map中的内容封装到 JavaBean 说明:
     *               Map中的key必须与JavaBean中的属性名称相同
     *               Map中的value传递给JavaBean对应的属性
     * @Parameters: @param bean
     * @Parameters: @param map
     */
    public static Object populate(Object bean, Map<String, Object> map) {
        if (map != null && map.size() > 0) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String propertyName = entry.getKey();
                Object propertyValue = entry.getValue();
                try {
                    PropertyDescriptor pd = new PropertyDescriptor(propertyName, bean.getClass());
                    Method method = pd.getWriteMethod();
                    method.invoke(bean, propertyValue);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return bean;
    }
}
/**
 * @Description: JavaBean类定义
 */
public class User {
    String name;
    int age;
    boolean gender;
    Date birthday;
    String address;
    // 省略getName/setName方法
    @Override
    public String toString() {
    return "User [name=" + name + ", age=" + age + ",gender=" + gender + ", birthday=" + birthday + ",address=" + address + "]";
    }
}
/**
 * @Description: JavaBean-API:内省机制测试类
 */
public class IntrospectorTest {

    private User user;

    @Before
    public void init() {
        user = new User();
        user.setName("张三");
        user.setAge(21);
        user.setGender(true);
        user.setBirthday(new Date());
        user.setAddress("北京丰台");
    }

    /**
     * @Description: 获取User-Bean的所有属性信息
     * @Parameters: @throws Exception
     */
    @Test
    public void getBeanPropertyInfo() throws Exception {
        // 获取User-BeanInfo对象:beanInfo是对一个Bean的描述,可以通过它取得Bean内部的信息
        /**
         *  获取User-BeanInfo对象
         *  1、Introspector类是一个工具类,提供了一系列取得BeanInfo的方法;
         *  2、BeanInfo接口对一个JavaBean的描述,可以通过它取得Bean内部的信息; 
         *  3、PropertyDescriptor属性描述器类对一个Bean属性的描述,它提供了一系列对Bean属性进行操作的方法
         */
        BeanInfo userBeanInfo = Introspector.getBeanInfo(User.class);
        PropertyDescriptor[] pds = userBeanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            Method method = pd.getReadMethod();
            String methodName = method.getName();
            Object result = method.invoke(user);
            System.out.println(methodName + " -> " + result);
        }
    }

    /**
     * @Description: 获取指定属性名称的属性描述器,并对属性进行操作
     */
    @Test
    public void getBeanPropertyByName() throws Exception {
        // 获取name属性的属性描述器
        PropertyDescriptor pd = new PropertyDescriptor("name", user.getClass());
        // 得到name属性的getter方法
        Method readMethod = pd.getReadMethod();
        // 执行getter方法,获取返回值,即name属性的值
        String result = (String) readMethod.invoke(user);
        System.out.println("user.name" + " -> " + result);
        // 得到name属性的setter方法
        Method writeMethod = pd.getWriteMethod();
        // 执行setter方法,修改name属性的值
        writeMethod.invoke(user, "李四");
        System.out.println("user.name" + " -> " + user.getName());
    }

}
/**
 * @Description: JavaBean属性操作工具测试类
 */
public class MyBeanUtilsTest {

    private User user;

    @Before
    public void init() {
        user = new User();
        user.setName("张三");
        user.setAge(21);
        user.setGender(true);
        user.setBirthday(new Date());
        user.setAddress("北京丰台");
    }

    @Test
    public void testSetPropertyValue() {
        // 设置String类型数据
        MyBeanUtils.setProperty(user, "name", "李思思");
        // 设置int类型数据
        MyBeanUtils.setProperty(user, "age", 23);
        // 设置boolean类型数据
        MyBeanUtils.setProperty(user, "gender", false);
        // 设置Date类型数据
        MyBeanUtils.setProperty(user, "birthday", new Date(13213412412L));
        System.out.println(user);
    }

    @Test
    public void testGetPropertyValue() {
        // 获取String类型属性
        String name = (String) MyBeanUtils.getPropertyValue("name", user);
        // 获取int类型属性
         int age = (Integer) MyBeanUtils.getPropertyValue("age", user);
        // 获取boolean类型属性
         boolean gender = (Boolean) MyBeanUtils.getPropertyValue("gender", user);
        // 获取Date类型属性
        Date birthday = (Date) MyBeanUtils.getPropertyValue("birthday", user);
         System.out.println(name + "、" + age + "、" + gender + "、" + birthday + "。");
    }

    @Test
    public void testPopulate() {
        // 向Map集合中封装数据,适用于request.getParameterMap() ;
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("name", "王五");
        map.put("age", 21);
        map.put("gender", true);
        map.put("birthday", new Date(32131412L));
        map.put("address", "上海");
        // 将Map集合中的数据封装到UserBean
        User u = (User) MyBeanUtils.populate(new User(), map);
        System.out.println(u);
    }
}

相对而言内省操作比较繁琐,而Apache Commons为我们提供了一套简单、易用的API来操作Bean的属性的工具包BeanUtils

更多关于BeanUtils的使用可查看:Commons BeanUtils 用户指南

Java 注解(Annotation)

Java Web Start

格式化 I/O

对于了解 C 语言的人来说,printf 这个输出并不陌生,Java也沿用了这种方法。

public class ceshi{
    public static void main(String[] arg){
        display("fxb1",32);
        display("fxb2",33);
        display("fxb3",34);
    }
    public static void display(String name,int age){
        System.out.printf("你好,%s.下一年你就%d\n",name,age);
        System.out.println("------------------------------");
    }   
}/*输出:
你好,fxb1.下一年你就32
------------------------------
你好,fxb2.下一年你就33
------------------------------
你好,fxb3.下一年你就34
------------------------------
*/

每一个以%字符开始的格式说明符都用相应的参数替换,格式说明符尾部的转换符将指示被格式化的数值类型。

用于printf的转换符:

  • d:十进制整数
  • x:十六进制整数
  • o:八进制整数
  • f:定点浮点数
  • e:指数浮点数
  • g:通用浮点数
  • a:十六进制浮点数
  • s:字符串
  • c:字符
  • b:布尔值
  • h:散列码
  • tx:日期时间(以t开头后面的值有很多)-可参考《Java核心技术 卷一》的58页
  • %:百分号
  • n:与平台有关的行分隔符
System.out.printf("%+,.2f  %+,.2f", -10000.0 / 3.0, 10000.0 / 3.0);
/*输出结果: 
 * -3,333.33  +3,333.33
 */

用于printf的标志:

  • + :打印整数和负数的符号
  • 空格 :在整数之前添加空格
  • 0 :数字前面补0
  • - :左对齐
  • ( :添加分组分隔符
  • #(对于f格式) :包含小数点
  • #(对于x或0格式):添加前缀0x或0
  • d,%1$x将以十进制和十六进制格式打印第一个参数
  • <:格式化前面说明的数值。例如,%d%

泛型(Generic)

参考资料:

赞赏

猜你喜欢

转载自blog.csdn.net/fanxiaobin577328725/article/details/81975750