黑马程序员-Java高新技术笔记1

来源:互联网 发布:mac无法打开文件夹 编辑:程序博客网 时间:2024/06/05 18:42

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ---------------------- 

01、课程价值与目标介绍

1、课程大纲:

1.eclipse的使用技巧

2.静态导入

3.可变参数与for循环增强

4.基本数据类型的自动拆箱与装箱

5.枚举

6.反射

7.JavaBean内省

8.beanutils工具包

9.注解

10.泛型

11.类加载器

12.代理

13.线程并发库

 

02、Eclipse的使用技巧

1.IDE开发工具都支持使用工程化方式管理一个项目的程序开发过程,一般来说一个相对独立的项目就是一个工程,一个项目中涉及的多个java文件,资源文件等用一个工程进行管理。(在这里可以看看以前工作间中的某个工程的结构),在不使用工程管理的情况下,如果一个项目中包括多个Java源文件,编程人员需要精心维护这些源文件之间、以及源文件与其它文件的目录关系,需要逐一编译这些源文件,需要手工启动运行编译后的结果。如果将一个程序的所有源文件用一个工程来组织,开发工具能对所有源文件集中管理,记住每个源文件的位置和相互关系。工程中有哪几个源文件、启动类是哪个、启动参数设置等配置信息在工程中都记录。

 一个workspace可以包含多个project,一个workspace保留了eclipse的一套环境选项的配置,例如,所使用的javac和java命令,等等,细节请查看window->preferences。如果要为eclispe再配置一套环境选项,可以再创建一个workspace。Package explorer视图窗口中的filters菜单项,可以显示空的父包(此功能默认是关闭的)。

2.一个Perspective代表了若干个view的集合,如何显示各种view。

3.设置单个工程的javac和java,选择工程,右键->properties可以设置javac,右键->run asopen run dialog可以设置java。

    先用新的工作间,然后创建新工程,默认的语言即为5.0。先使用Integer  x = 3;调整编译器的语法版本为1.4,看到eclipse窗口报错了。然后将这个工程的语言设置为6.0,马上又看到bad version .class运行错误了,这是因为myeclise自带的java为1.5 。然后再将整个工作间的javac设置为6.0(eclipse自带的是jdk1.5),然后看新建工程的javac,也随之改成了6.0,运行则又报bad version .class错误。将工程的编译语言再单独改为5.0,运行则没了问题。整个工作间的语言设置为6.0后,再将整个工作间的java也设置为自己安装的java6。

 

4.快捷键使用技巧:快捷键的位置:General->keys,设置alt+/键(丁:content a 就会搜索出)进行内容提示时,要注意解除alt+/键原来的绑定关系,直接输入alt+/就可以找到它的绑定关系,删除绑定关系时也可以使用removebinding这个按钮,课后必须教会大家在eclipse中。代码模板的设置位置:java->editor->Templates

 

03_Eclipse工程管理与快捷键配置

1、首选项:Window-->Preferences(首选项)-->Java-->Compiler(编译器) && Installed JREs(运行器)

 

2、新建工程Workspace:File-->Switch Workspace-->Other-->Workspace1

待Eclipse重新启动后,即可创建Java工程:File-->New-->Project-->JavaProject-->Project name:staticimport,其余默认,点击Finish即可

Perspective:透视图

3、新建Package:在staticimport工程的src目录下单击右键-->New-->Class->Packege:com.itheima.day1       Name:StaticImport

 

4、重构工程名称:在staticimport上单击鼠标右键-->Refactor-->Rename-->New Name:javaenhance

 

5、更改Eclipse中字体大小:Window-->Preferences-->General-->Appearance-->Colors andFonts

 

6、快速输出快捷键设置:Window-->Preferences-->General-->Keys-->在输入框中输入“content a”,选择Content Assist项目,然后解除绑定:Remove Command(Unbind Command)-->Binding:Alt+/-->Apply即可,如果还有其余快捷键与“Alt+/”有绑定的,则需要先将其解除绑定,确定即可,这是在Java项目的状态下输入syso即可弹出System.out.println();输出命令行。

 

04_Eclipse视图管理与程序调试、编译与运行环境

1、编译器和运行器必须保持一致,否则就会报错:Java.lang.UnsupportedClassVersionError:Badversion number in .class file

2、高版本的java可以运行低版本的javac编译的程序;而低版本的java则不能运行高版本的javac编译的程序

 

05_在Eclipse中配置java模板代码

1、新建java模板:Window-->Preferences-->Java-->Editor-->Templates(模板)-->New-->Name:tryf   Pattern:try{

   ${line_selection}

}

finally{

   ${cursor}

}

-->Apply-->OK即可,运用的时候可以选中需要try的语句,单击鼠标右键:Surround With-->tryf()

 

06_在Eclipse中导入已有的工程

1、导入工程:首先将需要导入的工程拷贝到Workspace1的根目录下,然后在Eclipse中选择File-->Import-->General-->ExistingProjects into Workspace-->Next-->Select root directory:选择需要导入的文件根目录,Finish完成即可。

 

07_Java5的静态导入与编译器语法设置

1、import语句可以导入一个类或某个包中的所有类

2、import static语句导入一个类中的某个静态方法或所有静态方法

语法举例:

import static java.lang.Math.max;//静态导入java.lang.Math包中的某一个方法

import static java.lang.Math.*; //静态导入java.lang.Math包中的所有方法,一般建议使用导入相对应包中的方法,提高程序运行效率;

 

08_可变参数(VariableParameter)与OverLoad相关面试题分析

1、问题:一个方法接受的参数个数不固定,例如:

System.out.println(countScore(2,3,5));

System.out.println(countScore(1,2,3,5));    

2、可变参数的特点:

1. 只能出现在参数列表的最后;

2. ...位于变量类型和变量名之间,前后有无空格都可以;

3. 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。

3、代码演示:

package com.itheima.day1; public class VariableParameter {    /**    * @param args    */   public static void main(String[] args) {      // TODO Auto-generated methodstub      System.out.println(add(2,3));      System.out.println(add(2,3,5));   }   public static int add(int x,int ...args){      int sum = x;      for(int i=0; i<args.length; i++){         sum = sum+args[i];      }      return sum;   }}

09_Java5的增强for循环

注释快捷键:ctrl+Shift+/

1、语法:

for ( type 变量名:集合变量名 )  { … }

2、注意事项:

1.迭代变量必须在( )中定义!

2.集合变量可以是数组或实现了Iterable接口的集合类

3、举例:

       

       public static int add(int x,int ...args){              intsum = x;              for(intarg:args) {                     sum += arg;              }              returnsum;       }

 

10_基本数据的自动拆箱及享元设计模式(flyweight)

1、自动装箱:

Integer num1 = 12;

2、自动拆箱:

System.out.println(num1 + 12);

3、基本数据类型的对象缓存:

Integer num1 = 12;

Integer num2 = 12;        这块相等,<=127都是真的

System.out.println(num1 == num2);

 

Integer num3 = 129;               这块不相等,因为是对象,Integer取值范围为:-128-127

Integer num4 = 129;

System.out.println(num3 == num4);

 

Integer num5 = Integer.valueOf(12);

Integer num6 = Integer.valueOf(12) ;   这块的道理同上

System.out.println(num5 == num6);

 

11_枚举的作用介绍

1、为什么要有枚举

问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。

枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

 

12_用普通类模拟枚举的实现原理

用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能。

1.私有的构造方法

2.每个元素分别用一个公有的静态成员变量表示

3.可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。

 

EnumTest.java代码演示:

package com.itheima.day1;public class EnumTest {   public static void main(String[] args) {      WeekDay weekDay = WeekDay.Mon;      System.out.println(weekDay.nextDay());   }}

WeekDay.java代码演示:

package com.itheima.day1; public abstract class WeekDay {   private WeekDay(){}   public final static WeekDay Sun =new WeekDay(){      @Override      public WeekDay nextDay() {         // TODO Auto-generated methodstub         return Mon;      }   };   public final static WeekDay Mon =new WeekDay(){      @Override      public WeekDay nextDay() {         // TODO Auto-generated methodstub         return Sun;      }   };   public abstract WeekDay nextDay();/* public WeekDaynextDay(){      if(this==Sun){         return Mon;      }      else {         return Sun;      }    }*/   public String toString(){      return this==Sun?"Sun":"Mon";   }}


13_Java5枚举的基本应用

枚举的基本应用

举例:定义一个Weekday的枚举。

扩展:枚举类的values,valueOf,name,toString,ordinal等方法(记住,讲课时要先于自定义方法前介绍,讲课更流畅)

总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,例如可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()。

代码演示:

package com.itheima.day1;public class EnumTest {   public static void main(String[] args) {           WeekDay weekDay2 = WeekDay.FRI;      System.out.println(weekDay2);      System.out.println(weekDay2.name());      System.out.println(weekDay2.ordinal());//获取其索引位      System.out.println(WeekDay.valueOf("SUN").toString());      System.out.println(WeekDay.values().length);//获取其数组长度   }   public enum WeekDay{      SUN,MON,TUE,WED,THI,FRI,SAT;   }}


14_实现带有构造方法的枚举

枚举的高级应用

1、枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。

2、枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。

3、带构造方法的枚举

1.构造方法必须定义成私有的

2.如果有多个构造方法,该如何选择哪个构造方法?

3.枚举元素MON和MON()的效果一样,都是调用默认的构造方法。

4、带抽象方法的枚举

1.定义枚举TrafficLamp

2.实现普通的next方法

3.实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。

4.增加上表示时间的构造方法

5、枚举只有一个成员时,就可以作为一种单例的实现方式。

 

代码演示:

package com.itheima.day1;public class EnumTest {   public static void main(String[] args) {      WeekDay weekDay2 = WeekDay.FRI;      System.out.println(weekDay2);   }   public enum WeekDay{      SUN(1),MON(),TUE,WED,THI,FRI,SAT;      private WeekDay(){System.out.println("first");}//空参数类型的构造函数      private WeekDay(int day){System.out.println("second");}//带有参数类型的构造函数   }}


15_实现带有抽象方法的枚举

代码演示:

package com.itheima.day1;import java.util.public class EnumTest {   public static void main(String[]       new Date(300){};   }   //带有抽象方法的枚举——交通灯   public enum TrafficLamp{      RED(30){         public TrafficLamp nextLamp(){            return GREEN;         }      },      GREEN(45){         public TrafficLamp nextLamp(){            return YELLOW;         }      },      YELLOW(5){         public TrafficLamp nextLamp(){            return RED;         }      };      public abstract TrafficLamp nextLamp();      private int time;      private TrafficLamp(int time){         this.time = time;      }   }}


16_透彻分析反射的基础_Class类

反射的基石-->Class类

1、 Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。

 

2、对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?

人Person

Java类Class

 

3、对比提问: Person类代表人,它的实例对象就是张三,李四这样一个个具体的人, Class类代表Java类,它的各个实例对象又分别对应什么呢?

1.对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。

2.一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对象显然具有相同的类型,这个类型是什么呢?

 

4、如何得到各个字节码对应的实例对象( Class类型)

1.类名.class,例如,System.class

2.对象.getClass(),例如,new Date().getClass()

3.Class.forName("类名"),例如,Class.forName("java.util.Date");

 

5、九个预定义Class实例对象:

分别是boolean、byte、char、short、int、long、float、double和void

参看Class.isPrimitive(判定指定的 Class 对象是否表示一个基本类型)方法的帮助

int.class == Integer.TYPE

 

6、数组类型的Class实例对象

Class.isArray()

总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…

 

常见Class方法:

Class<?>[] getInterfaces() 获取自己实现的多个接口

Method getMethods()     获取自己所有的方法列表

String getName()   获取类名

Package getPackege()    获取自己所属的包

 

 

17_理解反射的概念

1、反射就是把Java类中的各种成分映射成相应的java。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field、Method、Contructor、Package等等。

2、一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例对象后有什么用呢?怎么用呢?这正是学习和应用反射的要点。

 

18_构造方法的反射应用

1、Constructor类代表某个类中的一个构造方法

2、得到某个类所有的构造方法:

例子:Constructor [] constructors=Class.forName("java.lang.String").getConstructors();

3、得到某一个构造方法:

例子:  

Constructor constructor=Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);//获得方法时要用到类型

4、创建实例对象:

1.通常方式:String str = new String(new StringBuffer("abc"));

2.反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));

       //调用获得的方法时要用到上面相同类型的实例对象

Class.newInstance()方法:

例子:String obj =(String)Class.forName("java.lang.String").newInstance();

该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。

该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。

 

代码演示:

package com.itheima.day1;import java.lang.reflect.Constructor;public class ReflectTest {   public static void main(String[] args)throws Exception {      // TODO Auto-generated methodstub           //new String(new StringBuffer("abc"));      Constructor constructor1 = String.class.getConstructor(StringBuffer.class);//这里的StringBuffer是选择哪个构造方法      String str2 = (String)constructor1.newInstance(/*"abc"*/new StringBuffer("abc"));//这里的StringBuffer是指要用StringBuffer的时候必须传递一个StringBuffer进去      //这里编译器只知道constructor1是一个构造方法,但不知道是谁的构造方法,因此这里需要进行强制转换成String类型的即可。           System.out.println(str2.charAt(2));      //小结:程序编程分为编译和运行时期两个阶段,编译器只看代码的定义不看代码的运行      //1.得到方法的时候需要参数类型;2.用这个方法去调用这个函数的时候同样需要调用同样类型的对象   }}


19_成员变量的反射

1、Field类代表某个类中的一个成员变量

2、演示用eclipse自动生成Java类的构造方法

3、问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。

4、示例代码:

      

ReflectPoint pt1 = new ReflectPoint(3,5);

      Field fieldY= pt1.getClass().getField("y");

      //fieldY的值是多少?是5?错!fieldY不是对象身上的变量,而是类上,要用它去取某个对象上对应的值

      System.out.println(fieldY.get(pt1));

     

      //获取y的值

      //Field fieldX =pt1.getClass().getField("x");//getField()只能获取可见参数,例如public可获取,而private则不能获取

      Field fieldX = pt1.getClass().getDeclaredField("x");//获取可见所有参数(字段),权限足够大

      fieldX.setAccessible(true);//将fieldX设置为可以访问,才能获取其值

      System.out.println(fieldX.get(pt1));//暴力反射

快捷键:Alt + Shift + S  -->产生想对应的构造方法Generate Constructor using Fields

 

20_成员变量反射的综合案例

需求:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。

ReflectPoint.java 演示包:

package com.itheima.day1; public class ReflectPoint {   private int x;   public int y;     public String str1 = "ball";   public String str2 = "basketball";   public String str3 = "itcast";     public ReflectPoint(int x,int y) {      super();      this.x = x;      this.y = y;   }    @Override   public String toString() {      return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ",str3="            + str3 + "]";   }  }


package com.itheima.day1; import java.lang.reflect.Constructor;import java.lang.reflect.Field; public class ReflectTest {   public static void main(String[] args)throws Exception {      // TODO Auto-generated methodstub        changeStringValue(pt1);      System.out.println(pt1);   }     //反射综合案例,重点掌握   public static void changeStringValue(Object obj)throws Exception{      Field[] fields = obj.getClass().getFields();      for(Field field : fields){         //if(field.getType().equals(String.class)){         if(field.getType()/*获取自己的类型*/ == String.class){            //由于比较的是同一份字节码,因此这里只能用"=="而不能用equals进行比较            String oldValue = (String)field.get(obj);            String newValue = oldValue.replace('b','a');//将旧值替换成新值            field.set(obj,newValue);         }      }   } }


21_成员方法的反射

1、Method类代表某个类中的一个成员方法

2、得到类中的某一个方法:

例子:       Method charAt =Class.forName("java.lang.String").getMethod("charAt",int.class);

3、调用方法:

通常方式:System.out.println(str.charAt(1));

反射方式:System.out.println(charAt.invoke(str, 1));

如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法!

4、jdk1.4和jdk1.5的invoke方法的区别:

Jdk1.5:public Object invoke(Object obj,Object... args)

Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。

面向对象:只要把对象变成私有private,如果谁要操作这个对象,那么这个方法就应该作用到谁的身上,专家模式。

 

代码演示:

package com.itheima.day1;import java.lang.reflect.Method; public class ReflectTest {   public static void main(String[] args)throws Exception {      // TODO Auto-generated methodstub      String str1 = "abc";      //str1.charAt(1);      Method methodCharAt = String.class.getMethod("charAt",int.class);      System.out.println(methodCharAt.invoke(str1,1));//invoke表示调用某某的方法      System.out.println(methodCharAt.invoke(str1,newObject[]{2}));//按照JDK1.4的特点进行调用        } }


22_对接收数组参数的成员方法进行反射

用反射方式执行某个类中的main方法

1、目标:

写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,大家要明白为什么要用反射方式去调啊?

2、问题:

启动Java程序的main方法的参数是一个字符串数组,即public static voidmain(String[] args),通过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mainMethod.invoke(null,newString[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它当作jdk1.5的语法解释,因此会出现参数类型不对的问题。

3、解决办法:

mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});

mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了

 

代码演示:

 

package com.itheima.day1; import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method; public class ReflectTest {    /**    * @param args    */   public static void main(String[] args)throws Exception {      // TODO Auto-generated methodstub         //TestArguments.main(newString[]{"111","222","333"});//使用静态方法调用main函数      String startingClassName = args[0];      Method mainMethod = Class.forName(startingClassName).getMethod("main",String[].class);      //mainMethod.invoke(null, new Object[]{newString[]{"111","222","333"}});      mainMethod.invoke(null, (Object)new String[]{"111","222","333"});      //每个数组的父类都是Object,这里可以利用new Object[]{}实例对象将new String[]{}进行封装,避免出错      //这里的第二种方法是直接在其前面加上(Object),首先是告诉编译器这里只是一个Object对象,其次就是强行将其转换成Object对象        }} /*选中TestArguments,按F2快捷键,弹出其所属对象,复制后,接着点击右键-->Run as-->Run Configurations-->Arguments-->Programarguments:com.itheima.day1.TestArguments-->Apply--Run即可*/ class TestArguments{   public static void main(String[] args){      for(String arg : args){         System.out.println(arg);      }   }}


23_数组与Object的关系及其反射类型

数组的反射

1、具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。

2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。

3、基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。

4、Arrays.asList()方法处理int[]和String[]时的差异。

5、Array工具类用于完成对数组的反射操作。

代码演示:

package com.itheima.day1; import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.Arrays; public class ReflectTest {   public static void main(String[] args)throws Exception {      // TODO Auto-generated methodstub         int[] a1 = newint[]{1};      int[] a2 = newint[4];      int[][] a3 = new int[2][3];      String[] a4 = new String[]{"a","b","c"};      System.out.println(a1.getClass() == a2.getClass());      //System.out.println(a1.getClass() ==a3.getClass());      //System.out.println(a1.getClass() ==a4.getClass());      System.out.println(a1.getClass().getName());      System.out.println(a1.getClass().getSuperclass().getName());//获取其父类名称      System.out.println(a4.getClass().getSuperclass().getName());           Object aObj1 = a1;      Object aObj2 = a4;      //Object[] aObj3 = a1;      Object[] aObj4 = a3;      Object[] aObj5 = a4;           System.out.println(a1);      System.out.println(a2);      System.out.println(Arrays.asList(a1));      System.out.println(Arrays.asList(a4));        }}

小结:[I:正中括号表示数组,而I则表示是整数

 

24_数组的反射应用

Array工具类用于完成对数组的反射操作。

代码演示:

package com.itheima.day1; import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.Arrays; public class ReflectTest {   public static void main(String[] args)throws Exception {      // TODO Auto-generated methodstub      printObject(a4);      printObject("xyz");     //获取数组中的元素类型      Object[] aa = new Object[]{"a",1};      System.out.println(aa[1].getClass().getName());        }     private static void printObject(Object obj) {      // TODO Auto-generated methodstub      Class clazz = obj.getClass();      if(clazz.isArray()){         for(int x=0; x<Array.getLength(obj); x++){            System.out.println(Array.get(obj, x));         }      }      else{         System.out.println(obj);      }   }}
小结:从Object[] a = new Object[](“a”,1);中分析得知,我们无法直接获取a这个元素的类型,但是我们可以通过获取其其中某一个元素的字节码名称而得知,即:a[0].getClass().getName()

 

25_ArrayList、HashSet的比较以及Hashcode分析

代码演示:

package com.itheima.day1; import java.util.ArrayList;import java.util.Collection;import java.util.HashSet; public class ReflectTest2 {    /**    * @param args    */   public static void main(String[] args) {      // TODO Auto-generated methodstub      //Collection collections = new ArrayList();      Collection collections = newHashSet();      ReflectPoint pt1 = new ReflectPoint(3,3);      ReflectPoint pt2 = new ReflectPoint(5,5);      ReflectPoint pt3 = new ReflectPoint(3,3);           collections.add(pt1);      collections.add(pt2);      collections.add(pt3);      collections.add(pt1);           pt1.y = 7;      collections.remove(pt1);//内存泄露,这里的pt1是移除不掉的,因为其Hashcode地址值已变           System.out.println(collections.size());   } }


package com.itheima.day1; public class ReflectPoint {   private int x;   public int y;   public ReflectPoint(int x,int y) {      super();      this.x = x;      this.y = y;   }    @Override   public int hashCode() {      final int prime = 31;      int result = 1;      result = prime * result + x;      result = prime * result + y;      return result;   }    @Override   public boolean equals(Object obj) {      if (this == obj)         return true;      if (obj == null)         return false;      if (getClass() !=obj.getClass())         return false;      ReflectPoint other = (ReflectPoint) obj;      if (x != other.x)         return false;      if (y != other.y)         return false;      return true;   }}


26_框架的概念以及用反射技术开发框架的原理

反射的作用-->实现框架功能

1、框架与框架要解决的核心问题

我做房子卖给用户住,由用户自己安装门窗和空调,我做的房子就是框架,用户需要使用我的框架,把门窗插入进我提供的框架中。框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。

2、框架要解决的核心问题

我在写框架(房子)时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你以后写的类(门窗)呢?

因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new 某个类的实例对象了,而要用反射方式来做。

3、综合案例

1.先直接用new  语句创建ArrayList和HashSet的实例对象,演示用eclipse自动生成 ReflectPoint类的equals和hashcode方法,比较两个集合的运行结果差异。

2.然后改为采用配置文件加反射的方式创建ArrayList和HashSet的实例对象,比较观察运行结果差异。

3.引入了elipse对资源文件的管理方式的讲解。

 

代码演示:

package com.itheima.day1; import java.io.FileInputStream;import java.io.InputStream;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Properties; public class ReflectTest3 {    public static void main(String[] args)throws Exception{      // TODO Auto-generated methodstub           InputStream ips = new FileInputStream("config.properties");      Properties props = new Properties();      props.load(ips);      ips.close();      String className = props.getProperty("className");           Collection collections = (Collection)Class.forName(className).newInstance();           //Collection collections = new ArrayList();           ReflectPoint pt1 = new ReflectPoint(3,3);      ReflectPoint pt2 = new ReflectPoint(5,5);      ReflectPoint pt3 = new ReflectPoint(3,3);           collections.add(pt1);      collections.add(pt2);      collections.add(pt3);      collections.add(pt1);           System.out.println(collections.size());   } }

config.properties文件:

className=java.util.HashSet

注意:这里在建立config.properties文件的时候,需要在javaenhance工程上单击右键,新建File文件,而其自动生成的文件则在JRE文件目录下,因此可以避免其余错误


27_用类加载器的方法管理资源和配置文件

1.getRealPath();//金山词霸//内部

一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的。

2.类加载器可以将.class文件加载到内存当中去

3.配置文件一定要放在classpath执行路径下

注意:配置文件一定要区分相对路径和绝对路径,否则很容易出错


28_由内省引出JavaBean的讲解

1、JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

 

2、如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象通常称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问,大家觉得这些方法的名称叫什么好呢?JavaBean的属性是根据其中的setter和getter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它存到哪个变量上,用管吗?如果方法名为getId,中文意思即为获取id,至于你从哪个变量上取,用管吗?去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。

setId()的属性名id

isLast()的属性名last

setCPU的属性名是什么?CPU

getUPS的属性名是什么?UPS

总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

一个符合JavaBean特点的类可以当作普通类一样进行使用,但把它当JavaBean用肯定需要带来一些额外的好处,我们才会去

 

3、了解和应用JavaBean!好处如下:

1.在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么挑选的余地!

2.JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。

 

InstroSpector:内省,检查视察的意思,主要对JavaBean进行操作,其中JavaBean是一个特殊的Java类

 

4、JavaBean的常规代码演示:

class Person {private int x;public int getAge() {return x;}public void setAge() {this.x = age;}}


5、Age --> 如果第二个字母是小的,则把第一个字母变成小的-->age

例如:

gettime-->time       setTime-->time      getCPU-->CPU

 

29_对JavaBean的简单内省操作

代码演示:

package com.itheima.day1; import java.beans.IntrospectionException;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method; public class IntroSpectorTest {    public static void main(String[] args)throws Exception {      // TODO Auto-generated methodstub      ReflectPoint pt1 = new ReflectPoint(3,5);           String propertyName = "x";      //原始处理方法就是:"x"-->"X"-->"getX"-->MethodGetX-->      //Object retVal =getProperty(pt1,propertyName);      //PropertyDescriptor:属性描述符      ObjectretVal = getProperty(pt1,propertyName);      System.out.println(retVal);           Objectvalue = 7;           setProperties(pt1,propertyName, value);      System.out.println(pt1.getX());//setProperty设置某个对象的哪个属性,并将其设置成某个值   }    //设置value的值   private static void setProperties(Objectpt1, String propertyName,         Object value) throws IntrospectionException,         IllegalAccessException,InvocationTargetException {      PropertyDescriptor pd2 = new PropertyDescriptor(propertyName,pt1.getClass());      Method methodSetX = pd2.getWriteMethod();      methodSetX.invoke(pt1, value);   }    //获取methodGetX的值   private static Object getProperty(Object pt1, String propertyName)         throws IntrospectionException, IllegalAccessException,         InvocationTargetException{      PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt1.getClass());      Method methodGetX = pd.getReadMethod();      ObjectretVal = methodGetX.invoke(pt1);      return retVal;   } }
小结:

1.通过PropertyDescriptor这个对属性描述的方法可以获取其对应元素的相关方法,然后通过getProperty()方法获取需要的值

2.这里想获取某个对象的方法时可以利用重构:Extract Method-->Alt+Shift+M;

3.如果想提升其重构后代码的复用性,这里可以将重构后的ReflectPoint换成Object对象

 

30_对JavaBean的复杂内省操作

采用遍历BeanInfo的所有属性方式来查找和设置某个RefectPoint对象的x属性。在程序中把一个类当作JavaBean来看,就是调用IntroSpector.getBeanInfo方法,得到的BeanInfo对象封装了把这个类当作JavaBean看的结果信息

部分代码演示:

private static Object getProperty(Objectpt1, String propertyName)         throws IntrospectionException, IllegalAccessException,         InvocationTargetException{      /*PropertyDescriptor pd = newPropertyDescriptor(propertyName,pt1.getClass());      Method methodGetX = pd.getReadMethod();      Object retVal = methodGetX.invoke(pt1);*/           //对JavaBean的发杂内省操作      BeanInfo beanInfo = Introspector.getBeanInfo(pt1.getClass());      //由于获取到的属性是其所有属性,因此这里需要将其迭代分别获取      PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();      Object retVal = null;      for(PropertyDescriptor pd :pds){         if(pd.getName().equals(propertyName)){            Method methodGetX = pd.getReadMethod();            retVal = methodGetX.invoke(pt1);            break;         }      }      return retVal;   }


31_使用BeanUtils工具包操作JavaBean

Bean工具包

1、演示用eclipse如何加入jar包,先只是引入beanutils包,等程序运行出错后再引入logging包。

2、在前面内省例子的基础上,用BeanUtils类先get原来设置好的属性,再将其set为一个新值。

get属性时返回的结果为字符串,set属性时可以接受任意类型的对象,通常使用字符串。

3、用PropertyUtils类先get原来设置好的属性,再将其set为一个新值。

get属性时返回的结果为该属性本来的类型,set属性时只接受该属性本来的类型。

4、演示去掉JavaBean(ReflectPoint)的public修饰符时,BeanUtils工具包访问javabean属性时出现的问题。

导入需要的jar包操作步骤:在javaenhance工程上单击鼠标右键-->New-->SourceFolder-->Floder Name:lib--.复制需要使用的jar包,直接粘贴到新建的lib目录下,然后将其增加到build path环境中:单击导入的jar包右键-->Build Path-->Add toBuild Path即可

在使用IntroSpectorTest.java的时候运用到了JavaUtils时,只导入commons-beanutils.jar包是不够的,而且会报错:org/apache/commons/logging/LogFactory因此这里还需要按照导入beanutils jar包的方法导入logging包,并且添加到Build Path环境变量中

部分代码演示如下:

Map map = {name:"zxx",age:16};

        BeanUtils.setProperty(map, "name", "lhm");*/

     

      PropertyUtils.setProperty(pt1,"x", 9);

      System.out.println(PropertyUtils.getProperty(pt1,"x").getClass().getName());

     

小结:BeanUtils是以字符串的形式对JavaBean进行操作,而PropertyUtils则是对属性本身类型对JavaBean进行操作;如果需要类型转换,则使用BeanUtils,否则使用PropertyUtils

 


 


---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------
详细请查看:http://edu.csdn.net