day27
接口
package com.saas; public interface MyInterface { int NUM = 100; public void test(); }package com.saas; public class MyClass01 extends Object implements MyInterface{ int NUM = 200; @Override public void test() { System.out.println(NUM); System.out.println(this.NUM); // System.out.println(super.NUM); // super说的是Object对象,而Object类中不含有NUM属性,所以无法调用 System.out.println(MyInterface.NUM); System.out.println("this is test method."); } }package com.saas; public class Test { public static void main(String[] args) { System.out.println(MyInterface.NUM); MyClass01 mc = new MyClass01(); mc.test(); } }在接口MyInterface中分别定义了NUM变量和test()方法
根据接口的特点:
NUM是public,static和final修饰的
test()方法是public abstract修饰的
所以其实现类中应该含有NUM属性以及test方法
如果在实现类中没有做任何更改,则实现类中一定含有NUM属性,其值也是接口中一样的数值
如果在实现类中再定义一个NUM变量,则各自是各自的值,但是接口中的NUM不能通过super来调用,只能通过接口名来调用
test方法在子类中必须实现,否则该MyClass01类必须是抽象类
package com.saas; public class MyClass02 implements MyInterface { @Override public void test() { System.out.println("this is test method in MyClass02"); } }package com.saas; public class Test02 { public static void main(String[] args) { MyClass01 mc1 = new MyClass01(); System.out.println(mc1.NUM); mc1.test(); System.out.println("==================="); MyClass02 mc2 = new MyClass02(); System.out.println(mc2.NUM); mc2.test(); System.out.println(mc2.count); System.out.println("********************"); MyInterface mc3 = new MyClass01(); System.out.println(mc3.NUM); mc3.test(); System.out.println("==================="); MyInterface mc4 = new MyClass02(); System.out.println(mc4.NUM); mc4.test(); // System.out.println(mc4.count); // 实现类对象赋值给接口引用,无法调用其实现类特有的成员 } }对于mc3和mc4两个引用来说,都属于MyInfterface类型,但是分别由其实现类创建
那么通过引用调用属性和方法,最终都应该表现为其实现类的表现形式
接口引用不可以调用实现类所特有的属性和方法
package com.saas.oo1; public interface Swimmable { void swim(); }package com.saas.oo1; public interface Runnable { void run(); }package com.saas.oo1; public class Animal { public void eat(){ System.out.println("eatting..."); } public void sleep(){ System.out.println("sleeping..."); System.out.println("zzzzzZZZZZZ"); } }package com.saas.oo1; public class Dog extends Animal implements Swimmable, Runnable{ @Override public void run() { System.out.println("撒欢儿跑"); } @Override public void swim() { System.out.println("狗刨"); } @Override public void eat() { System.out.println("狗喜欢吃骨头"); super.eat(); } public void bark(){ System.out.println("wangwangwang"); } }package com.saas.oo1; public class Test { public static void main(String[] args) { Dog d = new Dog(); d.run(); System.out.println("------------------"); d.swim(); System.out.println("------------------"); d.sleep(); System.out.println("------------------"); d.eat(); System.out.println("------------------"); System.out.println("=================="); Animal ad = new Dog(); ad.sleep(); System.out.println("------------------"); ad.eat(); System.out.println("------------------"); // ad.swim(); // ad是属于Animal类型,不能调用Animal里面不存在的swim()方法 System.out.println("------------------"); // ad.run(); // ad是属于Animal类型,不能调用Animal里面不存在的run()方法 System.out.println("=================="); Swimmable sd = new Dog(); System.out.println("------------------"); sd.swim(); System.out.println("------------------"); // sd.run(); System.out.println("------------------"); // sd.eat(); System.out.println("------------------"); // sd.sleep(); System.out.println("=================="); Runnable rd = new Dog(); System.out.println("------------------"); // rd.swim(); System.out.println("------------------"); rd.run(); System.out.println("------------------"); // rd.eat(); System.out.println("------------------"); // rd.sleep(); } }Dog d = new Dog(); // 将狗当狗看 Animal ad = new Dog(); // 将狗当动物看,只能调用动物和狗共同的属性和行为 Swimmable sd = new Dog(); // 将狗当会游泳的东西看,只能调用会游泳的东西和狗共同的属性和行为 Runnable rd = new Dog(); // 将狗当会跑的东西看,只能调用会跑的东西和狗共同的属性和行为 //不同引用所能看到的对象范围不同,只能调用自身类型中所声明的部分 //以上后三行代码构成了多态,其中最后两行是接口实现的多态,第二行是继承实现的多态引用类型,仅可调用自己的类型的成员
常见的关系:
类与类:
单继承
extends 父类名称
类与接口:
多实现
implements 接口1,接口2, 接口3 ...
接口与接口:
多继承
extends 接口1, 接口2, 接口3...
package com.saas.oo1; public interface Liangqi extends Swimmable, Runnable{ }两栖类动物本身被定义成接口,可以继承自Swimmable接口和Runnable接口
常量接口
将多个常用于表示状态或者固定值的变量,以静态常量的形式定义在接口中统一管理,提到代码的可读性
package com.saas.oo2; public interface Contants { int MALE = 1; int FEMALE = 0; int score01 = 10; int score02 = 25; int score03 = 40; int score04 = 60; }接口是定义常量的最佳场所
接口的好处
降低程序的耦合性
更自然地使用多态
设计与实现的完全分离
更容易搭建程序框架
更容易实现更换具体实现
接口总结
概念:
微观:接口是一种能力或约定
宏观:接口是一种标准
与类的异同:
没有构造方法
仅可定义公开的静态的最终的变量和公开的抽象的方法
接口的应用:
Java特点是单继承,当父类方法种类无法满足子类需求时,可以实现接口扩展子类功能
接口的规范:
任何实现接口的类,必须实现接口中的方法,否则该类继续时抽象类
实现接口中的方法,必须是用public修饰的
常量接口:
用来存放固定不变的指定地方
可以用统一的接口来访问和管理
接口的应用
需求:
学院要求有学院的基本信息
学院的老师也要有基本信息
学院的打印机可以分别打印学院的基本信息和教师的基本信息
设计这样一个系统,要求要有较好的可扩展性和可维护性
package com.saas.oo3; public class College implements Introduce{ private Printer printer; public void setPrinter(Printer printer) { this.printer = printer; } @Override public String info() { return "i am a collage"; } // 学院的打印机来打印教师的信息 public void printContent(Introduce tea){ // printer是打印机对象,是学院类中的一个打印机属性 // 学院的打印机调用打印机的打印方法,将教师的详细信息进行打印 printer.print(tea.info()); } }package com.saas.oo3; public interface Introduce { String info(); }package com.saas.oo3; public class Teacher implements Introduce{ @Override public String info() { return "i am a teacher."; } }package com.saas.oo3; public interface Printer { void print(String content); }package com.saas.oo3; public class BlackPrinter implements Printer{ @Override public void print(String content) { System.out.println("start black white printing ..."); System.out.println(content); } }package com.saas.oo3; public class ColorPrinter implements Printer{ @Override public void print(String content) { System.out.println("start color printing ..."); System.out.println(content); } }package com.saas.oo3; public class Test { public static void main(String[] args) { Teacher tea = new Teacher(); College coll = new College(); Printer color = new ColorPrinter(); coll.setPrinter(color); coll.printContent(coll); System.out.println("-------------------"); coll.printContent(tea); System.out.println("===================="); Printer black = new BlackPrinter(); coll.setPrinter(black); coll.printContent(coll); System.out.println("-------------------"); coll.printContent(tea); } }这个案例相对与上次的案例来说扩展性和维护性变得更好
我们发现Teacher类和College类中都含有String类型的info方法,那么运用抽象的特点,将像的部分放到接口(Introduce)中,然后让Teacher类和College类分别实现该Introduce接口
将原本学院College类中的两个方法printContent合二为一,原本的两个参数College和Teacher现在都可以使用一个Introduc而引用来统一管理,原本含有College参数和Teacher参数的两个方法,现在才换成了一个含有College和Teacher的共同接口的Introduce类型的引用的一个方法
这么做的 好处是,我们新增学生类,College类的printContent方法无需做任何修改,只需要让学生类Student实现Introduce接口即可
今天关于打印机也做了升级,我们发现打印机虽然满足is a的关系,彩色打印机是一种打印,但是如果两个类中没有共同的代码块,更好的做法还是使用接口而不是继承关系
最终的运行结果如下:
start color printing ... i am a collage ------------------- start color printing ... i am a teacher. ==================== start black white printing ... i am a collage ------------------- start black white printing ... i am a teacher.这样的可扩展性和维护性,相对于之前有所提升。