黑马程序员----java基础增强下

ASP.Net+Android+IO开发S.Net培训、期待与您交流!
 (2)java反射中Constructor的描述
         constructor是代表类的构造函数的一个类,它可以获得类的构造函数的名字,参数,创建一个新的对象以及Annotation等,
   1》、根据字节码文件可以获得相应的构造函数例如String.class.getConstructor(StringBuffer.class)或者可以通过对象的str.getclass.getConstructor()方法获得对象对应的类
   的构造函数;在java.lang包下的Class类提供两个可以获得类的构造函数的方法为getConstructor(Class<?>... parameterTypes)和getConstructors(),前者是获得一个特定的
   构造函数,后者的到字节码的所有的构造函数
   2》、得到类的某一个构造函数需要知道该构造函数对应的参数列表如:
         class People{
        public People(String name){}
     public People(String name,int age){}
      }
      class Test{
         public static void main(String[] args){ Constructor con = People.class.getConstructor(String.class);//获得People类中带有一个String类型参数的构造函数
          Constructor con = People.class.getConstructor(String.class,int.class);//获得People类中带有两个参数的构造函数并且参数分别为String类型和int类型
      }
      }
      3》、我们可以通过反射方式来创建类的对象,此时我们用到Constructor类中的newInstance(Object... initargs)方法来实例化对象,(注,在Class类中也有一个newInstance())
        创建对象时我们应该明确创建该对象时所需要的参数
        如上例中的People类我们创建一个name=“zhou”的对象时只需 People p1 = con.newInstance(new String("zhou"));
    (3)java反射中Field类:该类用于描述类的属性,描述类属性是否有Annotation,属性名,得到该属性的值,设置属性是否可以Accessable等等
         1》、我们可以根据字节码获得类中定义的属性例如String.class.getField()和String.class.getDeclaredField(String name)获得属性名为name的属性
   其中getField和getFields是获得类中定义的公共属性,而getDeclaredField和getDeclaredFields是获得类中定义的所有属性
      对于类People定义如下public class People {
         private String name;
         private int age;
         private char sex;
         }
      可以通过一下格式来获得类中的属性 Field fields[] = People.class.getDeclaredFields();   for(Field field : fields){System.out.println(field);}
           2》、我们可以通过Field类的相关方法获得类属性的值,但是在取属性对应值时应先将属行的访问权限设为true
          实例代码:People p1 = People.class.getConstructor(String.class,int.class,char.class).newInstance(new String("zhangsan"),18,'F');
       Field name = People.class.getDeclaredField("name");
       name.setAccessible(true);//设置属性的访问权限
       String name1 = (String) name.get(p1);//得到对象p1的对应的name属性值也可以用getString(Object obj)方法
       System.out.println(name1);
       Field age = People.class.getDeclaredField("age");
       age.setAccessible(true);
       int ages = age.getInt(p1);
       System.out.println(ages);
                同时我们可以使用set方法为某一对象设置值例如:age.setInt(p1, 28);//第一个参数为类对象,第二个参数为索要设置的值
    3》、判断两个对象是否是一个对象,即一个类的属性是否与另一个类的属性相同使用Field类的equal方法:name.equals(p1.getClass().getDeclaredField("name"))
    (4)java反射中Method类,用于描述类的成员方法的类
   1》、Method的对象的获得,我们可以通过字节码的getMethods(),getMethod(String name, Class<?>... parameterTypes)和getDeclaredMethods()、getDeclaredMethod(String name, Class<?>... parameterTypes)
     其中前两个是获得字节码中定义的公共方法,后两个是获得字节码中定义的所有方法,针对People类我们可以通过一下方式获得它中所定义的方法
     Method[] methods = People.class.getMethods();或者得到类中定义的所有方法Method[] methods = People.class.getDeclaredMethods();
     获得类中某一特定的方法可以通过: Method method1 = People.class.getMethod("setName",String.class);
   2》、如何调用反射中产生的方法
         在Method类中提供了invoke(Object obj,object ... parmas)方法,方便我们使用利用反射得到的method,如Method getNameMethod = p1.getClass().getMethod("getName");
          String name2 = (String)getNameMethod.invoke(p1, new Object(){});  System.out.println(name2);
         注意:在jdk1.4及以前Method的invoke方法接受的对象是一个数组,当执行时,编译器先将数组拆成多个对象作为多个参数进行传递,而当某一个方法需要一个数组类型的参数时
      传入的数组参数时,编译器会将其认为多个对象,而产生一个参数数目不符的异常,我们可以通过以下两个方式来解决这个问题
       <1>、将数组封装为一个新的Object数组,这样在编译器第一次拆箱后,还是一个数组new Object[]{new String[]{"abd","abc","123"}}
       <2>、将数组通过强制类型转化为Object类型对象,这样告诉编译器这是一个对象(基本数据类型不是Object类型)
    (5)java数组的反射是用Array类,我们可以通过Class类的isArray方法判断一个类是否为数组类型,我们可以通过Array的getLength(Object obj)方法获得数组的长度,也可以通过get(Object obj,int index)
         获得数组中某一索引的值
    (6)java反射的应用:配置文件的使用,减少对源文件的修改,实现开闭原则
          实现方法有 代码//ResourceBundle rbs = ResourceBundle.getBundle("it");//在源文件目录下,编译时,虚拟机将其拷贝到class所在目录只能使用后缀为properties的文件
                        // String className = rbs.getString("className");
      InputStream isp = new FileInputStream("it.properties");//在工程目录下
      //InputStream isp = ReflectSet.class.getClassLoader().getResourceAsStream("it.properties");//在源文件目录下,编译时,虚拟机将其拷贝到class所在目录,这是使用类加载器的方式
      //
      Properties proper = new Properties();
      proper.load(isp);
      String className = proper.getProperty("className");
      Collection<Student> collection = (Collection<Student>)Class.forName(className).newInstance();
    (7)javabean的使用:javabean是符合一定规则的特殊的类,其中类的属性都是私有的并且提供公共的get和set方法,为外部使用,javabean的构造函数只有一个并且不带有任何参数
        例子public class People {
    private String name;
    private int age;
    private char sex;
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
    public int getAge() {return age;}
    public void setAge(int age) {this.age = age;}
    public char getSex() {return sex;}
    public void setSex(char sex) {this.sex = sex;}
   }
           javabean的作用:使用与传递信息(值)的用处,在javaEE中应用主要是在页面之间传递信息。我们可以通过java的内省和java反射机制来实现对javabean的操作
      People p1 = new People("zhangsan");
    //使用java的内省实现对javabean的操作
    PropertyDescriptor pd = new PropertyDescriptor(propertyName, People.class);
    //利用反射机制实现对javabean中类的调用
    Method methodGetName = pd.getReadMethod();
    对于javabean的操作我们可以使用BeanInfo的操作方法BeanInfo bi = Introspector.getBeanInfo(People.class);
               PropertyDescriptor[] pds = bi.getPropertyDescriptors();
               People p1 = new People();
               for(PropertyDescriptor pd:pds)
               {
                if(pd.getName() == "name")
                {
                 Method methodSetName = pd.getWriteMethod();
                 methodSetName.invoke(p1,new String("zhangsan"));
                 break;}}
    对JavaBean的第三种操作方法:使用BeanUtils来操作javabean  People p1 = new People("zhangsan",18,'F');
                 System.out.println(BeanUtils.getProperty(p1, "name"));
                 BeanUtils.setProperty(p1, "age", 20);//义字符串的方式对属性进行的操作
                 System.out.println(BeanUtils.getProperty(p1, "age"));
                 PropertyUtils.setProperty(p1, "age", 22);//以属性对应的类型对属性进行操作
                 System.out.println(PropertyUtils.getProperty(p1, "age"));
    7、hashcode与hashSet的关系
      hashSet集合根据hashcode值被分为若干个区域,在每个区域内其hashcode值满足一定的规律,每一个要存入的对象,根据hashcode算法算出该对象的hashcode值,再根据hashcode值将其存放到特定区域
   当要蒋某一个对象放到该集合中时,先算出其hashcode值,确定该将该对象放入到那个区域,并在该区域中查找是否有与该对象的hashcode值相等的对象,这样就提高了操作效率。但是对于hashSet集合
   就是采用hashcode算法来存取对象的,当对象中实现了hashcode方法,它会根据对象的hashcode算法来存取对象,当对象未实现hashcode时,他会根据系统默认的hashcode来存取对象,相同的对象被放在
   不同的区域内,就会造成对象重复
 8、java注解:annotation在java的lang包中有三个基本的annotation,分别为Overrider(子类重写父类的方法)、Deprecated(过时标记)、SuppressWarnings(取消一些警告)
    1》、自定义Annotation:我们也可以开发出特定功能的Annotation格式为 @ interface className{},源注解包含Retention、Target
    在定义Annotation时应该标记该Annotation应保留到啥时间才能去掉标记用Retention其中value值有三个CLASS,RUNTIME和SOURCE,其中RUNTIME表示标记保留到java文件运行时,在字节码中可以查看到标记
    信息,CLASS表示标记保留到编译时,运行时标记已经没有啦,在字节码中找不到此标记;SOURCE则是在编译器编译时就将标记丢失的标记,我们定义的标记一般是为了运行时使用,所以应该将value设置为
    RUNTIME使之在vm执行时有意义
    Target指示注释类型所适用的程序元素的种类,是属性,方法还是类等等,它对应的value值为ElementType类型的值
      Target对应的value值有ANNOTATION_TYPE(注释类型声明)、CONSTRUCTOR(构造方法声明)、FIELD(字段声明)、LOCAL_VARIABLE(局部变量声明)、METHOD(方法声明)、PACKAGE(包声明)、PARAMETER
   (参数声明)、TYPE(类、接口(包括注释类型)或枚举声明)
    实例@Retention(RetentionPolicy.RUNTIME)
   @Target(value = ElementType.FIELD)
   public @interface Cloumn {
    String color() default "red" ;//给Annotation添加属性
    String value();
   }//这是定义了一个作用在Field上的Annotation
   2》、获得相应的Annotation,利用java的反射机制我们可以的到在类,成员,变量....上的注解,javalang包下的Method,Field,Constructor类都也提供了相应的方法来获得定义在本身上的Annotation
      获得方法如下
      Field[] fields = clazz.getDeclaredFields();
   for(Field field : fields)
   {
    if(field.getAnnotations()!= null)
    {
     Cloumn clo = field.getAnnotation(Cloumn.class);//获得定义在Field上的Annotation
     String value = clo.value();
     String color = clo.color();
     System.out.println(value + "\t"+color);
    }
   }
  定义在类上的Annotation的获得 TypeAnnotation annot = (TypeAnnotation)clazz.getAnnotation(TypeAnnotation.class);//此时TypeAnnotation是定义在类,接口或者枚举类型上的Annotation
                                     System.out.println(annot.value()); 
   3》、可以定义特殊的属性:如 int[]类型 也可以有默认值用default{1,2,3}获得后可以通过反射得到数组中的值
   4》、可以定义一个枚举类型的属性,如WeekDay也可设置默认值
   5》、也可以定义一个注解类型的属性
 9、java泛型是java提供给集合类来约束集合类中元素类型的一种技术,在执行javaC以后,编译器会将泛型去掉,同样泛型也可以方法定义是作为形参来使用
     例如List<String> list = new ArrayList<String>();方法的定义中作形参public void update(T t)throws SQLException;这是在数据库操作是使用的,这里主要是通过java的反射机制,来拼接一个sql
  语句使用到的
  注意1、参数化类型与原始类型具有兼容性 1>、参数化类型可以引用一个原始类型的对象,如List<String> list = new ArrayList();2>、原始类型也可以引用一个参数化类型对象,如List list = new ArrayList<String>()
  此时list对象中只能存放String类型的数据
      2、参数化类型不考虑类型参数的继承关系 对于以下两种格式都是错误的 Vector<String> vector = new Vector<Object>();和Vector<Object> vector = new Vector<String>();
   3、在创建数组实例时,数组的原素不能使用参数化类型,例如List<String> list[] = new ArrayList<String>[10]
     1》、?泛型中的通配符,根据注意中第2条可以知道在泛型中参数不能进行类型的转化,所以引入了通配符?
       private static void printList(List<?> list) {//其中list的参数可以是任何类型,?代表任意类型
    for(int i = 0 ; i<list.size();i++)
    {
     System.out.println(list.get(i));
    }
   }在使用?通配符可以引用其他的各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法
  2》、通配符的扩展 java中对通配符的定界,有限定通配符的上边界用extends,限定?的下边界用super,这样就指定了?所代表的类型必须是super后类型的父类或者是super后类型
       Vector<? extends Number> x = new Vector<Double>();这是限定集合的上边界,如果?代表的类型不是Number的子类,则会报错,因为x中只能存放Number子类型的对象。
     Vector<? super Number> x = new Vector<Number>();Vector<? super Number> x1 = new Vector<Double>();前面一个方法是正确的,后者因为Double是Number的子类,错误
     注意:我们不能将带有通配符的集合赋值给一个固定类型的集合  
ASP.Net+Android+IO开发S.Net培训、期待与您交流!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值