Java基础加强<二>_内省、注解、泛型

来源:互联网 发布:喝咖啡会难怀孕吗 知乎 编辑:程序博客网 时间:2024/05/22 14:16

Java基础加强---day02

五、内省

    JavaBeanJavaBean是一种特殊的Java类,主要用于传递数据信息,这种Java类中的方法主要用于访问私有的字段,并且方法名符合某种命名规则。当某个java类中的一些方法符合某种命名规则,那么就可以把它当做JavaBean来使用。

    如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称为值对象(Value Object)。这些信息在类中用私有字段来存储,如果要读取或者设置这些字段的值,那么需要通过一些相应的方法来访问。

    去掉前缀(set、get)后,剩下的部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改为小写的;如果第二个字母是大写的,第一个字母保留大写。

    总之:一个JavaBean类的属性名可以根据方法名推断出来,并且我们根本看不到java类内部的成员变量

    由于JavaBean广泛的应用性,Eclipse有专门的快捷键产生,即getter和setter。

    JavaBean的好处:

    1、在JavaEE开发中,经常要使用到JavaBean,很多环境要求按照JavaBean,所以JavaBean很重要!

    2、JDK中提供了对JavaBean进行操作的一些API,所以操作相对简单方便,这一套API就称为内省。

    内省:对应的英文单词为:IntroSpector,有内部视察的意思,主要用于对JavaBean的操作。java提供的API为:PropertyDescriptor。但PropertyDescriptor类对JavaBean的操作过于复杂,也可以通过导入BeanUtils工具包对JavaBean进行内省操作。

    万事万物都应该都应该用一个东西来描述,BeanInfo是专门用于描述JavaBean的一个类,也可以通过遍历BeanInfo中所有属性的方式对JavaBean进行描述,IntroSpector.getBeanInfo(<?>class),获取BeanInfo对象。但这种方法操作较为麻烦,可以作为了解。

    导入方式:选中工程,右键-->buildPath-->Configure  buildPath 然后导入相应的工具包,即可。

    产生getter和setter的方式:在类中的空白处,右键-->Source-->Generate  Getters and Setters,然后选中相应字段,即可。

    抽取方法的方式:选中要抽取成为方法的代码,右键-->refactor-->Extract Method,即可。

下面代码体现:

1、内省的演示:

package itheima.day08;import java.beans.BeanInfo;import java.beans.IntrospectionException;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import org.apache.commons.beanutils.BeanUtils;import com.sun.xml.internal.fastinfoset.sax.Properties;import itheima.day07.ReflectPoint;public class IntroSpectorTest {public static void main(String[] args) throws Exception {//提供设置、获取某个字段的类 就是JavaBeanReflectPoint pt1 = new ReflectPoint(3, 5);//获取读取一个字段的方法String propertyName = "x";Object returnValue = getProperty(pt1, propertyName);System.out.println(returnValue);//3//设置一个字段的值Object value =7;setProperty(pt1,propertyName,value);//使用BeanUtils工具包  System.out.println(BeanUtils.getProperty(pt1, "x"));//BeanUtils工具包的方法更加简便System.out.println(pt1.getX());//7//BeanUtils.setProperty(pt1, "birthday.time", "111");//级联操作 // System.out.println(BeanUtils.getProperty(pt1, "birthday.time"));  }private static void setProperty(ReflectPoint pt1, String propertyName,Object value) throws Exception {//PropertyDescriptor(String propertyName, Class<?> beanClass)PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());//获取set方法 Method methodSetX = pd2.getWriteMethod();//方法关联具体的对象methodSetX.invoke(pt1,value);}private static Object getProperty(Object pt1,String propertyName) throws IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{//操作JavaBean的API,内省//PropertyDescriptor(String propertyName, Class<?> beanClass)PropertyDescriptor pd = new PropertyDescriptor(propertyName, pt1.getClass());//获取应用于读取字段属性值的方法Method methodGetX = pd.getReadMethod();//关联具体的对象Object returnValue = methodGetX.invoke(pt1);//这是早期的做法//BeanInfo类专门用于描述JavaBeanBeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());//获取JavaBean中所有的属性值PropertyDescriptor[] pds =beanInfo.getPropertyDescriptors();Object retvalue =null;for(PropertyDescriptor pd1:pds){//寻找我们想要的字段名if(pd1.getName().equals(propertyName)){Method methodGetx1 = pd.getReadMethod();retvalue= methodGetx1.invoke(pt1);}}return returnValue;}}

六、注解

    注解:注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记;是注解是JDK1.5的一个重要新特性。

    JDK中自带有三个注解:

    1、@SupressWarning:取消编译器提出的警告,只在源文件时期中有效。

    2、@Deprecated:提示元素是过时的,直到运行期都有效。

    3、@Override:表示覆盖父类中的方法,只在源文件时期有效,只能用在方法上。

    注解相当于程序中要调用的一个类,要在源程序中应用某个注解,得先有这个注解类;好比要调用某个类,必须先开发好这个类。注解的应用结构如下图所示:


    @Retention,元注解,用在注解中的注解,有三个取值:RetetionPolicy.SOURCE、RetetionPolicy.CLASS、RetetionPolicy.RUNTIME;分别对应:java源文件、class文件、内存中的字节码。

    @Target:指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。可以是Filed(字段)、Method(方法)、Type(类型,包括类、接口、注解等)。

    注解的属性:注解本身就是给给源程序打上某种标记,则注解的属性就是标记中的标记,即更具体的标记。

下面代码演示:

注解类:

package itheima.day08;import java.lang.annotation.Retention;import java.lang.annotation.ElementType;  import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import itheima.day07.EnumTest;//源注解,指明该注解类的生命周期@Retention(RetentionPolicy.RUNTIME)//源注解,指明注解类可以用在什么类型的数据上,即使用目标@Target({ElementType.METHOD,ElementType.TYPE})public @interface ItcastAnnotation {//注解的属性String color() default "bule";String value();// 注解的属性有默认值时,应用时可以不必指定int[] arrayAttr() default {3,2,1};//带枚举的注解EnumTest.TrafficLamp lam() default EnumTest.TrafficLamp.RED;}

应用注解的类:

package itheima.day08;//使用"注解类"的类//在使用注解类时,必须给未初始化的属性赋值@ItcastAnnotation(color ="red", value = "abc")public class AnnotationTest {//取消警告@SuppressWarnings("deprecated")//只有value一个属性待赋值时,可以省略属性名@ItcastAnnotation("xyz")public static void main(String[] args) {//过时的方法System.runFinalizersOnExit(true);//MyEclipse提示该方法过时AnnotationTest.sayHello();//对使用注解类的类进行反射if(AnnotationTest.class.isAnnotationPresent(ItcastAnnotation.class)){//通过反射的形式获取到注解类ItcastAnnotation annotation = (ItcastAnnotation)AnnotationTest.class.getAnnotation(ItcastAnnotation.class);//@itheima.day08.ItcastAnnotation(color=red, lam=RED, arrayAttr=[3, 2, 1], value=abc)System.out.println(annotation);//获取到注解类之后,可以获取注解类中的属性字段System.out.println(annotation.color());System.out.println(annotation.value());System.out.println(annotation.arrayAttr().length); System.out.println(annotation.lam().nextLamp().name());  }}//给该方法打上过时的标记,使用的是JDK提供的注解类@Deprecatedpublic static void sayHello(){System.out.println("hello itheima");}}

七、泛型

    泛型:泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。

    泛型是JDK1.5的一个新特性,没有泛型时,集合中通过Object提供扩展性,但什么类型的对象都可以往同一个集合中放,这就容易引起操作集合中元素时发生一些异常。指定了泛型后,集合中只能放进特定的类型元素,提高了代码的安全性。

    泛型的特定术语:

    ArrayList<E>:泛型类型;E称为类型变量或者类型参数;

   ArrayList<Integer>称为参数化的类型;<>称为typeof;ArrayList称为原始类型。

    参数化类型可以引用一个原始类型的对象,编译报告警告;如:

    Collection<String>c = new Vector();//兼容JDK1.4以前编写的程序;

    原始类型可以引用一个参数化类型的对象,编译报告警告;

    Collectionc = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去。

    上限:? extends E。

    下限:? super E。

    关于泛型,在集合那一章中有详细的介绍,在此不再赘述!

下面代码演示:

package itheima.day08;import java.lang.reflect.Constructor;import java.util.ArrayList;import java.util.Collection;public class GenericTest {public static void main(String[] args) throws Exception {//在泛型出现之前,用Object提供扩展性//面向接口的编程Collection collection1 = new ArrayList();//使用Object提供扩展性,弊端很明显:什么东西都可以往集合中放collection1.add(1);collection1.add(1.2);collection1.add("abc");System.out.println(collection1.size());//JDK1.5版本以后,用泛型限定存入集合的类型Collection<String> collection2 = new ArrayList<String>();collection2.add("abcd");//编译通不过,把安全问题扼杀在编译时期//collection2.add(1.2);System.out.println(collection2.size());//可以使用反射技术透过编译器Constructor<String> constructor1 =String.class.getConstructor(StringBuffer.class);String str2 = constructor1.newInstance(new StringBuffer("abc"));System.out.println(str2);ArrayList<Integer> collection3 = new ArrayList<Integer>();//同一份字节码,说明字节码与泛型无关,泛型只是给编译器看门的一个道具,仅此而已System.out.println(collection2.getClass()==collection3.getClass());//true//用反射透过编译器collection3.getClass().getMethod("add", Object.class).invoke(collection3, "abc");System.out.println(collection3.get(0));}}


原创粉丝点击