黑马程序员-Java基础总结16——高新技术Day02(JavaBean、注解与泛型)

时间:2023-02-18 13:17:55

高新技术Day02(JavaBean、注解与泛型)

-------android培训java培训、期待与您交流!---------- 

—————————内省(IntroSpector)JavaBean类—————————————

一、内省(IntroSpector)JavaBean:

1、定义:

   A内省(IntrospectorJava语言Bean类属性、事件的一种缺省处理方法

例: 一个类有姓名name的属性信息,而通过getName/setName方法来访问该类的name属性,这就是Java类中的默认规则(内省)

   BJavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段(成员变量),且方法名符合某种命名规则。

   简单概括: 一个符合内省规则(通过getter/setter方法访问类的字段)的类,就是一个JavaBean,也就可以调用java.beans包中类、方法来实现简便反射操作

 

2JavaBean值对象方法命名规则:

getAge()setAge(int age)  //当变量名第二个字母不是大写时,那么首字母必须小写

getCPU()setCPU(String CPU)//当方法操作的变量名均大写时,变量名保持原样

//这样的目的是为了方便/统一 根据变量名反射获得对应的操作方法

 

JavaBean中值对象:

  如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean,这个JavaBean的实例对象通常称之为值对象(Value Object,简称VO)

: 拥有agename等变量JavaBeanPerson,而Person p= new Person();

其中实例对象p就是值对象。

 

3操作方式(以反射形式调用):

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

代码示例:

  Person p = new Person();
BeanInfo bi = Introspector.getBeanInfo(p.getClass());
//通过Introspector的静态方法创建BeanInfo的实例对象。
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
//返回该对象中所有属性描述器(包括继承以及class属性)
MethodDescriptor[] mds = bi.getMethodDescriptors();
//返回该对象中的所有方法描述器(包括继承);

黑马程序员-Java基础总结16——高新技术Day02(JavaBean、注解与泛型)

4JavaBean(java.beans)的类与方法:

Introspector类中方法: 

BeanInfo  Introspector.getBeanInfo(Class...c)  : 通过Introspector静态方法创建BeanInfo的实例对象;


BeanInfo类中方法:

PropertyDescriptor[] getPropertyDescriptors() 获得该类对象的所有get/set方法;

MethodDescriptor[]  getMethodDescriptors()     获得该类的所有方法(包括继承)

 

PropertyDescriptor类中方法:  (反射方式获得gettersetter方法)

构造方法:  PropertyDescriptor(String propertyName,Class<?> beanClass)等;

一般方法:

 getName()  获得此特性的编程名称(该对象(getAge方法时)调用会返回"age")

 getReadMethod()    获得应该用于读取属性值的方法;

 getWriteMethod()   获得应该用于写入属性值的方法;

 setReadMethod(Method readMethod)   设置应该用于读取属性值的方法;

 setWriteMethod(Method writeMethod) 设置应该用于写入属性值的方法。


5BeanUtils工具: 封装JavaBean类中的修改/获取操作方法的工具

通过下载并导入commons-beanutils(方便操作JavaBean)commons-logging(书写日志文件包)两个工具集(jar),就可以调用BeanUtils工具中的类与方法等。

 

示例: 通过反射构造Person类对象,使用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()方法,可对属性对象中的属性值进行赋值

   前提: 要求两个类均要有get/set方法(符合JavaBean的内省规则)

:  

System.out.println(BeanUtils.getProperty(person,"date.year"));

            //打印当前日期的年份(距离1900年的差值)

BeanUtils.setProperty(person, "birthday.year","200");

           //修改birthday变量的Date对象中的year字段的值;

 

2copyProperties(Object A,Object B);复制对象,将对象B的属性复制给A

Map  describe(Objectbean)JavaBean的属性转换成Map集合格式;

【转换后格式:Map{age:7,name:"hehe"};

PS一句:网上虽然也有看到JDK1.7新特性的Map的赋值新方式,但是个人水平有限,无论是纯JDK1.7还是JDK1.7MyEclipse都没能编译通过。——有效期2013.6.2前等,呵呵】

populate(Object bean,Map properties):Map集合元素导入到JavaBean对象中;

 

7BeanUtilsPropertyUtils的区别:

APropertyUtilsBeanUtils类基本相同,区别在于BeanUtils操作方法的方式是字符串,而PropertyUtils操作方式是元素的原有类型(或其对象包装类)

例如: 

BeanUtils.setProperty(person,"age","20");//用字符串"20"来修改;

PropertyUtils.setProperty(person,"age",20);  //Integer类型值20 来修改;

【除了修改方式,两者的获取值对象的返回值也不同,BeanUtils返回值为String类型,而PropertyUtils返回值类型为元素的原有类型,例如Integer类型(可能为基本数据类型int等,不过会自动装箱成基本数据类型包装类对象)等】

 

B、应用: 

由于BeanUtils接收与返回值为String类型,所以多用于网页接收或返回打印显示等情况

PropertyUtils接收与返回值为元素原有类型可避免类型转换出错的情况,也可直接用于参与对象的运算或使用等情况。

 


————————————————注解(Annotaion)——————————————

二、注解Annotation  :JDK1.5版本开始的特性。

  注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。

  标记可以加在包,类,字段,方法,方法的参数以及局部变量上。

1Java提供的基本注解(方式):       java.lang包)

@SuppressWarnings("deprecation");  取消显示警告(JVM不再对指定方法提示警告)

@Deprecated   注解该方法已过时;

@Override     覆盖,指明该方法复写父类方法;

适用:包、类class、方法、变量、局部变量等;

 

2、自定义注解:  (创建注解类、使用注解类、反射调用使用了注解的类)

黑马程序员-Java基础总结16——高新技术Day02(JavaBean、注解与泛型)

A创建注解类: public @interface 接口名{ ......}

B添加注解属性(注解属性是个抽象方法,可添加缺省属性,例:String color() default"RED";)

:  1、在一个类上添加注解,就相当于在该类中创建了注解类的实例对象

2使用(创建)注解类时可指定注解属性,之后可在调用类中调用注解属性方法

 

3元注解: 添加在注解类上的注解(java.lang.annotation)

   1@Retention.常量指示该注释有效期限(保留多久)

常量value:   Java编程习惯,将程序调用的常量用单独的类(或枚举)封装

枚举类enumRetentionPolicy中的枚举值:

   SOURCE  编译器编译后要丢弃的注释;(:@Override@SuppressWarnings)

   CLASS   : (默认值)将注释保留至类文件中,但运行时VM不保留注释。

   RUNTIME 将注释保留至运行时,因此可以反射性地读取;(:@Deprecated)

示意图:

java源文件——(丢弃SOURCE)——>class类文件——(丢弃CLASS)——>内存字节码

PS: 丢弃XXX,意指丢弃注解有效期为XXX 的注解,在之后的程序代码中将不存在,也就失去该限制功能/作用

   2@Target.常量指示该注解使用范围(即将只能注解在哪些类的成员上)

ElementType.METHOD   只能注解在Method方法上;

TYPE               只能注解在Classinterfaceenum等类上(它们必须是TYPE)

ANNOTATION_TYPE      注解在注解类上

(还包括字段FIELD、包PACKAGE、构造方法CONSTRUCTOR)

 

PS: 1Class类中与注解(Annotation)相关的方法:

isAnnotationPresent(Annotction.class) : 该类中是否包含指定的注解类?

getAnnotation(Annotction.class)       :返回该类中指定的注解了的实例对象;

   2解析TYPE/类型:

interface Type(java.lang.reflect): Java编程语言中所有类型的公共高级接口;它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。

即可看做Type子类或子接口的有:Classinterfaceenum@interfaceJava类型。


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中增加属性: String color();

    使用该注解类时@MyAnnotation(color="red")

代码示例与解析:

@MyAnnotation(color="red")
//用反射方式获得注解对应的实例对象后,再通过该对象调用属性对应的方法
MyAnnotation ma=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
System.out.println(ma.color());

可以认为上面这个@MyAnnotationMyAnnotaion类的一个实例对象。

为属性指定缺省值 String color()default "yellow";

1value属性String name() default"zxx";

如果注解中有一个名称为value的属性,且想只设置value属性(即其他属性都采用默认值或者除非仅有value一个属性),那么可以省略“value=”部分,例如:@MyAnnotation("lhm")

 

2、数组类型的属性:

int [] arrayAttr()default {1,2,3};

使用: @MyAnnotation(arrayAttr ={2,3,4})

如果数组属性中只有一个元素,这时候属性值部分可以省略大括号。

枚举类型的属性

  EnumTest.TrafficLamp lamp();

  @MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN)

3、注解类型的属性

MetaAnnotation annotationAttr()  default@MetaAnnotation("xxxx");

使用:@MyAnnotation(annotationAttr = @MetaAnnotation(“yyy”))

可以认为上面这个@MyAnnotationMyAnnotaion类的一个实例对象,同样的道理,可以认为上面这个@MetaAnnotationMetaAnnotation类的一个实例对象,调用代码如下:

   MetaAnnotation ma = myAnnotation.annotationAttr();

   System.out.println(ma.value());

注解的详细语法可以通过看java语言规范了解,即看javalanguagespecification

4、注解的属性类型包括:基本数据类型,StringClass,枚举,其他注解,以及这些类型的数组。

————————————————迭代——————————————————

【略过,基本在基础视频课程都提及,主要是巩固下用Map.Entry<K,V>来迭代Map类集合】

 

————————————————泛型(高级应用)————————————————

四、泛型(高级应用——泛型通配符):

(1)泛型通配符

  TE:泛型通配符,具体参数类型(等待接收)

?:占位符,表示不确定类型;

? super T?extends T:泛型上下限通配符

1、通配符的使用与局限:

与 ? extends T两个泛型通配符是不能明确具体类型,所以不能调用与参数类型有关的(参数化)方法,否则程序出错(编译时或运行时都有可能出错)

: List<? extends Object>list1 = newArrayList<String>();

   //list.add("hehe");   //此添加元素方法无法通过编译;

 

? super T 有类型下限但只能接收TT的父类类型;且可调用参数化(但只能调用参数类型为T)方法

: List<? super Integer> list2= newArrayList<Number>();

    list2.add(222);    //只能添加Integer类型参数;

 

2编译去类型化通过反射给集合添加任意类型元素

代码示例    //反射添加字符串类型参数到参数类型为Integer集合;

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、参数化类型可以引用原始类型】

 例如: TreeSet ts = newTreeSet<String>();B、原始类型可以引用参数化类型】

2参数化类型不考虑类型参数的继承关系(不存在继承关系,只能使用泛型上/下限定符)

 错误示例: ArrayList<Object> al = newArrayList<String>(); //编译无法通过。

3编译器不允许创建类型变量的数组,即在创建数组实例时,数组的元素不能使用参数化的类型;

 错误示例:Vector<Integer> vcArray[] = newVector<Integer>[10];

注意:但可以通过参数化类型引用原始类型方式,来指定数组参数化类型

Vector<Integer>[] vector =new Vector[3];

 

4JVM编译时是逐行读取编译,因此处于不同行的泛型是不会自动关联的。

即示例代码 (编译可通过)

ArrayList al = newArrayList<String>();

   List<Integer> list = al;(即List<Integer> list =new ArrayList();

(PS: List是接口,不能实例化,因此当LS接收不是ArrayList,而是List,则不能赋值)

 

3)泛型使用注意事项:

1只有引用类型才能作为泛型方法的实际参数;基本数据类型是不可以,但Java自动装箱、拆箱功能能让其提升为基本数据类型对象;

2泛型限定是可以用"&"符号来指定多个边界

例如:<V extends Serializable & Comparable> void method(){ };

【指明传入的对象必须是继承或实现了SerializableComparable两接口的类型对象,例如DoubleInteger等】

3泛型(类型化变量)可以用于表示异常,称为参数化的异常,可用于方法的throwthrows异常或列表,但是不能用于catch语句

4、在泛型中是可以同时有多个类型参数,在定义它们的尖括号中用逗号分开

: public static<K,V> V getValue(K key){ returnmap.get(key); }

 

5泛型可以根据传入的类型来指定泛型的类型,但优先根据返回值类型来指明泛型

例如: Object obj = "abc";  String str = autoConvert(obj);

     private static <T> TautoConvert(Object obj){  return(T)obj; }

 

4)类型参数的类型推断:

参数传递推断(详见PPT文档或第41个视频):

(JDK1.7新特性) 示例:ArrayList<String> al = newArrayList<>();

泛型传参时有两个不同泛型值,那么因为Java的传播性(传染性),会取两个不同泛型值的交集(共同)的父类

类型形参(形式参数T)、类型实参(实际参数Integer)

 

————自定义泛型类————

【略……………

CRUD  :(Create)(Retrieve)(Update) 删(Delete)

DAO  : Data Access Object(数据访问对象)

 

————————反射获得泛型的实际参数类型———————

五、反射获得泛型的实际参数类型:

问题、应用(个人总结,不一定准确)

因为在Java编译后集合等是没有了泛型限定,或者在早期编写的代码中是没有泛型,那么我们如何获得(数据库或)集合中存储的参数类型???(特别是在没有获得某些源代码时)

 

因此通过反射获得泛型的实际类型参数。————依靠MethodParameterizedType

     通过Method方法的获取传参列表中的泛型类型,从而获得指定集合等中存储的类型参数

应用 Java框架工具中,能自动获取集合中泛型类型参数,然后可对集合中(泛型参数)元素进行转换或添加元素等操作的原理,就是基于此实现方式来获悉集合中元素是哪种泛型类型参数。

 

Method类中方法 

String toGenericString();  :返回描述此Method的字符串,包括类型参数;

(: 返回public<T> voidcom.method(java.util.Collection<T>))

Type  getGenericReturnType() :返回方法返回值的泛型类型(参数)

Type[] getGenericParameterTypes():返回方法参数列表的泛型类型数组;

【注意: 是以带泛型的参数类型返回返回值或参数列表】

 

ParameterizedType(接口)     (java.lang.reflect)

参数化类型,如Collection<String>

方法:

Type  getRawType()  :返回Type 对象,表示声明此类型的类或接口。

Type[] getActualTypeArguments()  :返回表示此类型实际类型参数的Type 对象的数组。

Type接口: class@interfaceenum.........