一、泛型
JDK1.5出现的新特性。用于解决安全问题,是一个安全机制。它存在于编译器,运行期会擦除,避免强制类型转换的风险。
ArrayListal = new ArrayList ();
- 因为集合在初始化定义时没有指定类型,会导致安全隐患。
- 所以泛型的出现解决了这个安全隐患。
- 上面的意思就是只能往集合里添加String类型的元素。
- 数组初始化定义会指定类型,而集合却没有。
ArrayList中的E称为 类型参数变量ArrayList 中的Integer称为 实际类型参数整个称为ArrayList 泛型类型整个ArrayList 称为参数化的类型ParameterizedType
1.1、泛型类使用:
- 当类中要操作的引用数据类型不确定的时候。
- 早期定义Object来完成拓展,现在定义泛型来完成拓展。
public class Demo{ public static void main(String[] args){ Demo person = new Demo (); person.show("哈哈"); } public void show(T t){ System.out.println(t); }}
1.2、自定义泛型:
(1)泛型类定义的泛型,在整个类中有效,同时它整个类的类型就已经固定了
(2)泛型被定义在方法上后,那么就 可以操作任意引用类型的数据。 (3)也可以在类和方法上同时定义泛型。(不重复)但是要注意方法和类的泛型是否一样。 (4)静态方法不可以访问类上定义的泛型。如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。public staticvoid method(W t):泛型放在修饰符后面,返回值前面。
1、方法泛型
定义在方法上的泛型就叫做方法泛型,作用的范围的当前方法内部
泛型在使用之前必须先定义<T>,其中的字母可以是任意字母,但是通常使用大写字母
可以认为,当方法在被调用到时,虚拟机自动判断出泛型的具体类型.
public staticvoid method(T t);
比如我们定义一个方法可以交换数组的位置,方法不但要支持String类型的数组,还要支持Integer类型的数组,则可以使用泛型方法来实现:
/** * 交换任意类型数组的位置 * */public class Demo { public static void main(String[] args) { // String类型数组 String[] strs = {"a", "b", "c", "d"}; change(strs, 0, 2); for (int i = 0; i < strs.length; i++) { System.out.println(strs[i]); } // Integer类型数组 Integer[] ints = {1, 2, 3, 4}; change(ints, 0, 2); for (int i = 0; i < ints.length; i++) { System.out.println(ints[i]); } } public staticvoid change(T[] arrs, int i, int j){ T t = arrs[i]; arrs[i] = arrs[j]; arrs[j] = t; }}
2、 类上泛型
类上的泛型:定义在类上的放行叫做类泛型,作用范围是整个类中都可以使用
public class GenericDao{}
可以认为,在使用这个类时,就需要指定出泛型的具体类型.如果不明确指定,则泛型是它的上边界类型的.
静态方法不能使用类上定义的泛型,如果想使用泛型静态方法必须自己定义泛型(因为静态方法不属于该类,而泛型存在运行期的)
3、泛型通配符
(1)? :通配符。也可以理解为占位符。可以接收任意类型。
因为泛型没有继承关系,所有当需要用一个泛型引用引用不同的泛型实现时,泛型中写他们共同的父类是不行的,这时该怎么做呢?引入一个新的概念,叫做泛型通配符?
注意泛型通配符只能用在泛型引用中,用来引用不同的泛型实现,不能出现在实现中.
List list = null;list = new ArrayList(); list = new ArrayList ();
4、 泛型的边界
(2)? extends E:可以接收E类型和E的子类型。上限限定不变。(父类已经固定,子类可以接收)。(这里的E为父类)
(3)? super E:可以接收E类型和E的父类型。 下限限定不变。(子类已经固定,父类都可以接收)。(这里的E为子类)(访问不到父类的方法。)? extends E - 用来指定泛型的上边界,使用在泛型的通配符中和泛型定义中,指定具体的泛型实现必须是指定的类或其子类.
- 利:在传入对象时,只能传入null
- 弊:获取到泛型的对象时,可以调用上边界的方法.
? super E - 用来指定泛型的下边界,使用在泛型的通配符中,指定具体的泛型实现必须是指定类或其父类.
- 利:可以传入对象时,可以传入下边界的子孙类对象
- 弊:获取到泛型对象时,只能调用Object身上的方法
public class Demo1 { public static void main(String[] args) { // 上限限定 List list = null;// 必须是Person和Person的子类 list = new ArrayList();// Person or teacher // 下限限定 List list1 = null; // 必须是Person和Person的父类 list1 = new ArrayList ();// Person or Animal } class Animal{ } class Person extends Animal { } class Teacher extends Person { }}
二、注解
Annotation 注解:程序中给人看到提示信息叫注释,给程序看的提示信息叫做注解
注解:可以作为配置信息控制程序的运行,注解可以在一些场合用来替代配置文件
@xxxx(....
1.1、jdk1.5内置的注解:
- @Override: 限定重写父类方法, 该注解只能用于方法
- @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
- @SuppressWarnings: 抑制编译器警告.
1.2、自定义注解
1、声明注解
(1)使用 @interface关键字来定义注解,在这个类中可以声明注解的属性
- 注解属性的声明类似于在为接口声明一个方法,同时可以为属性设定默认值
- 注解属性支持如下类型:String、基本数据类型、枚举、Class 、其它注解类型、以上数据类型相应一维数组
- 如果注解中只包含一个名为value的属性,则这个属性在使用时可以省略注解的名字直接写值
public @interface tran{ //String name(); //String name2() default "xxx"; String value();}
(2)使用元注解对注解进行描述
@Retention:用来指定注解的保留范围
- RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注解
- RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中. 当运行 Java 程序时, JVM 不会保留注解. 这是默认值
- !!RetentionPolicy.RUNTIME:编译器将把注释记录在 class 文件中. 当运行 Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释
@Target:指定被修饰的注解可以使用在什么位置
- ElementType的成员变量。可以是类/方法/字段/构造方法/包声明.....
@Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档。
@Inherited: 被它修饰的 Annotation 将具有继承性.如果某个类使用了被 @Inherited 修饰的 Annotation,则其子类将自动具有该注解
2、 使用注解
在 @Target声明的位置上使用 @Tran(属性名 = 属性值,.....)
3、反射注解
JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement 接口, 该接口代表程序中可以接受注释的程序元素,
包括Class Field Method Constructor Package都是这个接口的实现,所以这个接口中定义的反射注解的方法,他们都具有
T getAnnotation(Class annotationClass) // 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。 Annotation[] getAnnotations() // 返回此元素上存在的所有注释。 Annotation[] getDeclaredAnnotations() // 返回直接存在于此元素上的所有注释。 boolean isAnnotationPresent(Class annotationClass) // 如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
a) 首先我们自定义一个注解,并设定在运行期
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface DemoAnno { public String name(); public int age() default 100;}
b) 定义一个Student类,对其使用自定义的注解,如果自定义的注解没有设置默认值时,@DemoAnno(name="zhangsan", age = 20)
@DemoAnno(name="zhangsan")public class Student {}
c) 在Main方法中通过反射去确定是否有注解和拿到Student的名字和年龄
public class Demo { public static void main(String[] args) { Class sc = Student.class; if(sc.isAnnotationPresent(DemoAnno.class)){ DemoAnno da = (DemoAnno) sc.getAnnotation(DemoAnno.class); String name = da.name(); int age = da.age(); System.out.println(name+":"+age); }else{ System.out.println("没有注解"); } }}
################################################################