1 / 59

第4课 对象和类

参考《 Java 面向对象编程》的第6、7、8和12章. 第4课 对象和类. interface MyIFC{ void method1(); void method1(int a); } abstract class Base{ public void method1(){ System.out.println("hi"); } protected abstract void method2(); } class Sub extends Base implements MyIFC{ private int a;

bell
Download Presentation

第4课 对象和类

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 参考《Java面向对象编程》的第6、7、8和12章 第4课 对象和类 interface MyIFC{ void method1(); void method1(int a); } abstract class Base{ public void method1(){ System.out.println("hi"); } protected abstract void method2(); } class Sub extends Base implements MyIFC{ private int a; privatestatic 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++;} } • 构造方法 • 重载方法 • 覆盖方法 • 访问控制 • static变量,方法和初始代码块 • this引用的用途 • final类,方法和变量 • abstract类和方法,接口 • 解释如何以及何时使用内部类 • 降级,以及如何把Java程序从JDK的低版本升级到高版本

  2. 构造方法 • 声明构造方法的语法规则 • 重载构造方法,参见Employee.java • 默认构造方法, 参见Sample1.java • 子类调用父类的构造方法,参见Son.java,

  3. 构造方法的语法规则 • 一个新对象的初始化的最终步骤是去调用对象的构造方法。 • 构造方法必须满足以下条件: • 方法名必须与类名称完全相匹配; • 不要声明返回类型; • 不能被static、final、synchronized、abstract、native修饰。 public class Sample { int x; public Sample() { // No-arg constructor x=1; } public Sample(int x) { //int-arg constructor this.x=x; } }

  4. 构造方法的语法规则 public class Sample { int x; public void Sample() { x=1; } public static void main(String args[]){ Sample s=new Sample(); System.out.println(s.x); } }

  5. 重载构造方法 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 Employee() { this( " Unknown " ); } } Employee tom=new Employee("Tom",1000); Employee jack=new Employee("Jack"); Employee someone=new Employee();

  6. 默认构造方法 • 默认构造方法是没有参数的构造方法,你可以显式定义类的默认构造方法。 • 为了保证每个类至少有一个构造方法,如果定义的类中一个构造方法也没有写,Java将自动提供一个默认构造方法。该构造方法没有参数,用public 修饰,而且方法体为空。格式如下: public ClassName(){} • 只要类中显式定义了一个或多个构造方法,而且所有显式定义的构造方法都带参数,那么将失去默认构造方法。

  7. 默认构造方法 public class Sample1{} public class Sample2{ public Sample2(int a){System.out.println(“My Constructor”);} } public class Sample3{ public Sample3(){System.out.println(“My Default Constructor”);} } Sample1 s1=new Sample1(); Sample2 s2=new Sample2(); //非法 Sample2 s22=new Sample2(1); Sample3 s3=new Sample3();

  8. 子类调用父类构造方法 • 在构造子类对象时,JVM会先调用父类的构造方法 • 子类构造方法中通过super语句调用父类构造方法 • 如果子类构造方法中没有通过super语句调用父类构造方法,那么JVM会调用父类的默认构造方法,如果不存在默认构造方法,将导致编译错误

  9. 子类调用父类构造方法 class Father{ String fatherName; Father(){ this.fatherName=“未知"; } Father(String fatherName){ this.fatherName=fatherName; } } class Son extends Father{ String 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); System.out.println(son2.fatherName);

  10. 修饰符 • 修饰符的类型 • 访问控制修饰符(public,protected,private) • static,abstract,final • 修饰符的修饰内容(类,方法,变量) • 修饰符的作用 • 使用修饰符的限制

  11. 成员变量或成员方法的访问控制 修饰符 同类 同包 子类 不同包 public 是 是 是 是 protected 是 是 是 默认 是 是 private是

  12. 成员变量或成员方法的访问控制 包1 包2 ClassA public int v1; protected int v2; int v3 private int v4; ClassC ClassB ClassD extends ClassA ClassB, ClassC,ClassD分别可以访问ClassA的哪些成员变量?

  13. 类的访问控制 • 顶层类只能是public或默认访问级别 • public级别的类可以被同一个包或者其他包中的类访问 • 默认级别的类只能被同一个包中的类访问 public class Sample{…} //public级别 class Sample{…} //默认访问级别 protected class Sample{…} //非法 private class Sample{…} //非法

  14. static关键字 • 类(static)变量,参见Count.java • 类(static)方法,参见Wrong.java • 静态初始化程序,参见StaticBlock.java

  15. 静态变量和实例变量 • 静态变量在装载类的时候被分配内存并初始化,类只能被装载一次,所以静态变量在内存中只有一个拷贝 • 实例变量在创建实例时被分配内存并初始化,所以每个实例都有各自的实例变量 • 同一个类的实例之间共享静态变量

  16. 静态变量和实例变量 public class Count { private int serialNumber; private static int counter; public Count() { counter++; serialNumber = counter; System.out.println("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("count1.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); } }

  17. Count.counter//合法 Count.serialNumber//非法 静态变量和实例变量 Count count1=new Count(); 堆区 方法区 Count对象 Count的类型信息 count1引用变量 serialNumber=1 counter=1 Count count2=new Count(); 堆区 方法区 Count对象 Count的类型信息 count1引用变量 serialNumber=1 counter=2 count2引用变量 Count对象 serialNumber=2

  18. 静态方法和实例方法 • 成员方法分为类方法和实例方法。用static修饰的方法叫类方法,或静态方法。 • 静态方法也和静态变量一样,不需创建类的实例,可以直接通过类名被访问。 • 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); } }

  19. 静态方法和实例方法 堆区 public class Wrong { int x; void method(){x++;} public static void test() { x = 1; //非法 method();//非法 } public static void main(String args[]) { x = 9; //非法 method();//非法 } } Wrong对象 实例变量x Wrong对象 实例变量x Wrong.test() ? 静态方法中不允许直接访问实例变量和实例方法

  20. 静态方法和实例方法 堆区 public class Correct{ int x; void method(){ x++; //合法 } public static void main(String args[]) { Correct r1=new Correct(); 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

  21. this关键字 Sample s1=new Sample(1); Sample s2=new Sample(2); System.out.println(s1.x); System.out.println(s2.x); • this关键字引用当前实例 • 在static方法中不能使用this关键字 public class Sample{ int x; Sample(int x){ this.x=x; method(this); } void method(Sample s){ s.x++; //合法 } public static void test() { this.x++; //非法 } } 堆区 Sample对象 实例变量x Sample对象 实例变量x 引用变量s1 引用变量s2

  22. 静态初始化程序 • 类中可以包含静态代码块,它不存在于任何方法体中。当类被装载时,静态代码块只被执行一次。类中不同的静态块按它们在类中出现的顺序被依次执行。 public class Sample{ static 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 Second Static code i=6 At last,i=7

  23. final关键字 • final类:不能被继承 • final方法: 不能被子类覆盖 • final变量:必须被显式的初始化,并且只能初始化一次,参见InitFinal0.java public class A{ public final int method(){ return 1; } } public class B extends A{ public int method(){ //非法 return 2; } } public final class A{} public class B extends A{} //非法

  24. final变量例:What will happen when compile the following code? public class Test{ final int x = 0; Test(){ x = 1; //非法 } final int aMethod(){ return x; } }

  25. 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=new FinalTest();

  26. 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();

  27. native关键字 • native只用来修饰方法。 • native方法用其它语言(如C语言)实现,所以没有程序代码块。 public static native int myNativeMethod(int p);

  28. extends关键字和类的继承 • 继承是复用程序代码的有力手段,当多个类(Sub1,Sub2…Sub100)之间存在相同的属性和方法,可从这些类中抽象出父类Base,在父类Base中定义这些相同的属性和方法,所有的Sub类无需重新定义这些属性和方法,只需通过extends语句来声明继承Base类: public class Sub extends Base{…} Sub类就会自动拥有在Base类中定义的属性和方法。 • Java中不支持多继承 public class ClassC extends ClassA,ClassB{} //非法

  29. abstract关键字 • abstract修饰符可用来修饰类和成员方法: • 用abstract修饰的类表示抽象类,抽象类位于继承树的抽象层,抽象类不能被实例化,即不允许创建抽象类本身的实例。没有用abstract修饰的类称为具体类,具体类可以被实例化。 • 用abstract修饰的方法表示抽象方法,抽象方法没有方法体。抽象方法用来描述系统具有什么功能,但不提供具体的实现。没有用abstract修饰的方法称为具体方法,具体方法具有方法体。 public abstract class Base{ //Base是抽象类 abstract void method1(); //抽象方法 void method2(){ //具体方法 System.out.println("method2"); } }

  30. abstract关键字 • 一个类中有抽象方法,这个类必须是抽象类 • 抽象类中可以没有抽象方法 abstract class Base{ abstract void method1(); abstract void method2(); } class Sub extends Base{ //编译出错,Sub类必须声明为抽象类 void method1(){System.out.println("method1");} }

  31. 接口 • 在Java语言中,接口有两种意思: • 一是指概念性的接口,即指系统对外提供的所有服务。类的所有能被外部使用者访问的方法构成了类的接口。 • 二是指用interface关键字定义的实实在在的接口,也称为接口类型。它用于明确的描述系统对外提供的所有服务,它能够更加清晰的把系统的实现细节与接口分离。 public interface Transparency { public static final int OPAQUE=1; public static final int BITMASK=2; public static final int TRANSLUCENT=3; public int getTransparency(); }

  32. 接口的特征 • 接口中只能包含public、static、final类型的成员变量和public、abstract类型的成员方法。 • 接口中不能有非抽象方法 public interface A{ int var; //编译出错 void method1(){System.out.println("method1");} //编译出错 protected void method2(); //编译出错 static void method3(){System.out.println("method3");} //编译出错 }

  33. 接口的特征 • 接口之间允许存在继承关系 interface A{ void method1(); } interface B{ void method2(); } interface D extends A,B{} //合法 interface E implements A,B{} //错误

  34. 接口的实现 • 接口由类来实现 • 一个类能实现许多接口。 public class MyApplet extends Applet implements Runnable, MouseListener{ }

  35. 接口的实现 interface SayHello { void printMessage(); } class SayHelloImpl implements SayHello { public void printMessage() { System.out.println("Hello"); } }

  36. 接口的实现 interface SayHello { void printMessage(); void receiveMessage(); } abstract class SayHelloImpl implements SayHello { public void printMessage() { System.out.println("Hello"); } }

  37. 方法重载(overload) • 对于类的方法(包括从父类中继承的方法),如果有两个方法的方法名相同,但参数不一致,那么可以说,一个方法是另一个方法的重载方法。 • 重载方法必须满足以下条件: • 方法名相同。 • 方法的参数类型、个数、顺序至少有一项不相同。 • 方法的返回类型可以不相同。 • 方法的修饰符可以不相同。 //java.lang.Math类的用于取最大值的max方法, //有多个重载方法。 public 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);

  38. 方法重载(overload) 以下Sample类中已经定义了一个amethod()方法: public class Sample{ public void amethod(int i, String 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); //不可以

  39. 方法覆盖(override) • 方法覆盖是指子类重新实现了父类中的方法 • 以下代码中子类覆盖了父类的一个方法,然后定义了一个重载方法: public class Parent { public void method() {System.out.println(“Parent”); } } public class Child extends Parent { public void method(){System.out.println(“Child”);} //override public int method(int a) { //overload return 0; } }

  40. 方法覆盖的约束条件 • 子类方法的名称、参数签名和返回类型必须与父类方法的名称、参数签名和返回类型一致。 public class Base { public void method() {…} } public class Sub extends Base{ public int method() { //编译错误,返回类型不一致 return 0; } }

  41. 方法覆盖的约束条件 • 子类方法不能缩小父类方法的访问权限,但可以扩大访问权限 public class Parent { public void method() { } } public class Child extends Parent { private void method() { //编译错误 } }

  42. 方法覆盖的约束条件 • 子类方法不能抛出比父类方法更多的异常 class ExceptionA extends Exception{} class ExceptionB extends ExceptionA{} class 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 {} //合法 }

  43. 多态性 • Java语言允许某个类型的引用变量引用子类的实例,而且可以对这个引用变量进行类型转换: Animal animal=new Dog(); Dog dog=(Dog)animal; //向下转型,把Animal类型转换为Dog类型 Creature creature=animal; //向上转型,把Animal类型转换为Creature类型 animal=new Cat(); • 如果把引用变量转换为子类类型,称为向下转型,如果把引用变量转换为父类类型,称为向上转型。 • 在进行引用变量的类型转换时,会受到各种限制。而且在通过引用变量访问它所引用的实例的静态属性、静态方法、实例属性、实例方法,以及从父类中继承的方法和属性时,Java虚拟机会采用不同的绑定机制。

  44. 多态性(参见Tester.java) class Fathers{ String 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 Fathers{ String var="SonVar"; static String staticVar="StaticSonVar"; void method(){System.out.println("Son method");} static void staticMethod(){System.out.println("Static Son method");} String sonVar=null; void sonMethod(){} }

  45. 多态性(参见Tester.java) public class Tester{ public void test(){ Fathers f=new Sons(); //Fathers f=new Fathers(); //Sons f=new Sons(); //Sons f=(Sons)new Fathers(); System.out.println(f.var); System.out.println(f.staticVar); f.method(); f.staticMethod(); } public static void main(String args[]){ new Tester().test(); } }

  46. Fathers Sons var method() staticVar staticMethod() var method() staticVar staticMethod() sonVar sonMethod() 多态性 参见Tester.java • 对于一个引用类型的变量,编译器按照它声明的类型处理。 例如以下代码编译出错。 Fathers f=new Sons(); f.sonVar=“123”; f.sonMethod(); 如果要访问Sons的成员,必须通过强制转换: ((Sons)f).sonVar=“123”; ((Sons)f).sonMethod();

  47. Fathers Sons var method() staticVar staticMethod() var method() staticVar staticMethod() sonVar sonMethod() 多态性 • 对于一个引用类型的变量,运行时按照它实际引用的对象处理。 • 例如以下代码虽然编译可以通过,但运行时会抛出ClassCastException。 Fathers f=new Fathers(); Sons s=(Sons)f;//throw exception when run Animal a=new Dog(); Cat c=(Cat)a;//throw exception when run

  48. Fathers Sons var method() staticVar staticMethod() var method() staticVar staticMethod() sonVar sonMethod() 多态性 • 成员变量、静态方法按照引用变量声明的类型静态绑定;实例方法按照引用变量引用的实例动态绑定 例如,对于以下这段代码: Fathers f=new Sons(); System.out.println(“f.var=”+f.var); System.out.println(“f.staticVar=”+f.staticVar); f.method(); f.staticMethod(); 运行时将会输出如下结果: f.var=FatherVar f.staticVar=StaticFaterVar Son method Static Father method

  49. 例:What will be written to the standard output when the following program is run? (参见 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; } } 参见PolyTester.java public class PolyTester { public static void main(String args[]) { bogo(new Extension()); } static void bogo(Base b) { b.add(8); b.print(); } }

  50. 例:What will be written to the standard output when the following program is run? (参见 PolyTester.java) • 以上代码创建的是Extension类的实例,所以在运行时,所有调用add()方法的过程,将始终和Extension类的add()方法动态绑定。 • 以下是程序依次对变量i的改变过程: • 初试值:i=0 • step1:创建实例new Extension() 先调用父类的默认构造方法Base(),父类的默认构造方法中执行add(1),i=0+1*2 → i=2,再调用子类的默认构造方法Extension(),子类的默认构造方法中执行add(2),i=2+2*2→i=6。 • step2:执行add(8) i=6+8*2→i=22 本例子考察知识点: • 方法动态绑定 • 子类调用父类的构造方法

More Related