黑马程序员_java JDK1.5特性------- android培训、java培训、期待与您交流! ----------静态导入:??? JDK1.5
黑马程序员_java JDK1.5特性
------- android培训、java培训、期待与您交流! ----------
静态导入:
??? JDK1.5的新特性,它用于导入指定类的静态属性或静态方法。
??? 语法:import static java.包名.类名.*;
??? 演示:
??? ??? package com.itheima;
??? ??? import java.util.Calendar;
??? ??? import static java.util.Calendar.*;
??? ??? public class StaticImportDemo {
??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? Calendar cal = getInstance();
??? ??? ??? ??? cal.set(DATE, 25);
??? ??? ??? ??? System.out.println(cal.getTime());
??? ??? ??? }
??? ??? }
可变参数:
??? JDK1.5的新特性
??? 特点:1、只能出现在参数列表最后
??? ????? 2、...位于变量类型和变量名之间,前后有无空格都可以
??? ????? 3、调用可变参数方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数
??? 演示:
??? ??? package com.itheima;
??? ??? public class ChangeArgsDemo {
??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? System.out.println(changeArgs(2,4,6,8));
??? ??? ??? }
??? ??? ??? public static int changeArgs(int ... args)
??? ??? ??? {
??? ??? ??? ??? int sum = 0;
??? ??? ??? ??? for(int i = 0; i < args.length; i++)
??? ??? ??? ??? ??? sum += args[i];
??? ??? ??? ??? return sum;
??? ??? ??? }
??? ??? }
增强for循环:
??? JDK1.5之后的新特性。
??? 语法:
??? ??? for(参数类型 变量名 : 数组|集合)
??? ??? {
??? ??? ??? //迭代部分
??? ??? }
??? 特点:使用增强for循环遍历数组或集合时,无需指定长度,也无需根据索引来访问元素
??? 注意:增强for循环只能遍历数组或集合,不能改变数组或集合的值
??? 演示:
??? ??? package com.itheima;
??? ??? import java.util.Arrays;
??? ??? public class EnhanceForDemo {
??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? int[] arr = {12,32,24,21,37};
??? ??? ??? ??? for(int item : arr)
??? ??? ??? ??? {
??? ??? ??? ??? ??? //改变数组元素的值
??? ??? ??? ??? ??? item = item + 2;
??? ??? ??? ??? ??? System.out.print(item + " ");
??? ??? ??? ??? }
??? ??? ??? ??? //打印员数组
??? ??? ??? ??? System.out.println("\n" + Arrays.toString(arr));
??? ??? ??? }
??? ??? }
??? 运行结果:14 34 26 23 39
??? ??? ? [12, 32, 24, 21, 37]
枚举类:
??? JDK1.5的新特性,新增enum关键字,用以定义枚举类。
??? 特点:1、枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,
??? ??? 而不是Object类。其中Enum类实现了Serializable和Comparable接口。
??? ????? 2、使用enum定义的非抽象枚举类默认使用final修饰,因此非抽象枚举类不能派生子类
??? ??? ?A:为什么抽象枚举类或接口可以派生子类?而非抽象枚举类不可以
??? ??? ??? 因为抽象枚举类被abstract修饰,而abstract不能和final使用
??? ????? 3、枚举类的构造方法只能使用private修饰,默认情况也是
??? ????? 4、枚举类的所有实例必须在枚举类的第一行显示列出,系统会自动添加public static final修饰
??? ???????? 格式:每个枚举值之间以英文逗号隔开,最好以分号结束
??? ???????? 演示:
??? ??? ??? public enum SeasonEnum {
??? ??? ??? ??? SPRING, SUMMER, FALL, WINTER;
??? ??? ??? ??? private SeasonEnum(){}//如果改为public,编译失败。
??? ??? ??? }
??? ??? ??? //如果把构造器和实例交换位置,编译时出错
??? ????? 6、所有的枚举类都提供了一个values()方法,刚方法可以遍历所有的枚举值(实例)
??? ??? ?演示:
??? ??? ??? package com.itheima.demo;
??? ??? ??? public enum SeasonEnum {
??? ??? ??? ??? //定义四个枚举实例
??? ??? ??? ??? SPRING, SUMMER, FALL, WINTER;
??? ??? ??? }
??? ??? ??? package com.itheima.demo;
??? ??? ??? import com.itheima.season.Season;
??? ??? ??? public class Test {
??? ??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? ??? //用数组保存所有的枚举值
??? ??? ??? ??? ??? SeasonEnum[] seas = SeasonEnum.values();
??? ??? ??? ??? ??? for(SeasonEnum item : seas)
??? ??? ??? ??? ??? ??? System.out.print(item);
??? ??? ??? 运行结果:SPRING SUMMER FALL WINTER
??? 枚举类无参的实例化过程:
??? ??? 当在枚举类中给出一个枚举值,就创建了一个枚举类实例,
??? ??? 通过显示创建无参构造器来证实它的实例化过程。
??? ??? 演示说明:
??? ??? ??? public enum SeasonEnum {
??? ??? ??? ??? //列出4个枚举类实例
??? ??? ??? ??? SPRING,//public static final SeasonEnum SPRING = new SeasonEnum();
??? ??? ??? ??? SUMMER,//public static final SeasonEnum SUMMER = new SeasonEnum();
??? ??? ??? ??? FALL,//public static final SeasonEnum FALL = new SeasonEnum();
??? ??? ??? ??? WINTER;//public static final SeasonEnum WINTER = new SeasonEnum();
??? ??? ??? ??? //看构造器中的代码是否被执行
??? ??? ??? ??? private SeasonEnum()
??? ??? ??? ??? {
??? ??? ??? ??? ??? System.out.println("构造器被调用了");
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? /*测试类*/
??? ??? ??? public class SeasonTest {
??? ??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? ??? SeasonEnum s = SeasonEnum.valueOf("SPRING");
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? 运行结果:构造器被调用了
??? ??? ??? ??? ? 构造器被调用了
??? ??? ??? ??? ? 构造器被调用了
??? ??? ??? ??? ? 构造器被调用了
??? ??? ??????? 通过运行结果可以看出,当在主函数中调用使用枚举类时,先走了构造方法,
??? ??? ??? 有几个枚举值,构造器就被调用了多少次,就创建了多少个枚举实例,
??? ??? 结论:枚举类的实例只能是枚举值,不能随意通过new来创建对象,无需显示调用构造器。
??? 枚举类的带参实例化过程:
??? ??? 当枚举类显示的定义了带参构造方法时,列出枚举值时就必须对应传入参数
??? ??? 演示说明:
??? ??? ??? package com.itheima.gender;
??? ??? ??? public enum GenderEnum {
??? ??? ??? ??? //定义两个枚举实例
??? ??? ??? ??? ?//相当于public static final GenderEnum MALE = new GenderEnum("男");
??? ??? ??? ??? MALE("男"),
??? ??? ??? ??? //相当于public static final GenderEnum FEMALE = new GenderEnum("女");
??? ??? ??? ??? FEMALE("女");
??? ??? ??? ??? private GenderEnum(String sex) {
??? ??? ??? ??? ??? this.sex = sex;
??? ??? ??? ??? }
??? ??? ??? ??? //枚举类通常设置为不可变类,因此它的属性也不应该随便改变
??? ??? ??? ??? //所以用private final修饰
??? ??? ??? ??? private final String sex;
??? ??? ??? ??? public String getSex()
??? ??? ??? ??? {
??? ??? ??? ??? ??? return sex;
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? package com.itheima.gender;
??? ??? ??? /*测试类*/
??? ??? ??? public class GenderTest {
??? ??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? ??? GenderEnum male = GenderEnum.MALE;
??? ??? ??? ??? ??? System.out.print(male.getSex() + " ");
??? ??? ??? ??? ??? GenderEnum female = GenderEnum.FEMALE;
??? ??? ??? ??? ??? System.out.print(female.getSex());
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? 运行结果:男 女
??? ??? 结论:当枚举类定义了带参构造器时,如果枚举值不匹配对应的参数,编译失败
??? ??? ????? 枚举值传入参数时,实际上就是调用了带参构造器创建对象,只是它无需
??? ??? ????? 通过new来创建对象,也无需显示调用构造器
??? 枚举类的特殊方法:
??? ??? int compareTo(E o) 比较此枚举与指定对象的顺序。
??? ??? String name() 返回此枚举常量的名称,在其枚举声明中对其进行声明。
??? ??? String toString() 返回枚举常量的名称,它包含在声明中。
??? ??? static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)
??? ??? ??? ??? 返回带指定名称的指定枚举类型的枚举常量。
??? ??? ??? 演示:
??? ??? ??? ??? package com.itheima.demo;
??? ??? ??? ??? public enum SeasonEnum {
??? ??? ??? ??? ??? SPRING, SUMMER, FALL, WINTER;
??? ??? ??? ??? ??? public void show(SeasonEnum s)
??? ??? ??? ??? ??? {
??? ??? ??? ??? ??? ??? switch(s){
??? ??? ??? ??? ??? ??? case SPRING:
??? ??? ??? ??? ??? ??? ??? System.out.println("春天");
??? ??? ??? ??? ??? ??? ??? break;
??? ??? ??? ??? ??? ??? case SUMMER:
??? ??? ??? ??? ??? ??? ??? System.out.println("夏天");
??? ??? ??? ??? ??? ??? ??? break;
??? ??? ??? ??? ??? ??? case FALL:
??? ??? ??? ??? ??? ??? ??? System.out.println("秋天");
??? ??? ??? ??? ??? ??? ??? break;
??? ??? ??? ??? ??? ??? case WINTER:
??? ??? ??? ??? ??? ??? ??? System.out.println("冬天");
??? ??? ??? ??? ??? ??? ??? break;
??? ??? ??? ??? ??? ??? }
??? ??? ??? ??? ??? }
??? ??? ??? ??? }
??? ??? ??? ??? package com.itheima.season;
??? ??? ??? ??? import com.itheima.demo.SeasonEnum;
??? ??? ??? ??? public class SeasonTest {
??? ??? ??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? ??? ??? //通过给定的字符串常量,获取枚举类实例,
??? ??? ??? ??? ??? ??? //给出的字符串常量必须是枚举实例之一,
??? ??? ??? ??? ??? ??? //否则运行时引发IllegalArgumentException异常
??? ??? ??? ??? ??? ??? SeasonEnum s = SeasonEnum.valueOf("SPRING");
??? ??? ??? ??? ??? ??? System.out.println(s);
??? ??? ??? ??? ??? ??? s.show(s);
??? ??? ??? ??? ??? }
??? ??? ??? ??? }
??? ??? ??? 运行结果:
??? ??? ??? ??? SPRING
??? ??? ??? ??? 春天
??? ??? int ordinal() 返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
??? ??? Class<E> getDeclaringClass() 返回与此枚举常量的枚举类型相对应的 Class 对象。
??? 枚举类中的抽象方法:
??? ??? 如果枚举类实现了一个接口或继承了一个抽象类,如果每个枚举实例调用该方法都具有
??? ??? 相同功能,那么可以直接在枚举类中重写该方法
??? ??? 演示:
??? ??? ??? public enum EnumClass implements A {
??? ??? ??? ??? MALE(1),FEMALE(2);
??? ??? ??? ??? private final int x;
??? ??? ??? ??? private EnumClass(int x)
??? ??? ??? ??? {
??? ??? ??? ??? ??? this.x = x;
??? ??? ??? ??? }
??? ??? ??? ??? //重写show()
??? ??? ??? ??? public void show(){}
??? ??? ??? }
??? ??? ??? interface A
??? ??? ??? {
??? ??? ??? ??? public abstract void show();
??? ??? ??? }
??? ??? 如果每个枚举类实例的实现细节不一样,那么可以通过匿名内部类的方式让每个枚举实例
??? ??? 都重写该方法
??? ??? 演示:
??? ??? ??? public enum EnumClass implements A {
??? ??? ??? ??? MALE(1)
??? ??? ??? ??? {
??? ??? ??? ??? ??? public void show() {
??? ??? ??? ??? ??? ??? //实现细节
??? ??? ??? ??? ??? }
??? ??? ??? ??? ???
??? ??? ??? ??? },
??? ??? ??? ??? FEMALE(2)
??? ??? ??? ??? {
??? ??? ??? ??? ??? public void show() {
??? ??? ??? ??? ??? ??? //实现细节
??? ??? ??? ??? ??? }
??? ??? ??? ??? ???
??? ??? ??? ??? };
??? ??? ??? ??? private final int x;
??? ??? ??? ??? private EnumClass(int x)
??? ??? ??? ??? {
??? ??? ??? ??? ??? this.x = x;
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? interface A
??? ??? ??? {
??? ??? ??? ??? public abstract void show();
??? ??? ??? }
??? ??? 如果该枚举类中本身就包含抽象方法,那么每个枚举实例都必须重写该方法。
??? ??? 注意:枚举类定义抽象方法时,不能使用abstract将类定义成抽象类,
??? ??? ????? 因为系统会自动添加abstract修饰,这里不能在显示添加
??? ??? 模拟交通灯练习:
??? ??? ??? package com.itheima.lamp;
??? ??? ??? public enum TransLamp {
??? ??? ??? ??? RED(40) {
??? ??? ??? ??? ??? @Override
??? ??? ??? ??? ??? public TransLamp nextLamp() {
??? ??? ??? ??? ??? ??? return GREEN;
??? ??? ??? ??? ??? }
??? ??? ??? ??? },
??? ??? ??? ??? GREEN(50) {
??? ??? ??? ??? ??? @Override
??? ??? ??? ??? ??? public TransLamp nextLamp() {
??? ??? ??? ??? ??? ??? return YELLOW;
??? ??? ??? ??? ??? }
??? ??? ??? ??? },
??? ??? ??? ??? YELLOW(3) {
??? ??? ??? ??? ??? @Override
??? ??? ??? ??? ??? public TransLamp nextLamp() {
??? ??? ??? ??? ??? ??? return RED;
??? ??? ??? ??? ??? }
??? ??? ??? ??? };
??? ??? ??? ??? private final int time;
??? ??? ??? ??? private TransLamp(int time)
??? ??? ??? ??? {
??? ??? ??? ??? ??? this.time = time;
??? ??? ??? ??? }
??? ??? ??? ??? public int getTime()
??? ??? ??? ??? {
??? ??? ??? ??? ??? return time;
??? ??? ??? ??? }
??? ??? ??? ??? public abstract TransLamp nextLamp();
??? ??? ??? }
??? ??? ??? /*测试类*/
??? ??? ??? package com.itheima.lamp;
??? ??? ??? public class Test {
??? ??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? ??? TransLamp tlRed = TransLamp.RED;
??? ??? ??? ??? ??? System.out.println(tlRed + " 时间:" + tlRed.getTime()
??? ??? ??? ??? ??? + "s,下一种灯是:" + tlRed.nextLamp());
??? ??? ??? ??? ??? TransLamp tlGreen = TransLamp.GREEN;
??? ??? ??? ??? ??? System.out.println(tlGreen + " 时间:" + tlGreen.getTime()
??? ??? ??? ??? ??? + "s,下一种灯是:" + tlGreen.nextLamp());
??? ??? ??? ??? ??? TransLamp tlYellow = TransLamp.YELLOW;
??? ??? ??? ??? ??? System.out.println(tlYellow + " 时间:" + tlYellow.getTime()
??? ??? ??? ??? ??? + "s,下一种灯是:" + tlYellow.nextLamp());
??? ??? ??? ??? }
??? ??? ??? }
??? ??? ??? 运行结果:
??? ??? ??? ??? RED 时间:40s,下一种灯是:GREEN
??? ??? ??? ??? GREEN 时间:50s,下一种灯是:YELLOW
??? ??? ??? ??? YELLOW 时间:3s,下一种灯是:RED
Annotation(注解):
??? JDK1.5的新特性。它是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行
??? 相应的处理。
??? Java提供的几个基本Annotation的用法,使用Annotation时要在其前面增加@符号,用于修饰它支持
??? 的程序元素。
??? @Override:限定重写父类方法。它可以强制一个子类必须覆盖父类的方法。
??? ??? 作用:告诉编译器检查这个方法,避免了重写父类有可能出错带来的麻烦。
??? @Deprecated:标记元素已过时,当程序使用已过时的类或方法时,编译器将会给出警告。
??? @SuppressWarnings:抑制编译器警告。它会一直作用于该程序元素的所有子元素。通常情况下,
??? ??? 如果程序使用没有泛型限制的集合将会引起编译警告,为了避免这种警告,就可以使用它。
??? ??? 演示:
??? ??? ??? package com.itheima;
??? ??? ??? import java.util.ArrayList;
??? ??? ??? @SuppressWarnings(value = "unchecked")
??? ??? ??? public class ArrayListTest {
??? ??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? ??? //创建一个不带泛型限制的集合
??? ??? ??? ??? ??? ArrayList al = new ArrayList();
??? ??? ??? ??? ??? al.add("hah");
??? ??? ??? ??? }
??? ??? ??? }
??? ??? 通过编译上面程序,当使用@SuppressWarnings来关闭编译器警告时,一定要在括号里使用
??? ??? name = "value"的形式为该Annotation的成员设置值,否则编译失败!!!
元注解:
??? 在java.lang.annotaion包下提供了4个元注解,这4个元注解都只能用于修饰其他的Annotation定义。
??? @Retention:
??? ??? 只能用于修饰一个Annotation定义,用于指定被修饰的Annotation可以保留多长时间,
??? ??? @Retention包含一个RetentionPolicy类型的value成员变量,所以使用@Retention时,
??? ??? 必须为该value指定值:
??? ??? ??? RetentionPolicy.CLASS:
??? ??? ??? ??? 编译器将把Annotation记录在class文件中。当运行Java程序时,JVM不再
??? ??? ??? ??? 保留Annotation。这是默认值。
??? ??? ??? RetentionPolicy.RUNTIME:
??? ??? ??? ??? 编译器将把Annotation记录在class文件中。当运行Java程序时,JVM也会
??? ??? ??? ??? 保留Annotation,程序可以通过反射获取该Annotation信息。
??? ??? ??? RetentionPolicy.SOURCE:
??? ??? ??? ??? Annotation只保留在源代码中,编译器直接丢弃这种Annotation。
??? ??? 如果需要通过反射获取注解信息,就需要使用RetentionPolicy.RUNTIME
??? ??? 演示:
??? ??? ??? package com.itheima.annotation;
??? ??? ??? import java.lang.annotation.Retention;
??? ??? ??? import java.lang.annotation.RetentionPolicy;
??? ??? ??? //定义下面的MyAnnotation Annotation保留到运行时
??? ??? ??? @Retention(RetentionPolicy.RUNTIME)//== @Retention(value=RetentionPolicy.RUNTIME)
??? ??? ??? public @interface MyAnnotation {
??? ??? ??? ??? public abstract String show() default "hehe";
??? ??? ??? ??? public abstract int age() default 32;
??? ??? ??? }
??? @Target:
??? ??? @Target也只能修饰一个Annotation定义,它用于指定自定义Annotation的作用域。它也
??? ??? 需要指定值:
??? ??? ??? ElementType.ANNOTATION_TYPE:只能修饰Annotation
??? ??? ??? ElementType.CONSTRUCTOR:只能修饰构造器
??? ??? ??? ElementType.FIELD:只能修饰成员变量
??? ??? ??? ElementType.LOCAL_VARIABLE:只能修饰局部变量
??? ??? ??? ElementType.METHOD:只能修饰方法定义
??? ??? ??? ElementType.PACKAGE:只能修饰包定义
??? ??? ??? ElementType.PARAMETER:可以修饰参数
??? ??? ??? ElementType.TYPE:可以修饰类、接口(包括注解类型)、枚举类
??? ??? 演示:
??? ??? ??? package com.itheima.annotation;
??? ??? ??? import java.lang.annotation.ElementType;
??? ??? ??? import java.lang.annotation.Retention;
??? ??? ??? import java.lang.annotation.RetentionPolicy;
??? ??? ??? import java.lang.annotation.Target;
??? ??? ??? import javax.lang.model.element.Element;
??? ??? ??? @Retention(RetentionPolicy.RUNTIME)
??? ??? ??? //指定MyAnnotation只能修饰构造器
??? ??? ??? @Target(ElementType.CONSTRUCTOR)
??? ??? ??? public @interface MyAnnotation {
??? ??? ??? ??? public abstract String show() default "hehe";
??? ??? ??? ??? public abstract int age() default 32;
??? ??? ??? }
??? ??? ??? package com.itheima.annotation;
??? ??? ??? import java.lang.annotation.Annotation;
??? ??? ??? import javax.xml.ws.Action;
??? ??? ??? // @MyAnnotation 如果不注释,编译出错
??? ??? ??? public class AnnotationTest {
??? ??? ??? ??? //编译通过
??? ??? ??? ??? @MyAnnotation
??? ??? ??? ??? public AnnotationTest(){}
??? ??? ??? ??? @Action
??? ??? ??? ??? @Override
??? ??? ??? ??? public boolean equals(Object obj)
??? ??? ??? ??? {
??? ??? ??? ??? ??? return true;
??? ??? ??? ??? }
??? ??? ??? ??? @SuppressWarnings(value = "unchecked")
??? ??? ??? ??? // @MyAnnotation //如果不注释,编译出错
??? ??? ??? ??? public void show()
??? ??? ??? ??? {
??? ??? ??? ??? ???
??? ??? ??? ??? }
??? ??? ??? }
自定义Annotation:
??? 定义新的Annotation类型,使用@interface关键字定义一个新的Annotation类型。
??? 语法举例:
??? ??? public @interface MyAnnotation
??? ??? {
??? ???
??? ??? }
??? 定义该Annotation之后,就可以在程序的任何地方使用该Annotation。默认情况下,可用于修饰
??? 类、接口、方法、变量等。
??? 演示:
??? ??? @MyAnnotation
??? ??? public class AnnotationTest {
??? ??? ??? @MyAnnotation
??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? @MyAnnotation
??? ??? ??? ??? int a = 30;
??? ??? ??? }
??? ??? }
??? 自定义Annotation时,还可以带属性、方法,和定义接口的语法要求基本一样,但是其中的抽象
??? 方法不能带参数。
??? 演示:
??? ??? public @interface MyAnnotation {
??? ??? ??? public static final String name = "haha";
??? ??? ??? public abstract String show();
??? ??? ??? //public abstract String show(int a);编译不通过
??? ??? }
??? 一旦在Annotation里定义了方法,使用该Annotation时就必须为其方法指定对应的类型参数值,
??? 否则编译失败!!!
??? 语法:@自定义Annotation接口(方法名1 = 对应的数据类型值, 方法名2 = 对应的数据类型值)
??? 演示:
??? ??? package com.itheima.annotation;
??? ???
??? ??? public @interface MyAnnotation {
??? ??? ??? public abstract String show();
??? ??? ??? public abstract int age();
??? ??? }
??? ??? package com.itheima.annotation;
??? ??? //使用该Annotation时,给出对应类型的值,并且自定义Annotation中,
??? ??? //有几个方法,就必须对应的给出几个对应的key-value对,否则编译失败
??? ??? @MyAnnotation(show = "haha", age = 4)
??? ??? public class AnnotationTest {
??? ??? ??? public static void main(String[] args) {
??? ??? ??? ???
??? ??? ??? }
??? ??? }
??? 也可以在定义Annotation的方法时,通过default关键字为其制定初始值,当然初始值也必须
??? 和所在方法对应的返回值类型相对应,否则编译失败!!!
??? 演示:
??? ??? package com.itheima.annotation;
??? ??? @Retention(RetentionPolicy.RUNTIME)
??? ??? public @interface MyAnnotation {
??? ??? ??? public abstract String show() default "hehe";
??? ??? ??? public abstract int age() default 32;
??? ??? }
??? ??? package com.itheima.annotation;
??? ??? @MyAnnotation
??? ??? public class AnnotationTest {
??? ??? ??? public static void main(String[] args) {
??? ??? ??? ???
??? ??? ??? }
??? ??? }
??? 通过上面程序看出:如果为自定义Annotation的方法指定了默认值,在使用Annotation时,
??? 则可以不为其指定值。当然也可以在使用Annotation时,为其指定值,则默认值就不会起作用。
根据Annotation是否可以包含成员变量,可以把Annotation分为如下两类:
??? 1:标记Annotation:没有定义成员的Annotation类型被称为标记。这种Annotation仅利用自身
??? ?? 的存在与否来为我们提供信息,如@Override等
??? 2:元数据Annotation:包含成员的Annotation,因为可以接收更多的元数据,所以也被称为
??? ?? 元数据Annotation。
提取Annotation信息:
??? Java5在java.lang.reflect包下新增了AnnotateElement接口,该接口代表程序中可以接受注释的
??? 程序元素。该接口主要有如下几个实现类。
??? ??? AccessibleObject, Class, Constructor, Field, Method, Package
??? 当一个Annotation类型被定义为运行时Annotation后,该Annotation才会在运行时可见,JVM才会
??? 加载对应的class文件。
??? AnnotatedElement接口是所有程序元素(如Class、Method、Constructor等)的父接口,所以程序
??? 通过反射获取了某个类的AnnotatedElement对象(如Class、Method、Constructor等)之后,程序
??? 就可以调用该对象的如下几个方法来访问Annotation信息。
??? ??? 1:<T extends Annotation> T getAnnotation(Class<T> annotationClass)
??? ??? ??? 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
??? ??? 2:Annotation[] getAnnotations() 返回此元素上存在的所有注释。
??? ??? 3:Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。
??? ??? 4:boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
??? ??? ??? 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
??? 演示:
??? ??? 接上面的程序
??? ??? package com.itheima.annotation;
??? ??? import java.lang.annotation.Annotation;
??? ??? public class Test {
??? ??? ??? public static void main(String[] args) throws Exception {
??? ??? ??? ??? if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class))
??? ??? ??? ??? {
??? ??? ??? ??? ??? MyAnnotation ma = (MyAnnotation)AnnotationTest.class.
??? ??? ??? ??? ??? getAnnotation(MyAnnotation.class);
??? ??? ??? ??? ??? System.out.println(ma.age());
??? ??? ??? ??? ??? System.out.println(ma.show());
??? ??? ??? ??? }
??? ??? ??? }
??? ??? }
??? ??? 运行结果:hehe
??? ??? ??? ? 32
泛型:
??? JDK1.5的新特性。用于解决安全问题,是一个类型安全机制。
好处:
??? 1、将运行时期出现的问题(ClassCastException),转移到编译时期,方便程序员解决问题。
??? 2、避免了强制转换带来的麻烦,增强了程序的健壮性。
格式:通过< >来定义要操作的引用数据类型,其实< >就是用来接收类型的,将要存储的数据类型传递到< >中。
??? 演示:
??? ??? import java.util.*;
??? ??? public class CollectionTest
??? ??? {
??? ??? ??? public static void main(String[] args)
??? ??? ??? {
??? ??? ??? ??? //ArrayList<String> al = new ArrayList<String>();
??? ??? ??? ??? //Java7的菱形语法,Java允许在构造器后不需要带完整的泛型信息
??? ??? ??? ??? ArrayList<String> al = new ArrayList();
??? ??? ??? ??? al.add("haha");
??? ??? ??? ??? al.add("xixi");
??? ??? ??? ??? //al.add(3);因为指定了集合只能添加String类型的元素,
??? ??? ??? ??? //所以向集合添加其他类型的元素的时候编译出错。
??? ??? ??? ??? Iterator<String> it = al.iterator();
??? ??? ??? ??? while(it.hasNext())
??? ??? ??? ??? {
??? ??? ??? ??? ??? String str = it.next();//因为指定了元素类型,所以不用在强转
??? ??? ??? ??? ??? System.out.println(str);
??? ??? ??? ??? }
??? ??? ??? }
??? ??? }
自定义泛型类、接口:
??? 什么时候定义泛型类?
??? ??? 当要操作的引用数据类型不确定的时候
??? 定义的泛型类作用于整个类中,为了让不同方法操作不同类型,而且类型还不确定,那么可以
??? 将泛型定义在方法上。所谓泛型方法,就是在声明方法时定义一个或多个类型形参。
??? 定义泛型方法格式:
??? ??? 修饰符 <T, S> 返回值类型 方法名(形参列表)
??? ??? {
??? ???
??? ??? }
??? ???
??? 特殊之处:静态方法、静态初始化块、静态变量不可以访问类上定义的泛型,如果静态方法操作
??? 的引用数据类型不确定,可以将泛型定义在方法上。
??? 示例:
??? ??? package com.itheima.generic;
??? ??? public class GenericDemo {
??? ??? ??? public static void main(String[] args) {
??? ??? ??? ??? Demo<String> demo = new Demo<String>();
??? ??? ??? ??? demo.show(234); //编译通过,因为该方法定义成立泛型方法
??? ??? ??? ??? demo.show("bbd");
??? ??? ??? ??? Demo.printW("355");
??? ??? ??? }
??? ??? }
??? ??? class Demo<T>
??? ??? {
??? ??? ??? //下面代码编译时出错,当创建带泛型声明的自定义类时,构造器不能增加泛型
??? ??? ??? //声明,否则编译失败。但调用该构造时,却可以传入实际参数类型。
??? ??? ??? public Demo<T>();
??? ??? ??? //如果去掉show()方法的泛型定义,编译出错,因为创建对象时,指定了类型
??? ??? ??? //而调用该方法时,传入了一个基本数据类型的参数
??? ??? ??? public <T> void show(T t)
??? ??? ??? {
??? ??? ??? ??? System.out.println("show? :" + t);
??? ??? ??? }
??? ??? ??? //通常泛型方法的参数都会使用类型变量。下面的泛型方法参数就使用类型变量W!
??? ??? ??? //在调用者调用这个方法时会给W赋值,那么参数t的类型也就确定了。
??? ??? ??? public <W> void print(W t)
??? ??? ??? {
??? ??? ??? ??? System.out.println("print? :" + t);
??? ??? ??? }
??? ??? ??? ////如果不加泛型,编译出错,静态方法不可以访问类上定义的泛型
??? ??? ??? public static <W> void printW(W t)
??? ??? ??? {
??? ??? ??? ??? System.out.println("printW?? :" + t);
??? ??? ??? }
??? ??? }
??? 通过上面程序可以看出,泛型可以定义在类上,也可以定义在方法上。它们的不同是:方法声明
??? 中定义的泛型形参,只能在该方法里使用,而接口、类声明的泛型形参则可以再整个类中使用。
??? 与类、接口中使用泛型参数不同的是:方法中泛型参数无须显示传入实际类型参数
从泛型类派生子类:
??? 定义类、接口、方法时,可以声明类型形参,当使用带泛型声明的父类、接口或方法时,父类和接口
??? 不能再包含类型形参,应该为类型形参传入实际的参数类型。
??? 示例:
??? ??? public class A<T>{}
??? ??? public class B extends A<T>{}//编译失败
??? 调用方法时必须为所有的数据类型传入参数值,与调用方法不同的是,使用泛型类、接口时,可以
??? 不为类型形参出入实际参数值。
??? 示例:
??? ??? public class A<T>{}
??? ??? public class B extends A{}//没问题,只是有编译器警告
类型通配符:
??? 当使用泛型时,都应该为这个泛型类传入一个类型参数,如果没有传入将引发编译器警告。如果
??? 不知道传入的是什么类型,是否可以也用Object类定义呢?
??? 演示说明:
??? ??? package com.itheima.generic;
??? ??? import java.util.ArrayList;
??? ??? public class GenericTest {
??? ??? ??? public static void main(String[] args)
??? ??? ??? {
??? ??? ??? ??? //创建一个明确泛型声明的集合
??? ??? ??? ??? ArrayList<String> al = new ArrayList<String>();
??? ??? ??? ??? al.add("haha");
??? ??? ??? ??? al.add("hehe");
??? ??? ??? ??? test(al);//编译出错
??? ??? ??? }
??? ??? ??? //下面这个方法,假设我们不知道传入的类型,用一个
??? ??? ??? //Object类型来接受
??? ??? ??? private static void test(ArrayList<Object> al)
??? ??? ??? {
??? ??? ??? ???
??? ??? ??? }
??? ??? }
??? 上面程序编译出错,表明ArrayList<String>对象不能被当成ArrayList<Object>对象使用,也就是
??? 说:ArrayList<String>类不是ArrayList<Object>类的子类!!!带泛型声明的Object类型不是其
??? 它子类型的父类!!!在使用泛型类创建对象时,左右两边的类型必须一致!!!
??? 演示:
??? ??? ArrayList<String> al = new ArrayList<String>;
使用类型通配符:
??? 类型通配符是一个"?",它的元素类型可以匹配任何类型,表示各种泛型声明类型的父类。但是,
??? 它只能出现在引用中。
??? 举例:ArrayList<?> al = new ArrayList<String>();
??? ????? ArrayList<?> al = new ArrayList<?>();//编译失败
??? 演示:
??? ??? package com.itheima.generic;
??? ??? import java.util.ArrayList;
??? ??? public class GenericTest {
??? ??? ??? public static void main(String[] args)
??? ??? ??? {
??? ??? ??? ??? ArrayList<String> al = new ArrayList<String>();
??? ??? ??? ??? al.add("haha");
??? ??? ??? ??? al.add("hehe");
??? ??? ??? ??? test(al);
??? ??? ??? }
??? ??? ??? private static void test(ArrayList<?> al)
??? ??? ??? {
??? ??? ??? ???
??? ??? ??? }
??? ??? }
??? 但这种带通配符的ArrayList仅表示它是各种泛型ArrayList的父类,并不能把元素添加到其中。
??? 唯一的例外是null,它是所有引用类型的实例
??? 演示:
??? ??? ArrayList<?> al = new ArrayList<String>();
??? ??? al.add(null);//没问题
??? ??? //下面将引起编译出错
??? ??? al.add("haha");
类型上限:
??? 语法:类名或接口名<?/T extends 类名>,表示该类型只能是指定类或其子类。
??? 举例:class Factory<T/? extends Person>
类型下限:
??? 语法:类名或接口名<?/T super 类名>,表示该类型只能是指定类或其父类。
??? 举例:class Factory<T/? extends Student>
------- android培训、java培训、期待与您交流! ----------