探索JDK5的新特性:革新编程体验的里程碑

引言

        Java Development Kit (JDK) 5,于2004年发布,是Java发展历程中具有里程碑意义的一个版本。它不仅引入了一系列关键的编程新特性,还大大提升了开发者的生产力和代码质量。本文将带领大家深入了解JDK 5带来的变革性创新,包括泛型、枚举、for-each循环、变长参数、注解(Annotations)等核心特性。

JDK5特性分析

1. 泛型应用

1.1 概述

泛型是JDK1.5以后推出的一种编译时类型,运行时无效,我们通常可以将其理解为一种参数化类型,可以应用在接口,类,方法,属性上,用于约束类中属性,方法参数以及返回值类型,基于这种方式可以对编程过程中的接口、类、方法进行通用化设计,同时在编译阶段解决在运行时执行一些校验操作,提高其运行效率。

1.2 应用类型

1.2.1 泛型接口

单泛型参数,关键代码如下:

package com.cy.java.generic;

interface Container<T>{//泛型接口
 void add(T t);
 T get(int i);
 int size();
}

多泛型参数,关键代码如下:

interface Task<Param,Result>{//思考map中的泛型Map<K,V>
/**
 * 此方法用于执行任务
 * @param arg 其类型由泛型参数Param决定
 * @return 其类型由泛型参数result决定
 */
Result execute(Param arg1);
}

 

1.2.2 泛型类

泛型抽象类,代码如下:

abstract class AbsContainer<T> implements Container<T>{//泛型类
protected int size;
public int size() {
return size;
}
}

泛型具体类,代码如下:

class ArrayContainer extends AbsContainer<Integer>{
private Object[] array;
public ArrayContainer() {
this.array=new Object[16];
}
@Override
public void add(Integer t) {

}

@Override
Public Integer get(int i) {
return null;
}
}
class IntegerConvertTask implements Task<String,Integer>{
@Override
public Integer execute(String arg) {
return Integer.parseInt(arg);
}
}

1.2.3 泛型方法

泛型方法主要应用与类中的静态方法,但不限于静态方法,例如:

class ObjectFactory{
 //泛型方法
 public static <T>T newInstance(Class<T> cls)
 throws Exception{
 return cls.newInstance();
 }
}
class ContainerUtils{
public static <T>void sort(List<T> list) {

}
}

1.3 泛型通配符

1.3.1 无界通配符

泛型中的无界通配符使用”?”表示,泛指一种不确定性类型。例如,可以代表一种任意参数类型(实参类型),通常会应用于变量的定义,例如:


Class<Object> c1=Object.class;//字节码对象
  //当编译阶段无法确定泛型类型时,应用”?”进行替换。
Class<?> c2=Class.forName("java.lang.Object");

 

1.3.2 有界通配符

泛型在应用时有时需要指定对象的上限和下限,我们称这种形式叫限定通配符,语法如下:

  • 指定泛型下限:<? super T> 表示参数是类型T或T的父类,不影响往里存,但往外取只能放在Object 对象里。

  • 指定泛型上限:<? extends T>表示参数类型是T或T的子类,上界只能外围取,不能往里放。因为编译阶段不能确定你要放入的类型。

有界通配符应用案例,构建一打印工具类,关键代码如下:

class PrintUtil{

static void doPrint(List<? extends CharSequence> list){//上限
System.out.println(list.get(0));
}

static void doPrint(Set<? super Integer> set){//下限
set.add(100);
        System.out.println(set);

}

}

说明,如果要从集合中读取类型T的数据, 并且不能写入,可以使用 上界通配符(<?extends>)—Producer Extends。如果要从集合中写入类型T 的数据, 并且不需要读取,可以使用下界通配符(<? super>)—Consumer Super。如果既要存又要取, 那么就要使用非限定通配符。

通配符应用分析,请问如下写法是否正确?假如不正确该如何修改?

List<Object> list1=new ArrayList<String>();
List<String> list2=new ArrayList<Object>();

1.4 泛型类型擦除

泛型是在编译阶段由编译器执行类型检查和类型推断,然后生成普通的非泛型的字节码。这种实现技术称为擦除(erasure),所以说泛型是编译时的一种类型,在运行时无效,运行时候都会变成Object类型。例如,尝试基于反射技术向List<String> list=new ArrayList<String>()对象中添加整数100。

关键代码如下:

List<String> list=new ArrayList<>();
list.add("A");
list.add("B");
//list.add(100);
//在运行时将100写入到list集合

//1.获取list对象的字节码对象
Class<?> cls=list.getClass();
//2.获取list字节码对象中的add方法对象
Method method=cls.getDeclaredMethod("add",Object.class);
//3.通过反射执行方法对象将100写入集合。
//执行list对象的method方法
method.invoke(list, 100);
System.out.println(list);

1.5 小节面试分析

  • 什么是泛型?(编译时的一种参数化的类型)

  • 为什么要使用泛型?(通用编程,提高运行效率)

  • 泛型有哪些应用方式?(类泛型,接口泛型,方法泛型)

  • 如何理解泛型类型擦除?(泛型在运行时无效,默认所有类型为Object类型)

  • 泛型应用时有哪些通配符?(无界,上届限定通配符,下届限定通配符)

2. 注解应用

2.1 概述

注解是JDK1.5推出的一种新的应用类型(特殊的class),是一种元数据(Meta Data):用于描述接口,类,属性,方法,参数等。可以将其理解为一个为生活中的标签(例如买了件衣服,衣服上贴了个牌子)。Java中所有的注解都默认继承Annotation接口。

2.2 注解定义

我们先来看一下,Java中自带的Overide注解,代码如下:

@Target(value=METHOD)
@Retention(value=SOURCE)
public @interface Override{}

在实际项目注解可能由第三方定义,也可能会由我们自己定义,例如

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//表示只能描述类
@interface Entity{}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)//表示只能描述属性
@interface ID{}

其中:@Target 用于描述定义的注解能够修饰的对象,@Retention 用于描述定义的注解何时有效。

创建注解时,指定注解属性,例如:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Component{
/**注解中的属性定义*/
String value() default "";
boolean lazy() default true;
}

2.3 注解与反射

使用注解描述类及成员,代码如下:

@Entity
class Book{
@ID
private Integer id;
}
@Component(value="lruCache",lazy=false)
class HashLruCache{}

通过反射技术判定注解的存在,例如:

//1.判定类上是否有Entity注解
Class<?> c1=Book.class;
boolean flag = c1.isAnnotationPresent(Entity.class);
System.out.println(flag);
//2.判定对象中id属性上是否有ID注解
//2.1获取属性id
Field f1 = c1.getDeclaredField("id");
//2.2判定属性上是否有ID注解
flag=f1.isAnnotationPresent(ID.class);
System.out.println(flag);

通过反射获取注解属性值,例如:

//如何获取类或属性等上面注解呢?
//1.获取字节码对象(入口)
Class<?> cls=HashLruCache.class;
//2.获取类上的注解
Component c=
cls.getDeclaredAnnotation(Component.class);
//3.获取注解中属性的值
String value=c.value();
boolean lazy=c.lazy();
System.out.println(value);
System.out.println(lazy);

2.4 小节面试分析

  • Java中的注解如何定义?(@interface)

  • Java中注解的作用是什么?(描述类、属性、方法、参数用于赋予这些成员特定含义)

  • Java中的注解与Annotation接口是什么关系?(is a的关系,继承关系)

  • 如何获取类及成员上状态为运行时有效的注解对象?(反射技术)

3. 拆箱封箱

3.1 概述

Java中不仅提供了8种基本数据类型,还为了更好的体现面向对象特性,专门提供了8种基本数据类型对应的对象封装类型。Jdk1.5之后为了更好的实现基本数据类型和8种封装类型之间的转换,提供自动封箱和拆箱机制。

3.2 自动封箱

自动拆箱就是将基本类型自动转换为对象数据类型,例如:

Integer n1=100;

其中,对于等号右边的值会自动调用Integer.valueOf方法转换为对象类型。

3.3 自动拆箱

自动拆箱就是对象类型自动转换为基本数据类型,例如:

Integer n1=Integer.valueOf(100);
int n2=n1;//自动拆箱

说明,无论是自动拆箱,还是自动封装,为Java编程过程中的类型转换提供了很好便利。

3.4 小节面试分析

  • 如何理解Java中的自动拆箱和封箱特性?

  • Java中的自动拆箱和封箱能给编码带来哪些便利?

4. 枚举类型

4.1 概述

枚举是JDK1.5以后推出的一种新的类型(特殊的类),主要用于更加严格的约束变量类型,例如现有一个产品对象,此对象有一个性别属性,请问此属性的类型如何定义呢,还有现在有一订单,我们如何定义订单状态呢?在实际项目中这些类型的定义我们通常会借助枚举进行实现。

4.2 枚举定义

Java中的枚举借助enum关键字进行定义,例如JDK中的枚举:

public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

枚举类型,通常应用于值固定的实例类型,例如一周七天,代码如下:

enum Week {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

其中:Week中MONDAY, TUESDAY等都属于枚举的实例,这些实例都是在类加载时创建,可通过枚举类名直接访问,例如Week.MONDAY。

4.3 枚举类型应用

定义一性别枚举类,例如:

enum Gender{//Gender.class
MALE,FEMALE,NONE; 
}

在定义产品类型时,应用性别枚举类,例如:

class Product{
/**性别要求*/
private Gender gender=Gender.NONE;
public void setGender(Gender gender) {
this.gender = gender;
}
}

定义含有带参构建函数的枚举类型,例如:

enum Sex{
//枚举类型的对象是在类加载时创建
MALE("男"),FEMALE("女");//执行带参构造函数
private String name;
private Sex(String name){
this.name=name;
}
public String getName() {
return name;
}
}

定义会员类,应用Sex枚举类型,例如:

class Member{
private Sex sex=Sex.MALE;
public void setSex(Sex sex) {
this.sex = sex;
}
}

枚举应用测试,案例如下:

Member m=new Member();
String sexStr="MALE";
//将字符串转换为枚举类型时,字符串的值需要
//与枚举类中的实例名相同(区分大小写)
//Sex sex=Sex.valueOf(sexStr);
Sex sex=Enum.valueOf(Sex.class, sexStr);
System.out.println(sex.getName());
m.setSex(sex);

4.4 小节面试分析

  • Java中的枚举是什么?

  • Java中的枚举应用在什么场景?

  • Java中的枚举类型如何定义?

  • Java中的枚举实例是什么时候构建的?

  • Java中的枚举类中的可以定义构造方法吗?

5. 可变参数

5.1 概述

JDK5中允许方法最后一个参数使用带三个点的类型进行定义,在进行方法调用时可传入任意个数的实际参数,其目标主要是用于简化方法名相同,参数类型也相同,但参数个数不同的一系列方法的定义。

5.2 应用实践

可变参数应用案例,关键代码如下:

public class JDK5TryVarargs {
   public static void main(String[] args) {
      greets("Hello", "Peter", "Paul");
   }

   public static void greets(String greeting, String... names) {
      System.out.print(greeting + ",");
      // varargs received as an array
      for (int i = 0; i < names.length; ++i) {
         System.out.print(" " + names[i]);
      }
      System.out.println();
   }
}

说明,可变参数只能应用在方法参数列表中的最后一个参数的定义上。

5.3 小节面试分析

  • 可变参数一般应用在什么场景?

  • 一个方法内部可以多个可变参数吗?

  • 一个方法内部有多个参数时,可变参数可以是第一个参数吗?

6. 总结(Summary)

6.1 重难点分析

  • 泛型定义及应用。

  • 注解的定义及应用。

  • 自动拆箱封箱应用。

  • 枚举的定义及应用。

  • 可变参数的应用。

6.2 FAQ分析

  • 泛型有哪些应用类型?

  • 泛型通配符你知道多少?

  • 如何理解注解,如何定义?

  • 注解反射是如何结合使用的?

  • 可变参数为我们的应用带来哪些便利?

6.3 Bug分析

  • NullPointerException

本篇文章主要对应JAVA基础常见核心面试点中的JDK5新特性。有兴趣可以查看该文章。

  • 28
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值