黑马程序员_Java基础加强(上)_eclipse及5.0新特性_26

                                     ------- android培训java培训、期待与您交流!----------

 

前言

  • 去面试人家没有时间看你的代码,你的算法,人家就看你的整体效果,没有人会把你的程序放到计算机中运行一下。我才见你,我不知道你们哪个基础好,哪个基础不好,哪个品行好,哪个品行不好, 我就看哪个小伙比较精神,哪个小伙穿的挺光鲜亮丽的。
  • 用单词来定义自己的类名或者变量名。
  • 如果想将自己的工程改变一个名字,可以在工程上击右键-->refactor(重构)-->Rename
  • 尽量让别人高兴,自己会有很多的机会。

1、课程价值与目标介绍

  • 在这个行业中有没有前途就看你的基础怎么样,但是不学高级也不行,高级可以促进我们的基础。用人单位判断你的能力如何,也是看重你对这些基础知识的深入程度,看重你学习新知识的能力。

 

2、eclipse及IDE开发工具介绍

  • myeclipse是eclipse开发java ee项目的插件,它是myeclipse插件提供的打包工具连浏览器和插件一起安装了。eclipse是用java语言开发出来的。启动eclipse的过程相当于启动了一个exe文件,这个exe文件启动了一个java类而java类的界面是这样的。在任务管理器中有一个javaw.exe的进程。
  • 简写:

1.       javaee

2.       ide       integrity development environment

3.       jms      Java Message Service

4.       jmx      Java Management Extensions

5.       jndi      Java Naming and Directory Interface

  • perspective 透视图
  • java IDE常用的有eclipse、Myeclipse、NetBeans、JBuilder等(JBuilder收费)

开发工具用哪个无所谓,它只是提高你的效率,你手工的也可以办。

 

3、eclipse工程管理与快捷键配置

  • IDE开发工具都支持使用工程化方式管理一个项目的程序开发过程,一般来说一个相对独立的项目就是一个工程,一个项目中涉及的多个java文件,资源文件(配置文件)等用一个工程进行管理。(在这里可以看看以前工作间中的某个工程的结构),在不使用工程管理的情况下,如果一个项目中包括多个Java源文件,编程人员需要精心维护这些源文件之间、以及源文件与其它文件的目录关系,需要逐一编译这些源文件,需要手工启动运行编译后的结果。如果将一个程序的所有源文件用一个工程来组织,开发工具能对所有源文件集中管理,记住每个源文件的位置和相互关系。 工程中有哪几个源文件、启动类是哪个、启动参数设置等配置信息在工程中都记录。
  • 新建立的工作间,配置快捷键:Window-->Preferences。因为这里不是针对java文件,而是针对所有的出现在项目中的语言进行配置,所以选择General(通用)-->Editors-->Keys-->输入content assit-->点Remove Binding-->再创建新的绑定。
  • 快捷键使用技巧:快捷键的位置:General->keys,设置alt+/键(输入:content a 就会搜索出)进行内容提示时,要注意解除alt+/键原来的绑定关系,直接输入alt+/就可以找到它的绑定关系,删除绑定关系时也可以使用remove binding这个按钮。

 

4、eclipse中视图管理和程序调试

  • Perspective(透视图)与view(视图)的关系:一个Perspective代表了若干个view的集合。每个小的窗口就叫做view。如果把view窗口给关闭了,想再显示,可以点Window-->Show View来选择。
  • 不同的透视图,就是不同的多个小窗口的集合。可以在右上角进行不同透视图的切换。
  • 设置单个工程的javac和java,选择工程,右键-->properties可以设置javac,右键-->run as-->open run dialog可以设置java。
  • 在eclipse中怎样调试?查看一个变量的值时,可在在前面双击建立一个断点。
  • 选中变量-->右键-->Watch,可以看到调试时变量对应的值。

 

5、配置eclipse的编译和运行环境

  • 一个workspace可以包含多个project,一个workspace保留了eclipse的一套环境选项的配置,例如,所使用的javac和java命令,等等。细节请查看window->preferences,其中的java-->Compiler是用来配置编译的,其中的java-->InstalledJREs是用来配置运行环境的。
  • 如果要为eclispe再配置一套环境选项,可以再创建一个workspace(在eclipse中可以通过File-->SwitchWorkspace-->Other选择或者创建一个工作间)。Package explorer视图窗口中的filters菜单项,可以显示空的父包(此功能默认是关闭的)。
  • java.lang.UnsupportedClassVersionError:Badversion number in .class file.出现这个错误是因为java编译时用的版本和运行的时候的版本不匹配。在更改JRE时找到安装JDK的主目录即可。工作间可以配置编译和运行环境,这样的配置运用于所有的工程,也可以在工程上击右键,对于本工程进行单独的设置。(类似于继承和覆盖的关系)
  • 设置整个workspace的javac与java。

设置单个工程的javac与java。

Ø 高版本的java能否运行低版本的javac编译的程序?(能)

Ø 低版本的java能否运行高版本的javac编译的程序?(不能)

 

6、在Eclipse配置java模板代码

  • 代码模板的设置位置:java->editor->Templates(可以点new添加一个模板。在添加了这些模板后,选中代码,击右键àSurroundWith,可以将选中的代码放入模块当中)

 

7、在eclipse中导入已有的工程。

  • 将工程导入到eclipse中去。将工程拷贝到工作台下面-->File-->import-->Existing Projects into Workspace.(如果你的JDK和我用JDK不是很一样,可以在导入的工程上点右键-->Build Path-->Configure Buid path-->更换Libraries。如果已经将一个jar包拷贝到工程下面了,可以用Add JARs。如果没有拷贝到已有工程下,可以用Add External JARs。而增加一个Library相当于增加了好多个jar)

 

8、java5的静态导入与编译器语法设置

  • import语句可以导入一个类或某个包中的所有类
  • import static语句导入一个类中的某个静态方法或所有静态方法。例:

Ø import static java.lang.Math.sin;

Ø import static java.lang.Math.*;

 

9、可变参数与OverLoad相关面试题分析

  • 可变参数的特点:

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

Ø …(三个点)位于变量类型和变量名之间,前后有无空格都可以;

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

  • overload和override的区别:

不仅要答出它们的不同,还要答出你独到的见解。如,当父类中的方法,用Private修饰的时候,子类中有相同的方法,它是否为重写。很显然,它不是重写。

 

10、java5的增强for循环

  • 语法:

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

  • 注意事项:

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

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

 

11、基本数据的自动拆装箱及永不放弃设计模式

  • 自动装箱:

Ø Integer num1 = 12;

  • 自动拆箱:

Ø System.out.println(num1 + 12);

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

Integer num1 = 12;

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

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

Integer num3 = 129;                这块不相等,因为是对象

Integer num4 = 129;

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

Integer num5 = Integer.valueOf(12);

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

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

  • 数据很小,用的比较频繁,搞出来很多个对象后,在这些对象中,有很多对象永远都是一模一样,那就没有必要搞那么多个了。这叫做享元模式。(有很多,很多小的对象,它们有很多相同的东西,那么就要以把它变成一个对象,还有很多不同的东西把它变成外部的属性。)

 

12、枚举的作用介绍 

枚举:类定义出来的值只能是规定的那几个。

  • 为什么要有枚举

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

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

  • 点某一行最前面的叉号,在出现的选项卡中点:Create class ‘WeekDay’,可以创建一个类。
  • static 和final谁在前面,都可以。

 

13、用普通类模拟枚举的实现原理

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

Ø 私有的构造方法

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

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

public abstract class WeekDay1 {

       privateWeekDay1(){}

       publicfinal static WeekDay1 SUN = new WeekDay1(){

              publicWeekDay1 nextDay() {

                     returnMON;

              }

             

       };

       publicfinal static WeekDay1 MON = new WeekDay1(){

              publicWeekDay1 nextDay() {

                     returnSUN;

              }

       };   

       publicabstract WeekDay1 nextDay();

/*    publicWeekDay nextDay(){

              if(this== SUN){

                     return  MON;

              }else{

                     returnSUN;

              }

       }

*/

       publicString toString(){

              returnthis==SUN?"SUN":"MON";

       }

}

 

14、java5的枚举的基本应用 

15、实现再有构造方法的枚举

16、实现带有抽象方法的枚举

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

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

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

  • 枚举就相当于一个类,枚举里面的一个元素,就相当于这个类搞出来的一个实际对象,
  • 枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
  • 枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
  • 带构造方法的枚举

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

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

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

  • 带方法的枚举

Ø 定义枚举TrafficLamp

Ø 实现普通的next方法

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

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

  • 枚举只有一个成员时,就可以作为一种单例的实现方式。
  • 写带有抽象方法的枚举步骤和技巧:

   1. enum TrafficLamp{RED,GREEN,YELLOW}

   2. enum TrafficLamp{RED,GREEN,YELLOW;publicabstract next();}

   3.enumTrafficLamp{RED{},GREEN{},YELLOW{};public abstract next();}

   4.填充各个{}中的next方法。

  • import java.util.Date;

public class EnumTest {

       publicstatic void main(String[] args) {

              WeekDay1weekDay = WeekDay1.MON;

              System.out.println(weekDay.nextDay());

              WeekDayweekDay2 = WeekDay.FRI;

              System.out.println(weekDay2);

              System.out.println(weekDay2.name());

      //返回此枚举常量的名称,在其枚举声明中对其进行声明。 与此方法相比应优先考虑使用 toString() 方法,因为toString 方法返回更加用户友好的名称

              System.out.println(weekDay2.ordinal());    

//返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。

              System.out.println(WeekDay.valueOf("SUN"));

      //valueOf();返回的是一个WeekDay对象。输出进会自动调用toString()方法,输出“SUN”

              System.out.println(WeekDay.values().length); //得到枚举类型的元素的数组

              newDate(300){};

       }

       publicenum WeekDay{

              SUN(1),MON(),TUE,WED,THI,FRI,SAT;

   //你定义的所有的其他的信息都必须在这个列表之后,如果元素列表之后有东西的话,一定要加一个分号,如果没有东西的话,这个分号可以不加。

              privateWeekDay(){System.out.println("first");} //枚举类型的构造方法必须为private的。默认调的是空的构造函数,如果想调用下面的构造方法,可以传入一个参数。

              privateWeekDay(int day){System.out.println("second");}

       }

       publicenum TrafficLamp{ //有三人元素,每一个元素都是由它的子类来写的。子类要完成父类的抽象的方法。

              RED(30){ //相当于new一个子类的实例对象,调用父类的有参构造方法。

                     public  TrafficLamp nextLamp(){

                            returnGREEN;

                     }

              },

              GREEN(45){

                     public  TrafficLamp nextLamp(){

                            returnYELLOW;

                     }                  

              },

              YELLOW(5){

                     public  TrafficLamp nextLamp(){

                            returnRED;

                     }                  

              };

              publicabstract TrafficLamp nextLamp();

              privateint time;

              privateTrafficLamp(int time){this.time = time;}

       }

}

  • 内部类可以有4个修饰符的,而外部类只有有2个(public、默认的)
  • 类的方法返回的类型,可以是自己的这个类型。
  • 类中可以定义静态常量,常量指向的结果就是自己这个类型的实际对象。

 

17、透彻分析反射的基础-Class类

  • 反射不是1.5有的新特性,它是从1.2之后就有的。做框架都要用到反射机制。
  • 对比提问: Person类代表人,它的实例对象就是张三,李四这样一个个具体的人, Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。(Class-->代表一类什么样的事物。)

问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?

Ø 人-->Person

Ø Java类-->Class

  • Class类代表Java类,它的各个实例对象又分别对应什么呢?

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

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

  • 如何得到各个字节码对应的实例对象(即Class类型,有三种方式)

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

 Ø对象.getClass(),例如,newDate().getClass()

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

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

Person p1 = new Person();

Person p2 = new Person();

Class cls1 = Date.class //第一种获得字节码的方式。

Class cls2 = Person.class //字节码2

p1.getClass(); //第二种,这个类的字节码已经加载到这个类中来了(这个时候就不能加载了,直接找到要用的字节码,把它返回)。

Class.forName(“java.lang.String”); //第三种,静态的方法。这个类的字节码还没有在虚拟机当中(用类加载器去加载,用forName()返回加载进来的字节码)。做反射一般用第三种,因为在写源程序的时候,还不知道类的名字。在运行的时候人家传递给我一个字符串,这个字符串中包含了一个字符串的名字。

  • 九个预定义Class实例对象:

Ø 八个基本类型和 void (八个基本的数据类型及void都有对应的Class对象)

Ø Int.class== Integer.TYPE

  • 数组类型的Class实例对象

Ø Class.isArray()

  • 总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
  • 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 {

       publicstatic void main(String[] args) throws Exception {

              Stringstr1 = "abc";

              Classcls1 = str1.getClass();

              Classcls2 = String.class;

              Classcls3 = Class.forName("java.lang.String");

              System.out.println(cls1== cls2); //返回true

              System.out.println(cls1== cls3);  

//返回true,说明cls1,cls2,cls3在内存中用的是同一个字节码文件

              System.out.println(cls1.isPrimitive()); //返回false

              System.out.println(int.class.isPrimitive()); //返回true

              System.out.println(int.class== Integer.class);  //返回false

              System.out.println(int.class== Integer.TYPE);  //返回true,TYPE返回的是封装的基本数据类型的字节码

              System.out.println(int[].class.isPrimitive()); //返回false

              System.out.println(int[].class.isArray()); //返回true

             

              //newString(new StringBuffer("abc"));

              Constructorconstructor1 = String.class.getConstructor(StringBuffer.class);

    //这里的StringBuffer表示选择哪个构造方法,下面的StringBuffer表示用这个构造方法的时候,还要传一个StringBuffer的对象进去。constructor1代表的是StringBuffer的构造方法。

              Stringstr2 = (String)constructor1.newInstance(/*"abc"*/newStringBuffer("abc"));

   //编译的时候就知道你是一个Constructor,但不知道是哪一个类构造方法,确定是哪个构造方法要在运行的时候才知道。newInstance返回的是Object,强制转换,告诉编译器,我返回的是String。newInstance传入的不能是字符串abc而应该是new StringBuffer("abc"),不然的话,会报错。

              System.out.println(str2.charAt(2));

              ReflectPointpt1 = new ReflectPoint(3,5);

              FieldfieldY = pt1.getClass().getField("y");

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

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

              FieldfieldX = pt1.getClass().getDeclaredField("x");

   //如果用方法getField(“x”)的话,因为x是私有的,所以会找不到,如果用getDeclareField()就可以找到了。

              fieldX.setAccessible(true); 

//暴力反射,如果没有这句话,下面的语句会报错的,不让你拿。

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

             

              changeStringValue(pt1);

              System.out.println(pt1);

             

              MethodmethodCharAt = String.class.getMethod("charAt", int.class);

              System.out.println(methodCharAt.invoke(str1,1)); //invoke调用的意思

              System.out.println(methodCharAt.invoke(str1,new Object[]{2}));

             

              //TestArguments.main(newString[]{"111","222","333"});

              StringstartingClassName = args[0];

              MethodmainMethod = Class.forName(startingClassName).getMethod("main",String[].class);

              //mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});

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

             

              int[] a1 = new int[]{1,2,3};

              int[] a2 = new int[4];

              int[][]a3 = new int[2][3];

              String[] a4 = new String[]{"a","b","c"};

              System.out.println(a1.getClass()== a2.getClass()); //返回true

              System.out.println(a1.getClass()== a4.getClass()); //返回false

              System.out.println(a1.getClass()== a3.getClass()); //返回false

              System.out.println(a1.getClass().getName()); //返回[I

              System.out.println(a1.getClass().getSuperclass().getName()); //返回父类java.lang.Object

              System.out.println(a4.getClass().getSuperclass().getName()); //返回父类java.lang.Object

             

              ObjectaObj1 = a1;

              ObjectaObj2 = a4;

              //Object[]aObj3 = a1; //基本数据的类型是不能够转换为Object的。

              Object[]aObj4 = a3; //Object中装的是一维的数组,这个一维的数组可以为Object.

              Object[]aObj5 = a4;

             

              System.out.println(a1);

              System.out.println(a4);

              System.out.println(Arrays.asList(a1));   //返回[[I@1cfb549]

              System.out.println(Arrays.asList(a4));    //返回[a, b, c]

              //上面两个语句返回的结果不一样,这是因为:在JDK1.4版本中,asList(Object[]obj)方法要传入的参数是一个Object类型的数组。a4是一个字符类型的数组,可以传入。可以a1在调用asList()方法后,因为a1是基本数据类型,不能转换为Object类型的数组。所以调用JDK1.5的asList(T... a)可变参数的方法,将a1做为一个参数传入。

              printObject(a4);

              printObject("xyz");

       }

       privatestatic void printObject(Object obj) {

              Classclazz = obj.getClass();

              if(clazz.isArray()){

                     intlen = Array.getLength(obj);

                     for(inti=0;i<len;i++){

                            System.out.println(Array.get(obj,i));

                     }

              }else{

                     System.out.println(obj);

              }

       }

       privatestatic void changeStringValue(Object obj) throws Exception {

              Field[]fields = obj.getClass().getFields();

              for(Fieldfield : fields){

                     //if(field.getType().equals(String.class)){

                     if(field.getType()== String.class){ //字节码的比较用==来比。

                            StringoldValue = (String)field.get(obj);

                            StringnewValue = oldValue.replace('b', 'a');

                            field.set(obj,newValue);

                     }

              }

       }

}

class TestArguments{ //将光标放在这个类的类名上,按下F2将会出现完整的类名。

       publicstatic void main(String[] args){

              for(Stringarg : args){

                     System.out.println(arg);

              }

       }

}

 

import java.util.Date;

public class ReflectPoint {

       privateDate birthday = new Date();

       privateint x;

       publicint y;

       publicString str1 = "ball";

       publicString str2 = "basketball";

       publicString str3 = "itcast";

       publicReflectPoint(int x, int y) {

              super();

              this.x= x;

              this.y= y;

       }

       @Override

       publicint hashCode() {

              finalint prime = 31;

              intresult = 1;

              result= prime * result + x;

              result= prime * result + y;

              returnresult;

       }

       @Override

       publicboolean equals(Object obj) {

              if(this == obj)

                     returntrue;

              if(obj == null)

                     returnfalse;

              if(getClass() != obj.getClass())

                     returnfalse;

              finalReflectPoint other = (ReflectPoint) obj;

              if(x != other.x)

                     returnfalse;

              if(y != other.y)

                     returnfalse;

              returntrue;

       }

       @Override

       publicString toString(){

              returnstr1 + ":" + str2 + ":" + str3;

       }

       publicint getX() {

              returnx;

       }

       publicvoid setX(int x) {

              this.x= x;

       }

       publicint getY() {

              returny;

       }

       publicvoid setY(int y) {

              this.y= y;

       }

       publicDate getBirthday() {

              returnbirthday;

       }

       publicvoid setBirthday(Date birthday) {

              this.birthday= birthday;

       }

}

 

18、理解反射的概念

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

 

19、构造方法的反射应用(代码见17)

  • Constructor类代表某个类中的一个构造方法。
  • Constructor对象代表一个构造方法,Constructor对象上会有什么方法呢?得到名字,得到所属于的类,产生实例对象。
  • 一个类有多个构造方法,用什么方式可以区分清楚想得到其中的哪个方法呢?根据参数的个数和类型,例如,Class.getMethod(name,Class... args)中的args参数就代表所要获取的那个方法的各个参数的类型的列表。重点:参数类型用什么方式表示?用Class实例对象。例如:

int.class,(int[]).class

int [] ints = new int[0];

ints.getClass();

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

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

  • 得到某一个构造方法:

Ø 例子:       Constructor constructor =Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);

      //获得方法时要用到类型

  • 创建实例对象:

Ø 通常方式:String str = new String(newStringBuffer("abc"));

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

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

  • Class.newInstance()方法:

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

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

Ø 该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。(反射比较占用时间,比较消耗性能,反射会导致程序性能严重下降,所以会在这里加上了缓冲技术)

 

20、成员变量的反映(代码见17)

  • Field类代表某个类中的一个成员变量
  • 演示用eclipse自动生成Java类的构造方法。

用eclipse的快捷键:alt+shift+s-->选择Generate Constructor using Fields…或者用鼠标右击-->Source-->Generate Constructor using Fields…也可以达到同样的效果。

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

       ReflectPoint point = newReflectPoint(1,7);

       Field y =Class.forName("cn.itcast.corejava.ReflectPoint").getField("y");

       System.out.println(y.get(point));

       //Field x =Class.forName("cn.itcast.corejava.ReflectPoint").getField("x");

       Fieldx = Class.forName("cn.itcast.corejava.ReflectPoint").getDeclaredField("x");

       x.setAccessible(true);

       System.out.println(x.get(point));

 

21、成员变量的综合案例(代码见17)

  • 作业:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
  • 你给我一个对象,我把这个对象中相应的成员变量给改掉。
  • 一个问题,我把自己的变量定义成private,就是不想让人家访问,可是,现在人家用暴力反射还是能够访问我,这说不通啊,能不能让人家用暴力反射也访问不了我。首先,private主要是给javac编译器看的,希望在写程序的时候,在源代码中不要访问我,是帮组程序员实现高内聚、低耦合的一种策略。你这个程序员不领情,非要去访问,那我拦不住你,由你去吧。同样的道理,泛型集合在编译时可以帮助我们限定元素的内容,这是人家提供的好处,而你非不想要这个好处,怎么办?绕过编译器,就可以往集合中存入另外类型了。

 

22、成员方法的反射

  • Method类代表某个类中的一个成员方法。Class.getMethod方法用于得到一个方法,该方法要接受什么参数呢?显然要一个方法名,而一个同名的方法有多个重载形式,用什么方式可以区分清楚想得到重载方法系列中的哪个方法呢?根据参数的个数和类型,例如,Class.getMethod(name,Class... args)中的args参数就代表所要获取的那个方法的各个参数的类型的列表。再强调一遍参数类型用什么来表示啊?用Class对象!
  • 得到类中的某一个方法:

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

  • 调用方法:

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

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

如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!

  • 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})形式。

  • 面向对象思想:只要把变量搞成私有的,如果谁要操作这个变量,那这个变量在谁身上,这个方法就应该在谁的身上。所以这个invoke是方法的invoke,但是调用invoke的时候是在某个对象上去调。
  • 如果是静态的方法要调用的时候写成invoke(null,1);的形式,因为静态的方法在调用的时候不需要对象。

 

23、数组与Object的关系及其反射类型(代码见17)

  • 用反射方式执行某个类中的main方法
  • 目标:

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

  • 问题:

Ø 启动Java程序的main方法的参数是一个字符串数组,即public static void main(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的语法解释,因此会出现参数类型不对的问题。

  • 解决办法:

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

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

  • Run As-->Run Configurations…-->Arguments-->传入参数cn.itcast.day.TestArguments,这个传入的参数相当于命令行参数中传入的存入args数组中的值。

 

24、数组与Object的关系及其反射类型(代码见17)

  • 数组的反射
  • 具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。
  • 代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
  • 基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
  • Arrays.asList()方法处理int[]和String[]时的差异。
  • Object[] 与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成newString[]{“aaa”,”bb”};,Object x = “abc”能强制转换成Stringx = “abc”。

 

25、数组的反射应用(代码见17)

  • Array工具类用于完成对数组的反射操作。
  • 思考题:怎么得到数组中的元素类型?

int[] a = new int[3];

Object[] a = new Object[]{“a”, 1}; //这里面即可以放String,也可放Int,不确定

a[0].getClass().getName();

只能得到某一个具体的元素的类型,不能得到整个数组的元素类型。

 

                                     ------- android培训java培训、期待与您交流!----------  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值