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

---------------------- 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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于C++&OPENCV 的全景图像拼接 C++是一种广泛使用的编程语言,它是由Bjarne Stroustrup于1979年在新泽西州美利山贝尔实验室开始设计开发的。C++是C语言的扩展,旨在提供更强大的编程能力,包括面向对象编程和泛型编程的支持。C++支持数据封装、继承和多态等面向对象编程的特性和泛型编程的模板,以及丰富的标准库,提供了大量的数据结构和算法,极大地提高了开发效率。12 C++是一种静态类型的、编译式的、通用的、大小写敏感的编程语言,它综合了高级语言和低级语言的特点。C++的语法与C语言非常相似,但增加了许多面向对象编程的特性,如类、对象、封装、继承和多态等。这使得C++既保持了C语言的低级特性,如直接访问硬件的能力,又提供了高级语言的特性,如数据封装和代码重用。13 C++的应用领域非常广泛,包括但不限于教育、系统开发、游戏开发、嵌入式系统、工业和商业应用、科研和高性能计算等领域。在教育领域,C++因其结构化和面向对象的特性,常被选为计算机科学和工程专业的入门编程语言。在系统开发领域,C++因其高效性和灵活性,经常被作为开发语言。游戏开发领域中,C++由于其高效性和广泛应用,在开发高性能游戏和游戏引擎中扮演着重要角色。在嵌入式系统领域,C++的高效和灵活性使其成为理想选择。此外,C++还广泛应用于桌面应用、Web浏览器、操作系统、编译器、媒体应用程序、数据库引擎、医疗工程和机器人等领域。16 学习C++的关键是理解其核心概念和编程风格,而不是过于深入技术细节。C++支持多种编程风格,每种风格都能有效地保证运行时间效率和空间效率。因此,无论是初学者还是经验丰富的程序员,都可以通过C++来设计和实现新系统或维护旧系统。3

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值