高新技术Day02(JavaBean、注解与泛型)
-------android培训、java培训、期待与您交流!----------
—————————内省(IntroSpector)与JavaBean类—————————————
一、内省(IntroSpector)与JavaBean类:
1、定义:
例: 一个类有姓名name的属性信息,而通过getName/setName方法来访问该类的name属性,这就是Java类中的默认规则(内省)。
2、JavaBean中值对象方法命名规则:
getAge()与setAge(int age)
getCPU()与setCPU(String CPU)//当方法操作的变量名均大写时,变量名保持原样;
//这样的目的是为了方便/统一 根据变量名反射获得对应的操作方法;
JavaBean中值对象:
例: 拥有age、name等变量JavaBean类Person,而Person p= new Person();
其中实例对象p就是值对象。
3、操作方式(以反射形式调用):
代码示例:
Person p = new Person();
BeanInfo bi = Introspector.getBeanInfo(p.getClass());
//通过Introspector的静态方法创建BeanInfo的实例对象。
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
//返回该对象中所有属性描述器(包括继承以及class属性)
MethodDescriptor[] mds = bi.getMethodDescriptors();
//返回该对象中的所有方法描述器(包括继承);
4、JavaBean(java.beans包)的类与方法:
Introspector类中方法:
BeanInfo
BeanInfo类中方法:
PropertyDescriptor[] getPropertyDescriptors()
MethodDescriptor[]
PropertyDescriptor类中方法:
构造方法: PropertyDescriptor(String propertyName,Class<?> beanClass)等;
一般方法:
5、BeanUtils工具:
通过下载并导入commons-beanutils(方便操作JavaBean类)与commons-logging(书写日志文件包)两个工具集(jar库),就可以调用BeanUtils工具中的类与方法等。
示例:
//根据Person反射获得并创建带参数的构造方法,并赋值创建Person类实例对象;
Constructor constructor =Person.class.getConstructor(int.class,String.class);
Person person =(ReflectPoint)constructor.newInstance(15,"Edward");
//使用BeanUtils工具中的BeanUtils类中的操作方法:
System.out.println(BeanUtils.getProperty(person,"name"));
BeanUtils.setProperty(person,"age","20"); //将person对象的age重新赋值为20;
6 、加强功能 :
1、当类中有private Date birthday = new Date();【因为Date类中有year等成员变量】,BeanUtils类中的setProperty()方法,可对属性对象中的属性值进行赋值;
例:
System.out.println(BeanUtils.getProperty(person,"date.year"));
BeanUtils.setProperty(person, "birthday.year","200");
2、copyProperties(Object A,Object B);: 复制对象,将对象B的属性复制给A;
Map
【转换后格式:Map{age:7,name:"hehe"}等;】
【PS一句:网上虽然也有看到JDK1.7新特性的Map的赋值新方式,但是个人水平有限,无论是纯JDK1.7还是JDK1.7的MyEclipse都没能编译通过。——有效期2013.6.2前等,呵呵】
populate(Object bean,Map properties):将Map集合元素导入到JavaBean对象中;
7、BeanUtils与PropertyUtils的区别:
A、PropertyUtils与BeanUtils类基本相同,区别在于BeanUtils操作方法的方式是字符串,而PropertyUtils操作方式是元素的原有类型(或其对象包装类);
例如:
BeanUtils.setProperty(person,"age","20");//用字符串"20"来修改;
PropertyUtils.setProperty(person,"age",20);
【除了修改方式,两者的获取值对象的返回值也不同,BeanUtils返回值为String类型,而PropertyUtils返回值类型为元素的原有类型,例如Integer类型(可能为基本数据类型int等,不过会自动装箱成基本数据类型包装类对象)等】
B、应用:
由于BeanUtils接收与返回值为String类型,所以多用于网页接收或返回打印显示等情况;
而PropertyUtils接收与返回值为元素原有类型,可避免类型转换出错的情况,也可直接用于参与对象的运算或使用等情况。
————————————————注解(Annotaion)——————————————
二、注解Annotation
注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。
标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
1、Java提供的基本注解(方式):
@SuppressWarnings("deprecation");
@Deprecated
@Override
适用:包、类class、方法、变量、局部变量等;
2、自定义注解:
A、创建注解类: public @interface 接口名{ ......}
B、添加注解属性(注解属性是个抽象方法,可添加缺省属性,例:String color() default"RED";);
注:
2、使用(创建)注解类时可指定注解属性,之后可在该调用类中调用注解属性方法;
3、元注解:
常量value:
枚举类enumRetentionPolicy中的枚举值:
示意图:
java源文件——(丢弃SOURCE)——>class类文件——(丢弃CLASS)——>内存字节码
【PS: 丢弃XXX,意指丢弃注解有效期为XXX 的注解,在之后的程序代码中将不存在,也就失去该限制功能/作用】
ElementType.METHOD
TYPE
ANNOTATION_TYPE
(还包括字段FIELD、包PACKAGE、构造方法CONSTRUCTOR等)。
PS: 1、Class类中与注解(Annotation)相关的方法:
isAnnotationPresent(Annotction.class) : 该类中是否包含指定的注解类?
getAnnotation(Annotction.class)
interface Type(java.lang.reflect包): Java编程语言中所有类型的公共高级接口;它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。
即可看做Type子类或子接口的有:Class、interface、enum、@interface等Java类型。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) //保留到运行时--》这是元注解,注解的注解
@Target({ElementType.METHOD,ElementType.TYPE})//可以查阅帮助文档-->ElementType
public @interface MyAnnotation//这是一个注解类
{
String color() default "bule";//默认是 public abstract
String value();
int[] arrayAttr() default {1,2,3};//数组属性的注解类型
Class getCls() default String.class;//字节码属性的注解类型
EnumTest.TrafficLamp lamp() default EnumTest.TrafficLamp.GREEN;//枚举属性的注解类型
MetaAnnotation annotationAttr() default @MetaAnnotation(nextDay="1月1号");//注解属性的注解类型
}
————————注解属性(便于浏览,华丽分割线)————————
三、注解的属性:
比喻: 增加证件属性,来明确携带胸牌者的更详细的身份等。
定义注解基本类型的属性和应用属性:
例:
使用该注解类时:
代码示例与解析:
@MyAnnotation(color="red")
//用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation ma=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(ma.color());
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象。
为属性指定缺省值:
1、value属性:
如果注解中有一个名称为value的属性,且想只设置value属性(即其他属性都采用默认值或者除非仅有value一个属性),那么可以省略“value=”部分,例如:@MyAnnotation("lhm")。
2、数组类型的属性:
int [] arrayAttr()default {1,2,3};
使用: @MyAnnotation(arrayAttr ={2,3,4})
如果数组属性中只有一个元素,这时候属性值部分可以省略大括号。
枚举类型的属性
3、注解类型的属性:
MetaAnnotation annotationAttr() default@MetaAnnotation("xxxx");
使用:@MyAnnotation(annotationAttr = @MetaAnnotation(“yyy”))
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象,同样的道理,可以认为上面这个@MetaAnnotation是MetaAnnotation类的一个实例对象,调用代码如下:
注解的详细语法可以通过看java语言规范了解,即看java的languagespecification。
4、注解的属性类型包括:基本数据类型,String,Class,枚举,其他注解,以及这些类型的数组。
————————————————迭代——————————————————
【略过,基本在基础视频课程都提及,主要是巩固下用Map.Entry<K,V>来迭代Map类集合】
————————————————泛型(高级应用)————————————————
四、泛型(高级应用——泛型通配符):
(1)泛型通配符:
?:占位符,表示不确定类型;
? super T与?extends T:泛型上下限通配符;
1、通配符的使用与局限:
? 与 ? extends T两个泛型通配符是不能明确具体类型,所以不能调用与参数类型有关的(参数化)方法,否则程序出错(编译时或运行时都有可能出错)。
例: List<? extends Object>list1 = newArrayList<String>();
而? super T 有类型下限,但只能接收T与T的父类类型;且可调用参数化(但只能调用参数类型为T)方法;
例: List<? super Integer> list2= newArrayList<Number>();
2、编译去类型化: 通过反射给集合添加任意类型元素;
代码示例:
ArrayList<Integer>collection3 = newArrayList<Integer>();collection3.getClass().getMethod("add",Object.class).invoke(collection3,"abc");System.out.println(collection3.get(0));
解析: Java泛型是伪泛型,此泛型的限定只对编译时有效,因为在编译后,会生成普通的非泛型的字节码,此实现技术称为"擦除"(即"去类型化"),即字节码中的集合是没有了所有的泛型限定,因此是可以通过反射来添加任何类型数据到集合中。
(2)泛型集合概念与局限:
泛型集合概念解析:
ArrayList : 原始类型;
ArrayList<E>: 泛型类型;
ArrayList<Integer>: 参数化类型;
ArrayList<E>中E 称为类型变量或类型参数;
ArrayList<Integer>中Integer等 称为类型参数的实例或实际类型参数。
【ArrayList<Integer>中的<>念着typeof 】
1、参数化类型与原始类型是可以相互兼容的;【A、参数化类型可以引用原始类型】
2、参数化类型不考虑类型参数的继承关系(不存在继承关系,只能使用泛型上/下限定符);
3、编译器不允许创建类型变量的数组,即在创建数组实例时,数组的元素不能使用参数化的类型;
错误示例:Vector<Integer> vcArray[] = newVector<Integer>[10];
注意:但可以通过参数化类型引用原始类型方式,来指定数组参数化类型;
Vector<Integer>[] vector =new Vector[3];
4、JVM编译时是逐行读取编译,因此处于不同行的泛型是不会自动关联的。
即示例代码:
ArrayList al = newArrayList<String>();
(PS: List是接口,不能实例化,因此当LS接收不是ArrayList,而是List,则不能赋值)
(3)泛型使用注意事项:
1、只有引用类型才能作为泛型方法的实际参数;基本数据类型是不可以,但Java的自动装箱、拆箱功能能让其提升为基本数据类型对象;
2、泛型限定是可以用"&"符号来指定多个边界;
例如:<V extends Serializable & Comparable> void method(){ };
【指明传入的对象必须是继承或实现了Serializable和Comparable两接口的类型对象,例如Double、Integer等】
3、泛型(类型化变量)可以用于表示异常,称为参数化的异常,可用于方法的throw、throws异常或列表,但是不能用于catch语句中;
4、在泛型中是可以同时有多个类型参数,在定义它们的尖括号中用逗号分开;
例: public static<K,V> V getValue(K key){ returnmap.get(key); }
5、泛型可以根据传入的类型来指定泛型的类型,但优先根据返回值类型来指明泛型;
例如: Object obj = "abc";
(4)类型参数的类型推断:
参数传递推断(详见PPT文档或第41个视频):
(JDK1.7新特性) 示例:ArrayList<String> al = newArrayList<>();
泛型传参时有两个不同泛型值,那么因为Java的传播性(传染性),会取两个不同泛型值的交集(共同)的父类。
类型形参(形式参数T等)、类型实参(实际参数Integer等)
————自定义泛型类————
【略……………】
CRUD
DAO
————————反射获得泛型的实际参数类型———————
五、反射获得泛型的实际参数类型:
问题、应用:
因为在Java编译后集合等是没有了泛型限定,或者在早期编写的代码中是没有泛型,那么我们如何获得(数据库或)集合中存储的参数类型???(特别是在没有获得某些源代码时)
因此: 通过反射获得泛型的实际类型参数。————依靠Method、ParameterizedType等
通过Method方法的获取传参列表中的泛型类型,从而获得指定集合等中存储的类型参数;
应用:
Method类中方法:
String toGenericString();
(例: 返回public<T> voidcom.method(java.util.Collection<T>))
Type
Type[]
【注意: 是以带泛型的参数类型返回返回值或参数列表】
ParameterizedType(接口):
参数化类型,如Collection<String>;
方法:
Type
Type[]
Type接口: class、@interface、enum、.........