黑马程序员—java高新技术(2)

来源:互联网 发布:ipad mini2 优化设置 编辑:程序博客网 时间:2024/04/29 19:58

JavaBean内省

         英文:IntroSpector

         作用:对JavaBean进行操作。

        

         JavaBean:属性xxx,get方法getXxx(),set方法setXxx();

         属性描述符:PropertyDescriptor

         StringpropertyName = “x”;

         PropertyDescriptorpd = new PropertyDescriptor(propertyName,对象的class);

         MethodmethodGetX = pd.getReadMethod();

         ObjectretVal = methodGetX.invoke(对象);//调用对象的get方法,返回属性值

         MethodmethodSetX = pd.getWriteMethod();

         methodSeX.invoke(对象,属性值);//调用对象的set方法,设置属性值

         Introspector类的getBeanInfo方法返回BeanInfo对象。

         BeanInfo对象的getPropertyDescriptors方法返回属性描述符数组。

BeanUtils工具包

         Apache的开源项目;

         BeanUtils:会将类型转换为字符串。

         PropertyUtils:会得到属性原始的类型。

         该工具包可以对属性链式设置值。

注解(Annotation)

      JDK提供的基本注解:

1.      @Deprecated:说明某个方法,属性或者类已经被废弃,建议不要使用。

2.      @Override:让编译器检查某个方法是否是重写了父类的方法。

3.      @SuppressWarnings:让编译器在编译时不提示警告。

总结:注解就相当于一种标记,在程序中加了注解就等于打上了某种标记,没加,则等于没有某种标记,以后,javac编译器,开发工具,和其他程序可以用反射来了解你的类及各种元素上有何种标记,看你有什么标记,就去干相应的事。标记可以加载包,类,字段,方法,方法的参数以及局部变量上。

元注解:

@Retention(RetentionPolicy.RUNTIME):说明被该Annotation注解的Annotation会把注解的信息保留在内存中的字节码中

注解的三个生命周期:

                  RetentionPolicy.RUNTIME:字节码阶段//@Deprecated

                  RetentionPolicy.CLASSclass文件中

                  RetentionPolicy.SOURCEjava源文件中//@Override,@SuppressWarnings

@Target:注解作用于类的哪个成分,值为ElementType枚举值

          Target的默认值为任何元素。

为注解增加属性:

public@interface MyAnnotation{

         String color();//为注解增加了color属性,使用时@MyAnnotation(color=”red”)

         String value();//特殊属性,在使用时可以不用写属性名。

}

可以为属性添加默认值:Stringcolor() default “red”;

数组属性使用方式:属性名={value1,value2};

注解类型的属性:假设有元注解类型@MetaAnnotation

MetaAnnotationannotationAttr() default @ MetaAnnotation(“”);//设置默认值方式。

泛型

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

ArrayList<Integer>a = new ArrayList();

ArrayList<String> b = newArrayList();

System.out.println(a.getClass()== b.getClass());//同一份字节码

System.out.println(a.getClass());//返回java.util.ArrayList

参数化类型不考虑类型参数的继承关系:

Vector<Object>v = new Vector<String>();//错误

Vector<String>v = new Vector<Object>();//也错误

这两个类型是没有转化关系的类型。改成如下即可:

Vector v = newVector<String>();

Vector<Object>v2 = v;

泛型的通配符扩展应用

“?”表示任意类型。

使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。

限定通配符的上边界:

         正确:Vector<? Extends  Number> x = new Vector<Integer>();

         错误:Vector<? Extends  Number> x = new Vector<String>();

限定通配符的下边界:

         正确:Vector<? super   Integer> x = new Vector<Number>();

         错误:Vector<? super   Integer > x = new Vector<Byte>();

提示:限定通配符总是包括自己。


泛型方法定义:

public static<T> T add(T x, T y){

}

用于放置泛型的类型参数的尖括号应出现在方法的其他所有修饰符之后和在方法的返回值类型之前,也就是紧邻返回值之前。按照惯例,类型参数通常用单个大写字母表示。

只有引用类型才能作为泛型方法的实际参数。

除了在应用泛型时可以使用extends限定符,在定义泛型时也可以使用extends限定符。

普通方法,构造方法,和静态方法中都可以使用泛型。编译器也不允许创建类型变量的数组。

也可以用类型变量表示异常,成为参数化的异常,可以用于方法的throws列表中。但是不能catch子句中。

在泛型中可以同时有多个类型参数。在定义他们的尖括号中用逗号分隔。

泛型方法练习

强制转化类型:

public static <T> T autoConvert(Object obj){

         return (T)obj;

}

调用:Object obj= “ddd”;

String x = autoConvert(obj);

当一个类型变量用来表达两个参数之间后者参数和返回值之间的关系时,即同一个类型变量在方法签名的两处都被使用,或者类型变量在方法体代码中也被使用而不是仅在签名的时候使用,才需要使用泛型方法。

注意:

1.      在对泛型类型进行参数化时,类型参数的实例必须是引用类型,不能是基本类型。

2.      当一个变量被声明为泛型时,只能被实例变量和方法调用(还有内嵌类型),而不能被静态变量和静态方法调用。因为静态成员是被所有参数化的类所共享的,所以静态成员不应该有类级别的类型参数。

获得方法的参数化类型:

         public class ReflectTest {

      public static void main(String[]args) throws Exception {

Method method= ReflectTest.class.getMethod("add",Vector.class);

         Type[] types  = method.getGenericParameterTypes();

         ParameterizedType pType = (ParameterizedType)types[0];

         System.out.println(pType.getRawType());                                                System.out.println(pType.getActualTypeArguments()[0]);

      } 

      public static void add(Vector<Date>obj){

     

      } 

}

自定义泛型:

Java的泛型是从C++的模板函数借鉴过来的,但是Java的泛型没有C++的泛型强大,

这是由于Java虚拟机设计的原因;但是它还是尽量去模仿C++的泛型。

那么C++里面是怎么解决泛型的?

如下函数的结构很相似,仅类型不同:

int add(int x,int y) {

return x+y;

 }

float add(float x,float y) {

return x+y;

}

double add(double x,double y) {

return x+y;

}

C++用模板函数解决,只写一个通用的方法,它可以适应各种类型,示意代码如下

template<class T>   //T就代表类型不祥,可以是任意类型。 

T add(T x,T y) {  

 return (T) (x+y);

}

自定义泛型方法的练习与类型推断总结

泛型方法的练习题:

1、编写一个泛型方法,自动将Object类型的对象转换成其他类型。

public static <T> T autoConvertType(Object obj){  

return (T)obj;

}


2.交换数组中的两个元素的位置的泛型方法语法定义如下:

private static <T> void swap(T[] a,int i,int j){

T temp = a[i];

a[i] = a[j];

a[j] = temp; 

}

3.定义一个方法,可以将任意类型的数组中的所有元素填充为相应类型的某个对象。

public static <T> void fillArray(T[] arr,T element){  

for(int i = 0; i < arr.length; i++)

arr[i] = element;  

}

4.

定义一个方法,把任意参数类型的集合中的数据安全地复制到相应类型的数组中。

这个需要使用泛型方法进行定义,如果使用如下形式:static void copy(Collection a, Object[] b);就会有可能出现A类型的数据复制进B类型的数组中的情况。

使用泛型方法的定义形式为:static <T> void copy(Collection<T> a,T[] b);就没有这个问题。


5.定义一个方法,把任意参数类型的一个数组中的数据安全地复制到相应类型的另一个数组中。

   copy1(new Vector<String>(),new String[10]);

   copy2(new Date[10],new String[10]);//类型推断,T为Date数组和String数组的组合类型--》Object数组

//copy1(new Vector<Date>(),new String[10])这个时候就不类型推断了。

  //为Vector<>使用了泛型,为Vector的泛型指向了一个Date,那么就说明了那个T就是个Date了。

//在对Vector<>进行参数化的时候,指明为Date,就说明了T就是个Date。那么String类型就对不上了。所以会报错。

 

private static<T> void copy2(T[] dest, T[] src) {


}

private static<T> void copy1(Collection<T> dest, T[] src) {

}







0 0