1、JAVA程序设计,第5章 深入理解JAVA语言,5.1 变量及其传递,5 .1.1 基本类型变量与引用型变量基本类型:其值直接存于变量中。引用型的变量除占据一定的内存空间外,它所引用的对象实体(由new 创建)也要占据一定空间。引用型变量保存的实际上是对象在内存的地址,也称为对象的句柄。MyDate.class,引用型变量与对象实体的关系,day,month,year,m,n,MyDate m,n; n=new MyDate();n=m; n.addYear();,5.1.2 域变量与局部变量,从语法角度看域变量属于类或接口;public,private,static,final 修饰。而局部
2、变量是在方法中定义的变量或方法的参变量。都可用Final修饰,而局部变量则不能够被访问控制符及static修饰。从存储角度看从变量在内存中的存储方式来看,域变量是对象的一部分,而对象是存在于堆中的,局部变量是存在于栈中。域变量的生命周期与局部变量的生命周期比较。另外,域变量可以自动赋初值,局部变量则须显式赋值。局部变量必须显示赋值后才能够使用。,class Test() int a; void m() int b; System.out.println(b);/编译不能通过需要/初始化。 ,5.1.3 变量的传递,调用对象方法时,要传递参数。在传递参数时,Java 是值传递,即,在调用一个方法
3、时,是将表达式的值复制给形式参数。对于引用型变量,传递的值是引用值(可以理解为内存地址)。TransByValue.java,Java中的参数都是按值传递的,但对于引用型变量,传递的值是引用值,所以方法中对数据的操作可以改变对象的属性。,public class TransByValue private static int a; public static void main(String args) int a=0; modify(a); System.out.println(a); int b=new int1; modify(b); System.out.println(b0); /1
4、 or 5 public static void modify(int a) a+; public static void modify(int b) b0+; b=new int5; /:,5.1.4 变量的返回,方法的返回:返回基本类型。返回引用类型。它就可以存取对象实体。 Object getNewObject() Object obj=new Object(); return obj;调用时:Object p= GetNewObject();,5.2 多态和虚方法调用,多态(Polymorphism)是指一个程序中相同的名字表示不同的含义的情况。覆盖(override) (子类对父类方
5、法)重载(overload) (同一个类中定义多个同名的不同方法)。动态绑定(dynamic binding) -虚方法调用(virtual method invoking) 。它能够使对象所编写的程序,不用做修改就可以适应于其所有的子类,如在调用方法时,程序会正确地调用子对象的方法。多态的特点大大提高了程序的抽象程度和简洁性,更重要的是,它最大限度地降低了类和程序模块之间的耦合性,提高了类模块的封闭性,使得它们不需了解对方的具体细节,就可以很好地共同工作。这个优点对于程序的设计、开发和维护都有很大的好处。,5.2.1 上溯造型,就是把派生类型当作基本类型处理的过程。 doStuff(Shap
6、e s) s.erase(); / s.draw(); ,Circle c=new Circle;Triangle t= new Triangle();Line l= new Line();doStuff(c);doStuff(t);doStuff(l);,5.2.2 虚方法调用,所有的非final方法都会自动地进行绑定!TestVirtualInvoke.java用虚方法调用,可以实现运行时的多态!在使用上溯造型的情况下,子类对象可以当做父类对象,对于重载或继承的方法,Java运行时系统根据调用该方法的实例的类型来决定选择哪个方法调用。,虚方法调用,子类重载了父类方法时,运行时,系统调用子类
7、的方法。运行时,根据实际的类型调用正确的方法,对面向对象的程序设计来说,就叫“多态型性”。用虚方法调用,可以实现运行时的多态,它体现了面向对象程序设计中的代码复用性。已经编译好的类库可以调用新定义的子类的方法而不必重新编译,而且如果增加几个子类的定义,只需分别用new生成不同子类的实例,会自动调用不同子类的相应方法。,Circle c=new Circle();Triangle t=Triangle();Line l=new Line(); doStiff(c); doStiff(t); doStiff(l);,继承时,如果使用super.则调用父类的方法。例 Test_Virtual_Sup
8、er.java,static,private, 和 final不存在虚方法的调用问题。Static的方法,以申明的类型为准,与实例类型无关Test_Virtual_Static.javaPrivate方法子类看不见,也不会被虚化Final方法子类不能覆盖,不存在虚化问题,5.2.3 动态类型确定,1. 变量 instanceof 类型 结果是boolean 值。InstanceOf1.java,2. Class类,对象可以通过getClass()方法来获得运行时的信息。getClass()是java.lang.Object的方法,而Object是所有类的父类。所以任何对象都可以用getClas
9、s()方法。这种获得运行时对象的方法也叫反射。RunTimeClassInfo.javagetClass()方法得到对象的运行时的类信息,即一个Class类的对象,它的getFields()及getMethods()方法能进一步获得其详细信息 注:在JDK1.5以上的版本中,还有元数据注记(Annotation)来进一步增强反射功能 (如 Override ),5.3 对象构造与初始化,5.3.1 调用本类或父类的构造方法this调用本类的其他构造方法。super调用直接父类的构造方法如果没有this及super,则编译器自动加上super(),即调用直接父类不带参数的构造方法。this或su
10、per要放在第一条语句,且只能够有一条.,Class A A(int a)Class B extends A B(String s) /编译不能够通过.编译器会自动调用B(String s) super(); 出错.解决方法:在B的构造方法中,加入super(3);在A中加入一个不带参数的构造方法,A()去掉A中全部的构造方法,则编译器会自动加入一个不带参数的构造方法,称为默认的构造方法.,在构造函数中使用this和super.ConstructCallThisAndSuper.java,在构造方法中调用this及super或自动加入的super,最终保证了任何一个构造方法都要调用父类的构造方
11、法,而父类的构造方法又会再调用其父类的构造方法,直到最顶层的Object类。这是符合面向对象的概念的,因为必须令所有父类的构造方法都得到调用,否则整个对象的构建就可能不正确。,5.3.2 构造方法的执行过程,对于一个复杂的对象,构造方法的执行过程遵照以下步骤:调用本类或父类的构造方法,直至最深一层派生类。按照声明顺序执行域的初始化赋值。执行构造函数中的各语句。ConstructSequence.java构建器的调用顺序非常重要。先父类构造,再本类成员赋值,最后执行构造方法中的语句。,实例初始化与静态初始化,在类中直接写 语句. 实例初始化,先于中的语句执行或 static 语句. 静态初始化,
12、在第一次使用这个类时要执行,且总是先于实例的初始化,但其执行的时机是不确定的。例:InitialTest.java,5.3.3构造方法内部调用的方法的多态性,在构造子类的一个对象时,子类构造方法会调用父类的构造方法,而如果父类的构造方法中调用该对象的其他方法,如果所调用的方法又被子类所覆盖的话,它可能实际上调用的是子类的方法 ,这是由动态绑定(虚方法调用)所决定的。从语法上来说这是合法的,但有时会造成事实上的不合理,所以在构造方法中调用其他方法要小心。ConstructInvokeMetamorph.java,在本例中,在构造函数中调用了一个动态绑定的方法sayHello(),这时,会使用那个
13、方法被覆盖的定义,而这时对象尝未完全构建好,所以School还没有赋值。因此,可能的话,在构建器中避免调用任何方法,用尽可能简单的方法使对象进入就绪状态。惟一能够安全调用的是具有final属性的方法。,5.4 对象清除与垃圾回收,new创建对象。自动清除,清除过程称为垃圾回收。,5.4.1 对象的自动清除,对象回收是由 Java虚拟机的垃圾回收线程来完成的。系统中的任何对象都有一个引用计数器,当其值为0时,说明该对象可以回收。,String method() String a,b; a=new String(“hello world”); b=new String(“game over”);
14、System.out.println(a+b+”Ok”); a=null; a=b; return a;,5.4.2 System.gc()方法,它是System类的static方法, 它可以要求系统进行垃圾回收。但它仅仅只有建议权。,5.4.3 finalize()方法,关闭打开的文件、清除一些非内存资源等工作需要在对象懂得回收时进行,这可以通过覆盖Object 的finalize()方法来实现。因为系统在回收时会自动调用对象的finalize() 方法。一般来说,子类的finalize()方法中应该调用父类的finalize()方法,以保证父类的清理工作能够正常进行。 protected
15、void finalize() throws Throwable TestCleanUp.java,本例中,每个类都有一个方法cleanup()来负责清理工作。先完成本类的有关工作,然后调用父类的清除方法。 finally表明:无论会发生什么事情,总是为X调用cleanup().,JDK7中的try-with-resources,对于实现了java.lang.AutoCloseable的对象try( Scanner scanner= new Scanner( ) )会自动调用其close()方法,5.5 内部类与匿名类,内部类是在其他类中的类。匿名类是一种特殊的内部类,它没有类名,在定义类的同
16、时就生成该对象的一个实例。1.内部类的定义和使用将类的定义置入一个用于封装它的类内部即可。内部类不能够与外部类同名。在封装它的类的内部使用内部类,与普通类的使用方式相同,在其他地方使用,类名前要冠以外部类的名字。在用new创建内部类时,也要在 new前面冠以对象变量。InnerUse.java,2. 在内部类中使用外部类的成员,内部类中可以直接访问外部类的其他域及方法。即使private也行。如内部类中有与外部类同名的域或方法,可以用this来访问外部成员。TestInnerThis.java,3.内部类的修饰符,内部类与类中的域、方法一样是外部类的成员,它的前面也可以有访问控制符和其他修饰符
17、。内部类可用的修饰符比外部类的修饰符更多。(外部类不能够使用protected,private,static等修饰,而内部类可以。访问控制符:public,protected,默认及private。Final,abstract。用static修饰表明该内部类实际是一种外部类。,Static 环境在使用时要遵循以下规则:1、实例化static内部类时,在 new前面不需要用对象变量;2、Static内部类中不能访问其外部类的非static的域及方法,既只能够访问static成员。3、static方法中不能访问非static的域及方法,也不能够不带前缀地new 一个非static的内部类。,Tes
18、tInnerStatic.java,5.5.2 方法中的内部类及匿名类,1。方法中的内部类在一个方法中也可以定义类。这种类称为方法中的 内部类。TestInnerMethod.class,1、同局部变量一样,方法中的内部类前不能够用 public,private,protected,static修饰,但可以被final或者abstract修饰。2、方法中的内部类可以访问其外部类的成员;若是Static中的内部类可以访问外部类的static成员。3、方法中的内部类中,不能够访问该方法的局部变量,除非是final局部变量。4、方法中定义的类,在其他地方使用时,没有类的情况,正像例中一样,只能够用其
19、父类来引用这样的变量。,2。匿名类,匿名类有以下几个特点:1、不取名字,直接用其父类的名字。2、类的定义域创建该类的一个实例同时进行,即类的定义前面有一个new。不使用关键词class。 new 类名或接口名()。3、类名前面不能够有修饰符。4、类中不能够定义构造方法,因为它没有名字。在构造对象时不能够带参数。,TestInnerAnonymous.java,5.6 装箱、拆箱、枚举,从JDK1.5之后,增加了对基本类型的使用的一些改进Complier sugar,基本类型的包装类,int Interger类似的还有Boolean, Byte, Short, Character,Integer
20、, Long, Float, DoubleInteger I = new Integer(10);,自动装箱与拆箱,Boxing UnboxingInteger I = 10;int i = I;实际译为Integer I= Integer.valueOf(10);int i = I.intValue();主要方便用于集合中,如:Object ary = 1, aaa;System.out.println(String.format(%s %s, ary);,思考,Integer i = new Integer(10);Integer j = new Integer(10);System.ou
21、t.println(i=j);Integer m = 10;Integer n = 10;System.out.println(m=n);Integer p = 200;Integer q = 200;System.out.println(p=q);,枚举enum,public enum ActionSTOP, RIGHT, LEFT, UP, DOWNpublic enum ProrityMAX, NORM, MIN;多用于switchPrority p = Prority.MAX;switch(p)case MAX: System.out.println(ok);break; case 后只跟MAX,不跟类名,