1、第4课 对象和类,构造方法 重载方法 覆盖方法 访问控制 static变量,方法和初始代码块 this引用的用途 final类,方法和变量 abstract类和方法,接口 解释如何以及何时使用内部类 降级,以及如何把Java程序从JDK的低版本升级到高版本,参考Java面向对象编程的第6、7、8和12章,interface MyIFCvoid method1();void method1(int a); abstract class Basepublic void method1()System.out.println(“hi“); protected abstract void method
2、2(); class Sub extends Base implements MyIFCprivate int a;private static int b;public static final int C=1;Sub()this(-1);Sub(int a)this.a=a;public void method1()a+;public void method1(int a)this.a=a;public void method2()a-;public static void method3()b+; ,构造方法,声明构造方法的语法规则 重载构造方法,参见Employee.java 默认构造
3、方法, 参见Sample1.java 子类调用父类的构造方法,参见Son.java,构造方法的语法规则,一个新对象的初始化的最终步骤是去调用对象的构造方法。 构造方法必须满足以下条件: 方法名必须与类名称完全相匹配; 不要声明返回类型; 不能被static、final、synchronized、abstract、native修饰。public class Sample int x; public Sample() / No-arg constructorx=1;public Sample(int x) /int-arg constructorthis.x=x; ,构造方法的语法规则,publi
4、c class Sample int x; public void Sample() x=1;public static void main(String args)Sample s=new Sample();System.out.println(s.x); ,重载构造方法,public class Employee private String name;private int salary;public Employee(String n, int s) name = n;salary = s;public Employee(String n) this(n, 0);public Empl
5、oyee() this( “ Unknown “ ); ,Employee tom=new Employee(“Tom“,1000); Employee jack=new Employee(“Jack“); Employee someone=new Employee();,默认构造方法,默认构造方法是没有参数的构造方法,你可以显式定义类的默认构造方法。 为了保证每个类至少有一个构造方法,如果定义的类中一个构造方法也没有写,Java将自动提供一个默认构造方法。该构造方法没有参数,用public 修饰,而且方法体为空。格式如下:public ClassName() 只要类中显式定义了一个或多个构造
6、方法,而且所有显式定义的构造方法都带参数,那么将失去默认构造方法。,默认构造方法,public class Sample1 public class Sample2public Sample2(int a)System.out.println(“My Constructor”); public class Sample3public Sample3()System.out.println(“My Default Constructor”); ,Sample1 s1=new Sample1(); Sample2 s2=new Sample2(); /非法 Sample2 s22=new Samp
7、le2(1); Sample3 s3=new Sample3();,在构造子类对象时,JVM会先调用父类的构造方法 子类构造方法中通过super语句调用父类构造方法 如果子类构造方法中没有通过super语句调用父类构造方法,那么JVM会调用父类的默认构造方法,如果不存在默认构造方法,将导致编译错误,子类调用父类构造方法,class FatherString fatherName;Father()this.fatherName=“未知“;Father(String fatherName)this.fatherName=fatherName; class Son extends FatherStr
8、ing sonName;Son(String sonName)this.sonName=sonName; Son(String sonName,String fatherName)super(fatherName);this.sonName=sonName; ,子类调用父类构造方法,Son son1=new Son(“王小毛“,“王大毛“); Son son2=new Son(“张三“); System.out.println(son1.sonName); System.out.println(son1.fatherName); System.out.println(son2.sonName)
9、; System.out.println(son2.fatherName);,修饰符,修饰符的类型 访问控制修饰符(public,protected,private) static,abstract,final 修饰符的修饰内容(类,方法,变量) 修饰符的作用 使用修饰符的限制,成员变量或成员方法的访问控制,修饰符 同类 同包 子类 不同包 public 是 是 是 是 protected 是 是 是默认 是 是private 是,成员变量或成员方法的访问控制,包1,包2,public int v1; protected int v2; int v3 private int v4;,Class
10、A,ClassB,ClassC,ClassD extends ClassA,ClassB, ClassC,ClassD分别可以访问ClassA的哪些成员变量?,类的访问控制,顶层类只能是public或默认访问级别 public级别的类可以被同一个包或者其他包中的类访问 默认级别的类只能被同一个包中的类访问,public class Sample /public级别 class Sample /默认访问级别 protected class Sample /非法 private class Sample /非法,static关键字,类(static)变量,参见Count.java 类(static
11、)方法,参见Wrong.java 静态初始化程序,参见StaticBlock.java,静态变量和实例变量,静态变量在装载类的时候被分配内存并初始化,类只能被装载一次,所以静态变量在内存中只有一个拷贝 实例变量在创建实例时被分配内存并初始化,所以每个实例都有各自的实例变量 同一个类的实例之间共享静态变量,静态变量和实例变量,public class Count private int serialNumber;private static int counter;public Count() counter+;serialNumber = counter;System.out.println(
12、“My serialNumber is “ + serialNumber);public static void main(String args)System.out.println(“At first,counter=“+ counter);Count count1=new Count();System.out.println(“after creat count1, counter=“+counter);Count count2=new Count();System.out.println(“At last counter=“+counter);System.out.println(“c
13、ount1.serialNumber“+count1.serialNumber);System.out.println(“count2.serialNumber“+count2.serialNumber);System.out.println(“count1.counter“+count1.counter);System.out.println(“count2.counter“+count2.counter);System.out.println(“Count.counter“+Count.counter); ,静态变量和实例变量,堆区,Count对象,serialNumber=1,方法区,C
14、ount的类型信息,counter=1,count1引用变量,堆区,Count对象,serialNumber=1,方法区,Count的类型信息,counter=2,count1引用变量,count2引用变量,Count对象,serialNumber=2,Count count1=new Count();,Count count2=new Count();,Count.counter/合法 Count.serialNumber/非法,静态方法和实例方法,成员方法分为类方法和实例方法。用static修饰的方法叫类方法,或静态方法。 静态方法也和静态变量一样,不需创建类的实例,可以直接通过类名被访问
15、。 static方法不能被修饰成protected和abstract。,public class GeneralFunction public static int addUp(int x, int y) return x + y; public class UseGeneral public void method() int a = 9;int b = 10;int c = GeneralFunction.addUp(a, b);System.out.println(“addUp() gives “ + c); ,静态方法和实例方法,public class Wrong int x;voi
16、d method()x+;public static void test() x = 1; /非法method();/非法public static void main(String args) x = 9; /非法method();/非法 ,堆区,Wrong对象 实例变量x,Wrong对象 实例变量x,Wrong.test() ?,静态方法中不允许直接访问实例变量和实例方法,静态方法和实例方法,public class Correctint x;void method()x+; /合法 public static void main(String args) Correct r1=new C
17、orrect();r1.x = 9; / 合法r1.method();/ 合法Correct r2=new Correct();r2.x = 10; / 合法r2.method();/ 合法System.out.println(r1.x);System.out.println(r2.x); ,堆区,Correct对象 实例变量x,Correct对象 实例变量x,引用变量r1,引用变量r2,this关键字,this关键字引用当前实例 在static方法中不能使用this关键字,public class Sampleint x;Sample(int x)this.x=x;method(this);
18、void method(Sample s)s.x+; /合法 public static void test() this.x+; /非法 ,Sample s1=new Sample(1); Sample s2=new Sample(2); System.out.println(s1.x); System.out.println(s2.x);,堆区,Sample对象 实例变量x,Sample对象 实例变量x,引用变量s1,引用变量s2,静态初始化程序,类中可以包含静态代码块,它不存在于任何方法体中。当类被装载时,静态代码块只被执行一次。类中不同的静态块按它们在类中出现的顺序被依次执行。,pub
19、lic class Samplestatic int i = 5;static System.out.println(“ First Static code i= “+ i+ );static System.out.println(“ Second Static code i= “+ i+ );public static void main(String args) Sample s1=new Sample();Sample s2=new Sample();System.out.println(“At last, i= “+ i );,打印 First Static code i=5 Seco
20、nd Static code i=6 At last,i=7,final关键字,final类:不能被继承 final方法: 不能被子类覆盖 final变量:必须被显式的初始化,并且只能初始化一次,参见InitFinal0.java,public final class A public class B extends A /非法,public class Apublic final int method()return 1; public class B extends Apublic int method() /非法return 2; ,final变量 例:What will happen
21、when compile the following code?,public class Testfinal int x = 0;Test()x = 1; /非法final int aMethod()return x; ,final变量 例:What will happen when compile the following code?,1. class FinalTest 2. final int q; 3. 4. FinalTest() 5. this(0); 6. q = 1; 7. 8. FinalTest(int x) 9. q = x; 10. 11. ,FinalTest f
22、=new FinalTest();,final变量 例:What will happen when compile the following code?,1. class FinalTest 2. final int q; 3. 4. FinalTest() 5. 6. FinalTest(int x) 7. q = x; 8. 9. ,FinalTest f=new FinalTest();,native关键字,native只用来修饰方法。 native方法用其它语言(如C语言)实现,所以没有程序代码块。public static native int myNativeMethod(int
23、 p);,extends关键字和类的继承,继承是复用程序代码的有力手段,当多个类(Sub1,Sub2Sub100)之间存在相同的属性和方法,可从这些类中抽象出父类Base,在父类Base中定义这些相同的属性和方法,所有的Sub类无需重新定义这些属性和方法,只需通过extends语句来声明继承Base类: public class Sub extends Base Sub类就会自动拥有在Base类中定义的属性和方法。Java中不支持多继承 public class ClassC extends ClassA,ClassB /非法,abstract关键字,abstract修饰符可用来修饰类和成员方
24、法: 用abstract修饰的类表示抽象类,抽象类位于继承树的抽象层,抽象类不能被实例化,即不允许创建抽象类本身的实例。没有用abstract修饰的类称为具体类,具体类可以被实例化。 用abstract修饰的方法表示抽象方法,抽象方法没有方法体。抽象方法用来描述系统具有什么功能,但不提供具体的实现。没有用abstract修饰的方法称为具体方法,具体方法具有方法体。,public abstract class Base /Base是抽象类abstract void method1(); /抽象方法void method2() /具体方法System.out.println(“method2“);
25、 ,abstract关键字,一个类中有抽象方法,这个类必须是抽象类 抽象类中可以没有抽象方法,abstract class Baseabstract void method1();abstract void method2(); class Sub extends Base /编译出错,Sub类必须声明为抽象类void method1()System.out.println(“method1“); ,接口,在Java语言中,接口有两种意思: 一是指概念性的接口,即指系统对外提供的所有服务。类的所有能被外部使用者访问的方法构成了类的接口。 二是指用interface关键字定义的实实在在的接口,也
26、称为接口类型。它用于明确的描述系统对外提供的所有服务,它能够更加清晰的把系统的实现细节与接口分离。,public interface Transparency public static final int OPAQUE=1; public static final int BITMASK=2; public static final int TRANSLUCENT=3; public int getTransparency(); ,接口的特征,接口中只能包含public、static、final类型的成员变量和public、abstract类型的成员方法。 接口中不能有非抽象方法,publi
27、c interface Aint var; /编译出错void method1()System.out.println(“method1“); /编译出错protected void method2(); /编译出错static void method3()System.out.println(“method3“); /编译出错 ,接口的特征,接口之间允许存在继承关系interface Avoid method1(); interface Bvoid method2(); interface D extends A,B /合法 interface E implements A,B /错误,接口
28、的实现,接口由类来实现 一个类能实现许多接口。public class MyApplet extends Applet implements Runnable, MouseListener,接口的实现,interface SayHello void printMessage();class SayHelloImpl implements SayHello public void printMessage() System.out.println(“Hello“);,接口的实现,interface SayHello void printMessage();void receiveMessage(
29、);abstract class SayHelloImpl implements SayHello public void printMessage() System.out.println(“Hello“);,方法重载(overload),对于类的方法(包括从父类中继承的方法),如果有两个方法的方法名相同,但参数不一致,那么可以说,一个方法是另一个方法的重载方法。 重载方法必须满足以下条件: 方法名相同。 方法的参数类型、个数、顺序至少有一项不相同。 方法的返回类型可以不相同。 方法的修饰符可以不相同。,/java.lang.Math类的用于取最大值的max方法, /有多个重载方法。 pub
30、lic static int max(int a,int b) public static long max(long a,long b) public static float max(float a,float b) public static double max(double a,double b),int a=Math.max(1,2); double d=Math.max(1,2.0);,方法重载(overload),以下Sample类中已经定义了一个amethod()方法: public class Samplepublic void amethod(int i, String
31、s)/加入其他方法 下面哪些方法可以加入到Sample类中,并且保证编译正确呢? A)public void amethod(String s, int i) /可以 B)public int amethod(int i, String s)return 0; /不可以 C)private void amethod(int i, String mystring) /不可以 D)public void Amethod(int i, String s) /可以 E)abstract void amethod(int i); /不可以,方法覆盖(override),方法覆盖是指子类重新实现了父类中的
32、方法 以下代码中子类覆盖了父类的一个方法,然后定义了一个重载方法: public class Parent public void method() System.out.println(“Parent”); public class Child extends Parent public void method()System.out.println(“Child”); /overridepublic int method(int a) /overloadreturn 0; ,方法覆盖的约束条件,子类方法的名称、参数签名和返回类型必须与父类方法的名称、参数签名和返回类型一致。,public
33、class Base public void method() public class Sub extends Basepublic int method() /编译错误,返回类型不一致return 0; ,方法覆盖的约束条件,子类方法不能缩小父类方法的访问权限,但可以扩大访问权限,public class Parent public void method() public class Child extends Parent private void method() /编译错误 ,方法覆盖的约束条件,子类方法不能抛出比父类方法更多的异常class ExceptionA extends
34、Exceptionclass ExceptionB extends ExceptionAclass ExceptionC extends ExceptionB public class Parent void method() throws ExceptionB public class Child1 extends Parent void method()throws ExceptionA /非法 public class Child2 extends Parent void method()throws ExceptionC /合法 ,多态性,Java语言允许某个类型的引用变量引用子类的实
35、例,而且可以对这个引用变量进行类型转换: Animal animal=new Dog(); Dog dog=(Dog)animal; /向下转型,把Animal类型转换为Dog类型 Creature creature=animal; /向上转型,把Animal类型转换为Creature类型 animal=new Cat(); 如果把引用变量转换为子类类型,称为向下转型,如果把引用变量转换为父类类型,称为向上转型。 在进行引用变量的类型转换时,会受到各种限制。而且在通过引用变量访问它所引用的实例的静态属性、静态方法、实例属性、实例方法,以及从父类中继承的方法和属性时,Java虚拟机会采用不同的绑
36、定机制。,多态性(参见Tester.java),class FathersString var=“FatherVar“;static String staticVar=“StaticFatherVar“;void method()System.out.println(“Father method“);static void staticMethod()System.out.println(“Static Father method“); ,class Sons extends FathersString var=“SonVar“;static String staticVar=“StaticS
37、onVar“;void method()System.out.println(“Son method“);static void staticMethod()System.out.println(“Static Son method“);String sonVar=null;void sonMethod() ,多态性(参见Tester.java),public class Testerpublic void test()Fathers f=new Sons();/Fathers f=new Fathers();/Sons f=new Sons();/Sons f=(Sons)new Fathe
38、rs();System.out.println(f.var);System.out.println(f.staticVar);f.method();f.staticMethod();public static void main(String args)new Tester().test(); ,多态性,参见Tester.java 对于一个引用类型的变量,编译器按照它声明的类型处理。例如以下代码编译出错。Fathers fnew Sons();f.sonVar=“123”;f.sonMethod();如果要访问Sons的成员,必须通过强制转换:(Sons)f).sonVar=“123”;(So
39、ns)f).sonMethod();,Fathers,var method() staticVar staticMethod(),Sons,var method() staticVar staticMethod() sonVar sonMethod(),多态性,对于一个引用类型的变量,运行时按照它实际引用的对象处理。 例如以下代码虽然编译可以通过,但运行时会抛出ClassCastException。,Fathers,var method() staticVar staticMethod(),Sons,var method() staticVar staticMethod() sonVar so
40、nMethod(),Fathers f=new Fathers(); Sons s=(Sons)f;/throw exception when run,Animal a=new Dog(); Cat c=(Cat)a;/throw exception when run,多态性,成员变量、静态方法按照引用变量声明的类型静态绑定;实例方法按照引用变量引用的实例动态绑定 例如,对于以下这段代码: Fathers fnew Sons(); System.out.println(“f.var=”+f.var); System.out.println(“f.staticVar=”+f.staticVar)
41、; f.method(); f.staticMethod(); 运行时将会输出如下结果: f.var=FatherVar f.staticVar=StaticFaterVar Son method Static Father method,Fathers,var method() staticVar staticMethod(),Sons,var method() staticVar staticMethod() sonVar sonMethod(),例:What will be written to the standard output when the following program
42、 is run? (参见 PolyTester.java),参见PolyTester.java,class Base int i;Base() add(1);void add(int v) i+= v;void print() System.out.println(i); class Extension extends Base Extension()add(2);void add(int v) i+= v*2; ,public class PolyTester public static void main(String args) bogo(new Extension();static v
43、oid bogo(Base b) b.add(8);b.print(); ,例:What will be written to the standard output when the following program is run? (参见 PolyTester.java),以上代码创建的是Extension类的实例,所以在运行时,所有调用add()方法的过程,将始终和Extension类的add()方法动态绑定。 以下是程序依次对变量i的改变过程:初试值:i0step1:创建实例new Extension() 先调用父类的默认构造方法Base(),父类的默认构造方法中执行add(1),i
44、0+1*2 i=2,再调用子类的默认构造方法Extension(),子类的默认构造方法中执行add(2),i2+2*2i=6。 step2:执行add(8)i6+8*2i=22,本例子考察知识点: 方法动态绑定 子类调用父类的构造方法,内部类,内部类,是在一个类的内部定义的类。 匿名类是一种特殊的内部类。 内部类的特性 内部类的实例化,参见InnerInit.java,内部类,interface OuterIFC void method();public class Outerpublic class Inner1 /实例内部类public static class Inner2 /静态内部类
45、private OuterIFC o=new OuterIFC() int i=1;void method()i+; ; /一个实现了OuterIFC接口的匿名类OuterIFC getInstance()return o;void outerMethod()class Inner3; /局部内部类Inner3 in=new Inner3(); /end of class Outer,class Testerpublic void test()Outer.Inner1 in1=new Outer().new Inner1(); Outer.Inner1 in11=new Outer.Inner
46、1(); /非法Outer.Inner2 in2=new Outer().new Inner2();Outer.Inner2 in22=new Outer.Inner2(); ,内部类的特性,实例内部类可以直接访问嵌套类的成员。如果是定义在方法中的局部内部类,还可以访问该方法中的final型的局部变量和final型的方法参数。参见ClassA.java,class ClassAprivate int vA=0;class Bint vB=vA; void methodA(final int param1,int param2)final int localV=0;class Cint vC;v
47、oid methodC() int v1C=vA; /合法int v2C=localV; /合法int v3C=param1; /合法/ int v4C=param2; /非法/end of class C/end of methodA /end of class A,内部类的特性,静态内部类只能直接访问所嵌套类的静态成员,而不能直接访问所嵌套类的非静态的成员,如果一定要访问,必须通过外部嵌套类的实例访问。,class Aint vA=1;static class Bint vB=vA; /非法 class Cint vC=1;static class Dint vD=new C().vC;
48、/合法 ,内部类的特性,实例内部类不能声明任何static成员;静态内部类中可以声明static成员。 class Aclass Bstatic int var; /非法 class Cstatic class Dstatic int v; /合法static class E /合法 ,C.D.v=1; C.D.E e=new C.D.E();,降级(deprecation),在版本升级时,有些类、类的构造方法或成员方法被淘汰,这成为降级。,降级(deprecation),当升级代码时,用-deprecation标志来编译代码:javac -deprecation XXXXjava 例如编译DateConverter.java,