thinking in java test chapter9接口(1)~(10)
2016-09-12 15:15
525 查看
抽象方法是没有方法体的方法,java提供的一种机制,仅有声明而没有方法体。语法:abstract void f();
包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。
抽象类无法创建对象,创建抽象类的对象是不安全的。
从抽象类继承产生一个新类,必须为基类中所有抽象方法提供方法定义。如果不这样做,那么意味着新类中还有至少一个抽象方法,根据抽象类的定义,这个新类也是抽象类,该类也必须用abstract声明为抽象类。
练习(1):修改第八章练习9中的Rodent,使其成为一个抽象类。只要有可能,就将Rodent的方法声明为抽象方法。
练习(2):创建一个不包含任何抽象方法的抽象类,并验证我们不能为该类创建任何实例。
练习(3):创建一个基类,让它包含抽象方法print(),并在导出类中覆盖该方法。覆盖后的方法版本可以打印出导出类中定义的某个整形变量的值。在定义该变量之处,赋予它非零值。在基类的构造器中调用这个方法。现在,在main()方法中,创建一个导出类对象,然后调用它的print()方法。请解释发生的情形。
输出:
PrintDrive : 0
PrintDrive : 10
前面第8章已经说过初始化。
在类的初始化时,jvm会先给对象分配一块空间,所有的成员都被暂时赋值为0,对象引用赋值为null,这时int值还是0,然后从基类开始调用构造方法,在基类的构造方法中,调用了print()方法,注意此时调用的print()是导出类的方法,看内存示例图。
看似是调用了基类的print()的方法,其实是调用了自身的方法,调用某类的方法是需要该类的实例,但导出类中根本没有基类的实例成员。
在完成基类构造方法的调用之前,导出类的其他成员都不会初始化,此时int值是0,所以最终先输出:PrintDrive : 0
完成基类构造方法调用后,然后进行自身的成员变量的初始化,这时int值被赋为10。然后调用自身的构造方法,在构造方法里调用了重写的抽象方法print(),所以此时再输出:PrintDrive : 10
练习(4):创建一个不包含任何方法的抽象类,从它那儿导出一个类,并添加一个方法。创建一个静态方法,它可以接受指向基类的引用,将其向下转型到导出类,然后再调用该静态方法。在main()中,展示它的运行情况。然后,为基类中的方法加上abstract声明,这样就不再需要向下转型。
笔者实在不知道这个练习在将声明,想让读者理解什么,如果你能读懂题目的目的的话,请指导笔者。
abstract的类是至少包含一个抽象方法,而interface是完全的抽象类,它里面的所有方法必须是抽象的,不提供具体实现的。(可以规定参数列表返回值类型等,但不能有方法体)接口提供了形式,没有任何具体实现。
接口也可以包含域,但是这些域隐式的是static和final。
练习(5):在某个包内创建一个接口,内含桑方法,然后在另一个包中实现此接口。
创建接口同创建类相似,点new然后出来这个对话框,选interface即可
在另一个包内
练习(6):证明接口内所有的方法都是自动public的。
前面曾说到重写(覆盖)的几个规则,重写就是对父类方法的重新编写,接口的规则其实符合重写,与类的继承的重写相比,只不过接口是必须重写所有方法。
在重写的几个规则里,有一个规定:派生类重写的方法的权限不能低于基类方法的权限。我们可以运用这一规则完成题目。
如代码,当我们把重写自接口的方法fi()的权限改成包权限时,此时,编译器报错:
这是重写权限小于父类方法的错误,在最后,明确的指出了,原方法的权限:was “public”.
可见,接口的方法确实是默认public的。
练习(7):修改第八章中的练习9,使Rodent成为一个接口。
练习(8):在polymorphism.Sandwich.java中,创建接口FastFood并添加合适的方法,然后修改Sandwich以实现接口。
其他简单代码略,请见书本P158
练习(9):重构Music5.java,将在Wind,Percussion和Stringed中的公共方法移入一抽象类中。
其实就是在接口中添加toString()方法。
其它代码见书本P173
练习(10):修改Music5.java,添加Playable接口。将play()的声明从Instrument中移到Playable中。通过将Playable包括在Implements列表中,把Playable添加到导出类中。修改tune(),使它接受Playable而不是Instrument作为参数。
可以看到,这个练习也许涉及到了设计模式的知识,暂时无法理解,记住这种做法。
包含抽象方法的类叫做抽象类。如果一个类包含一个或多个抽象方法,该类必须被限定为抽象的。
抽象类无法创建对象,创建抽象类的对象是不安全的。
从抽象类继承产生一个新类,必须为基类中所有抽象方法提供方法定义。如果不这样做,那么意味着新类中还有至少一个抽象方法,根据抽象类的定义,这个新类也是抽象类,该类也必须用abstract声明为抽象类。
练习(1):修改第八章练习9中的Rodent,使其成为一个抽象类。只要有可能,就将Rodent的方法声明为抽象方法。
abstract class Rodent{ public Rodent(){ shanghai = 100; System.out.println("Rodent"); } private int shanghai; public abstract void bite(); @Override public abstract String toString(); } class Mouse extends Rodent{ private int sh; public Mouse(){ sh = 1000; System.out.println("Mouse"); } @Override public void bite() { System.out.println("造成伤害" +sh + "点" ); } @Override public String toString() { return "Mouse"; } }
练习(2):创建一个不包含任何抽象方法的抽象类,并验证我们不能为该类创建任何实例。
public class Test1 { public static void main(String[] args) { absTest abs = new absTest();//编译器报错:xxx is abstract ,cannot be instantiated; } } abstract class absTest{}
练习(3):创建一个基类,让它包含抽象方法print(),并在导出类中覆盖该方法。覆盖后的方法版本可以打印出导出类中定义的某个整形变量的值。在定义该变量之处,赋予它非零值。在基类的构造器中调用这个方法。现在,在main()方法中,创建一个导出类对象,然后调用它的print()方法。请解释发生的情形。
public class Test3 { public static void main(String[] args){ new PrinDrive().print(); } } abstract class PrinTest{ public PrinTest(){ print(); } abstract void print(); } class PrinDrive extends PrinTest{ private int id = 10; @Override void print() { System.out.println("PrintDrive : " + id); } }
输出:
PrintDrive : 0
PrintDrive : 10
前面第8章已经说过初始化。
在类的初始化时,jvm会先给对象分配一块空间,所有的成员都被暂时赋值为0,对象引用赋值为null,这时int值还是0,然后从基类开始调用构造方法,在基类的构造方法中,调用了print()方法,注意此时调用的print()是导出类的方法,看内存示例图。
看似是调用了基类的print()的方法,其实是调用了自身的方法,调用某类的方法是需要该类的实例,但导出类中根本没有基类的实例成员。
在完成基类构造方法的调用之前,导出类的其他成员都不会初始化,此时int值是0,所以最终先输出:PrintDrive : 0
完成基类构造方法调用后,然后进行自身的成员变量的初始化,这时int值被赋为10。然后调用自身的构造方法,在构造方法里调用了重写的抽象方法print(),所以此时再输出:PrintDrive : 10
练习(4):创建一个不包含任何方法的抽象类,从它那儿导出一个类,并添加一个方法。创建一个静态方法,它可以接受指向基类的引用,将其向下转型到导出类,然后再调用该静态方法。在main()中,展示它的运行情况。然后,为基类中的方法加上abstract声明,这样就不再需要向下转型。
public class Test4 { public static void main(String[] args){ Test4Abs t = new Child(); Child.g(t);//6,然后调用该静态方法 //7,运行后输出child created } } abstract class Test4Abs{//1,创建一个不包含任何方法的抽象类 abstract void f();//8,为基类方法添加abstract } class Child extends Test4Abs{//2,从它那儿到处一个类 void f(){};//3,添加一个方法 public Child(){ System.out.println("child created"); } public static void g(Test4Abs t4){//4,再添加一个静态方法,接受指向基类的引用 t4 = new Child();//5,向下转型到导出类 } }
笔者实在不知道这个练习在将声明,想让读者理解什么,如果你能读懂题目的目的的话,请指导笔者。
abstract的类是至少包含一个抽象方法,而interface是完全的抽象类,它里面的所有方法必须是抽象的,不提供具体实现的。(可以规定参数列表返回值类型等,但不能有方法体)接口提供了形式,没有任何具体实现。
接口也可以包含域,但是这些域隐式的是static和final。
练习(5):在某个包内创建一个接口,内含桑方法,然后在另一个包中实现此接口。
创建接口同创建类相似,点new然后出来这个对话框,选interface即可
public interface Excample { void fi();//方法是默认public的,如果是包访问权限,那么接口就有很大限制,失去了意义。 void g(int i); boolean h(float f); }
在另一个包内
public class InterfaceLearn implements Excample { @Override public void fi() { } @Override public void g(int i) { } @Override public boolean h(float f) { return false; } }
练习(6):证明接口内所有的方法都是自动public的。
前面曾说到重写(覆盖)的几个规则,重写就是对父类方法的重新编写,接口的规则其实符合重写,与类的继承的重写相比,只不过接口是必须重写所有方法。
在重写的几个规则里,有一个规定:派生类重写的方法的权限不能低于基类方法的权限。我们可以运用这一规则完成题目。
public class InterfaceLearn implements Excample { @Override void fi() {//此时该方法的权限为包权限 }
如代码,当我们把重写自接口的方法fi()的权限改成包权限时,此时,编译器报错:
这是重写权限小于父类方法的错误,在最后,明确的指出了,原方法的权限:was “public”.
可见,接口的方法确实是默认public的。
练习(7):修改第八章中的练习9,使Rodent成为一个接口。
interface Rodent{ //没有构造方法 int shanghai = 10;//域必须是初始化有值的 public abstract void bite();//所有方法都是没有方法体的 public abstract 编译器是暗色显示,因为没有写的必要,是默认的 @Override public abstract String toString(); }
练习(8):在polymorphism.Sandwich.java中,创建接口FastFood并添加合适的方法,然后修改Sandwich以实现接口。
public class Sandwich extends PortableLunch implements FastFood{ public Sandwich(){ System.out.println("Sandwich"); } public static void main(String[] args){ new Sandwich().cook(); } @Override public void cook() { Bread b = new Bread(); Cheese c = new Cheese(); Lettuce l = new Lettuce(); } } interface FastFood{ void cook(); }
其他简单代码略,请见书本P158
练习(9):重构Music5.java,将在Wind,Percussion和Stringed中的公共方法移入一抽象类中。
其实就是在接口中添加toString()方法。
interface Instrument{ int VALUE = 5;//static &final void play(Note n); void adjust(); String toString(); }
其它代码见书本P173
练习(10):修改Music5.java,添加Playable接口。将play()的声明从Instrument中移到Playable中。通过将Playable包括在Implements列表中,把Playable添加到导出类中。修改tune(),使它接受Playable而不是Instrument作为参数。
public class Music5 { static void tune(Playable p){ p.play(Note.FIRST); } static void tuneAll(Playable[] e){ for (Playable p : e) { tune(p); } } public static void main(String[] args){ Playable[] orchestra = {new Wind(), new Percussion(),new Stringed(), new Brass(),new Woodwing()}; tuneAll(orchestra); } } enum Note{ FIRST,SECCOND,THIRD; } interface Instrument{ int VALUE = 5;//static &final void adjust(); String toString(); } interface Playable{ void play(Note n); } class Wind implements Instrument,Playable{ @Override public void play(Note n) { System.out.println(this + "play " + n); } @Override public void adjust() { System.out.println(this + "adjust"); } @Override public String toString() { return "Wind"; } }
可以看到,这个练习也许涉及到了设计模式的知识,暂时无法理解,记住这种做法。
相关文章推荐
- caffe的python接口学习(10):微调 & 直接训练
- 背水一战 Windows 10 (122) - 其它: 通过 Windows.System.Profile 命名空间下的类获取信息, 查找指定类或接口的所在程序集的所有子类和子接口
- 【无GPU】windows10+VS2013+caffe安装【python接口】
- (原创)c#学习笔记10--定义类成员03--接口的实现01--显示实现接口成员
- Java基础10 接口的继承与抽象类
- [作业10-11]1.编写一个类立方体Cub,让其实现IEnumarable接口,细节是令其可以遍历迭代长宽高,并做一个客户代码验证。
- Java微信二次开发之10-解析接口中的消息创建时间CreateTime 并转换成需要的格式
- 关于WinCE流接口驱动支持10以上的端口号(COM10)
- day 10:Java的继承和接口
- 10、mybatis的接口编程
- 用c#开发微信 (10) JS-SDK 基本用法- 分享接口“发送到朋友”
- Java基础10 接口的继承与抽象类
- 【Java学习笔记】10.继承、抽象类、接口
- 微信公众帐号开发教程第10篇-解析接口中的消息创建时间CreateTime(10)
- [Java 10 泛型] 泛型通配符 Info<?> i = new Info<String>(); 在程序中定义没有方法的接口,称之为标识接口
- php实现国际汇率兑换接口ZZ 分类: Android开发 2014-05-30 10:58 105人阅读 评论(0) 收藏
- (原创)c#学习笔记10--定义类成员03--接口的实现02--用非公共的可访问性添加属性存取器
- SAP接口编程-RFC系列10 : BAPI控件的DimAs方法
- 如何正确认识VLAN 接口10与VLAN10?
- [Java 10 泛型] 泛型通配符 Info<?> i = new Info<String>(); 在程序中定义没有方法的接口,称之为标识接口