写在前面
Hello大家好, 我是【麟-小白】,一位软件工程专业的学生,喜好计算机知识。希望大家能够一起学习进步呀!本人是一名在读大学生,专业水平有限,如发现错误或不足之处,请多多指正!谢谢大家!!!
如果小哥哥小姐姐们对我的文章感兴趣,请不要吝啬你们的小手,多多点赞加关注呀!❤❤❤ 爱你们!!!
目录
【往期回顾】
一文带你深入理解【Java基础】· 面向对象编程(下)②代码块、final和abstract
一文带你深入理解【Java基础】· 面向对象编程(下)①static和main方法
一文带你深入理解【Java基础】· 面向对象编程(中)③Object类和包装类的使用
一文带你深入理解【Java基础】· 面向对象编程(中)②子类对象实例化和多态
一文带你深入理解【Java基础】· 面向对象编程(中)①继承、方法的重写、权限修饰符和super
一文带你深入理解【Java基础】· 面向对象编程(上)②重载、封装、构造器、this、package和import
一文带你深入理解【Java基础】· 面向对象编程(上)①面向对象的理解、类和对象、对象的创建使用和属性
【习题总结】
1. 接口(interface)
1.1 接口是什么
- 一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
- 另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都支持USB连接。
- 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。
- 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
- 接口(interface)是抽象方法和常量值定义的集合。
接口的特点:
- 用interface来定义。
- 接口中的所有成员变量都默认是由public static final修饰的。
- 接口中的所有抽象方法都默认是由public abstract修饰的。
- 接口中没有构造器。
- 接口采用多继承机制。
- 定义Java类的语法格式:先写extends,后写implements
- class SubClass extends SuperClass implements InterfaceA{ }
- 一个类可以实现多个接口,接口也可以继承其它接口。
- 实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
- 接口的主要用途就是被实现类实现。(面向接口编程)
- 与继承关系类似,接口与实现类之间存在多态性
- 接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义(JDK7.0及之前),而没有变量和方法的实现。
1.2 接口(interface)演示代码
/* * 接口的使用 * 1.接口使用interface来定义 * 2.Java中,接口和类是并列的两个结构 * 3.如何定义接口:定义接口中的成员 * * 3.1 JDK7及以前:只能定义全局常量和抽象方法 * >全局常量:public static final的.但是书写时,可以省略不写 * >抽象方法:public abstract的 * * 3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略) * * 4. 接口中不能定义构造器的!意味着接口不可以实例化 * * 5. Java开发中,接口通过让类去实现(implements)的方式来使用. * 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化 * 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类 * * 6. Java类可以实现多个接口 --->弥补了Java单继承性的局限性 * 格式:class AA extends BB implements CC,DD,EE * * 7. 接口与接口之间可以继承,而且可以多继承 * * ******************************* * 8. 接口的具体使用,体现多态性 * 9. 接口,实际上可以看做是一种规范 * * 面试题:抽象类与接口有哪些异同? * */ public class InterfaceTest { public static void main(String[] args) { System.out.println(Flyable.MAX_SPEED); System.out.println(Flyable.MIN_SPEED); // Flyable.MIN_SPEED = 2; Plane plane = new Plane(); plane.fly(); } } interface Flyable { // 全局常量 public static final int MAX_SPEED = 7900;// 第一宇宙速度 int MIN_SPEED = 1;// 省略了public static final // 抽象方法 public abstract void fly(); // 省略了public abstract void stop(); // Interfaces cannot have constructors // public Flyable(){ // // } } interface Attackable { void attack(); } class Plane implements Flyable { @Override public void fly() { System.out.println("通过引擎起飞"); } @Override public void stop() { System.out.println("驾驶员减速停止"); } } abstract class Kite implements Flyable { @Override public void fly() { } } class Bullet extends Object implements Flyable, Attackable, CC { @Override public void attack() { // TODO Auto-generated method stub } @Override public void fly() { // TODO Auto-generated method stub } @Override public void stop() { // TODO Auto-generated method stub } @Override public void method1() { // TODO Auto-generated method stub } @Override public void method2() { // TODO Auto-generated method stub } } // ************************************ interface AA { void method1(); } interface BB { void method2(); } interface CC extends AA, BB { }
/* * 接口的使用 * 1.接口使用上也满足多态性 * 2.接口,实际上就是定义了一种规范 * 3.开发中,体会面向接口编程! * */ public class USBTest { public static void main(String[] args) { Computer com = new Computer(); // 1.创建了接口的非匿名实现类的非匿名对象 Flash flash = new Flash(); com.transferData(flash); // 2. 创建了接口的非匿名实现类的匿名对象 com.transferData(new Printer()); // 3. 创建了接口的匿名实现类的非匿名对象 USB phone = new USB() { @Override public void start() { System.out.println("手机开始工作"); } @Override public void stop() { System.out.println("手机结束工作"); } }; com.transferData(phone); // 4. 创建了接口的匿名实现类的匿名对象 com.transferData(new USB() { @Override public void start() { System.out.println("mp3开始工作"); } @Override public void stop() { System.out.println("mp3结束工作"); } }); } } class Computer { public void transferData(USB usb) {// 多态 USB usb = new Flash(); usb.start(); System.out.println("具体传输数据的细节"); usb.stop(); } } interface USB { // 常量:定义了长、宽、最大最小的传输速度等 void start(); void stop(); } class Flash implements USB { @Override public void start() { System.out.println("U盘开启工作"); } @Override public void stop() { System.out.println("U盘结束工作"); } } class Printer implements USB { @Override public void start() { System.out.println("打印机开启工作"); } @Override public void stop() { System.out.println("打印机结束工作"); } }
1.3 代理模式(Proxy)
概述:代理模式是 Java 开发中使用较多的一种设计模式。代理设计就是为其他对象提供一种代理以控制对这个对象的访问。应用场景:
- 安全代理:屏蔽对真实角色的直接访问。
- 远程代理:通过代理类处理远程方法调用(RMI)
- 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象
- 比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时,不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开。
分类:
- 静态代理(静态定义代理类)
- 动态代理(动态生成代理类)
- JDK自带的动态代理,需要反射等知识
/* * 接口的应用:代理模式 * */ public class NetWorkTest { public static void main(String[] args) { Server server = new Server(); // server.browse(); ProxyServer proxyServer = new ProxyServer(server); proxyServer.browse(); } } interface NetWork { public void browse(); } //被代理类 class Server implements NetWork{ @Override public void browse() { System.out.println("真实的服务器访问网络"); } } //代理类 class ProxyServer implements NetWork{ private NetWork work; public ProxyServer(NetWork work){ this.work = work; } public void check(){ System.out.println("联网之前的检查工作"); } @Override public void browse() { check(); work.browse(); } }
public class StaticProxyTest { public static void main(String[] args) { Proxy s = new Proxy(new RealStar()); s.confer();// 经纪人面谈 s.signContract();// 经纪人签合同 s.bookTicket();// 经纪人订票 s.sing();// 明星:歌唱~~~ s.collectMoney();// 经纪人收钱 } } interface Star { void confer();// 面谈 void signContract();// 签合同 void bookTicket();// 订票 void sing();// 唱歌 void collectMoney();// 收钱 } // 被代理类 class RealStar implements Star { public void confer() { } public void signContract() { } public void bookTicket() { } public void sing() { System.out.println("明星:歌唱~~~"); } public void collectMoney() { } } // 代理类 class Proxy implements Star { private Star real; public Proxy(Star real) { this.real = real; } public void confer() { System.out.println("经纪人面谈"); } public void signContract() { System.out.println("经纪人签合同"); } public void bookTicket() { System.out.println("经纪人订票"); } public void sing() { real.sing(); } public void collectMoney() { System.out.println("经纪人收钱"); } }
1.4 接口练习
- 定义一个接口用来实现两个对象的比较。
- interface CompareObject{
- public int compareTo(Object o); //若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小
- }
- 定义一个Circle类,声明redius属性,提供getter和setter方法
- 定义一个ComparableCircle类,继承Circle类并且实现CompareObject接口。在ComparableCircle类中给出接口中方法compareTo的实现体,用来比较两个圆的半径大小。
- 定义一个测试类InterfaceTest,创建两个ComparableCircle对象,调用compareTo方法比较两个类的半径大小。
public interface CompareObject { // 若返回值是 0 , 代表相等; 若为正数,代表当前对象大;负数代表当前对象小 public int compareTo(Object o); } public class Circle { private Double radius;// 包装类 public Double getRadius() { return radius; } public void setRadius(Double radius) { this.radius = radius; } public Circle() { super(); } public Circle(Double radius) { super(); this.radius = radius; } } public class ComparableCircle extends Circle implements CompareObject { public ComparableCircle(double radius) { super(radius); } @Override public int compareTo(Object o) { if (this == o) { return 0; } if (o instanceof ComparableCircle) { ComparableCircle c = (ComparableCircle) o; // 错误的: // return (int) (this.getRadius() - c.getRadius()); // 正确的方式一: // if(this.getRadius() > c.getRadius()){ // return 1; // }else if(this.getRadius() < c.getRadius()){ // return -1; // }else{ // return 0; // } // 当属性radius声明为Double类型时,可以调用包装类的方法 // 正确的方式二: return this.getRadius().compareTo(c.getRadius()); } else { // return 0; throw new RuntimeException("传入的数据类型不匹配"); } } } public class ComparableCircleTest { public static void main(String[] args) { ComparableCircle c1 = new ComparableCircle(3.4); ComparableCircle c2 = new ComparableCircle(3.6); int compareValue = c1.compareTo(c2); if (compareValue > 0) { System.out.println("c1对象大"); } else if (compareValue < 0) { System.out.println("c2对象大"); } else { System.out.println("c1与c2一样大"); } int compareValue1 = c1.compareTo(new String("AA")); System.out.println(compareValue1);// 报RuntimeException异常 } }
1.5 Java8中关于接口的改进
Java 8 中,你可以为接口添加 静态方法 和 默认方法 。从技术角度来说,这是完全合法的,只是它看起来违反了接口作为一个抽象定义的理念。静态方法: 使用 static 关键字修饰。 可以通过接口直接调用静态方法 ,并执行其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections 或者 Path/Paths 这样成对的接口和类。默认方法: 默认方法使用 default 关键字修饰。可以通过实现类对象来调用。我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。比如:java 8 API 中对 Collection 、 List 、 Comparator 等接口提供了丰富的默认方法。
- 若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现:接口冲突。解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。
- 若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。
public interface CompareA { // 静态方法 public static void method1() { System.out.println("CompareA:北京"); } // 默认方法 public default void method2() { System.out.println("CompareA:上海"); } default void method3() {// 省略了public System.out.println("CompareA:上海"); } } public interface CompareB { default void method3(){ System.out.println("CompareB:上海"); } } public class SuperClass { public void method3(){ System.out.println("SuperClass:北京"); } } public class SubClassTest { public static void main(String[] args) { SubClass s = new SubClass(); // s.method1(); // SubClass.method1(); // 知识点1:接口中定义的静态方法,只能通过接口来调用。 CompareA.method1();// CompareA:北京 // 知识点2:通过实现类的对象,可以调用接口中的默认方法。 // 如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法 s.method2();// SubClass:上海 // 知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法, // 那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则 // 知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法, // 那么在实现类没有重写此方法的情况下,报错。-->接口冲突。 // 这就需要我们必须在实现类中重写此方法 s.method3();// SubClass:深圳 } } class SubClass extends SuperClass implements CompareA, CompareB { public void method2() { System.out.println("SubClass:上海"); } public void method3() { System.out.println("SubClass:深圳"); } // 知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法 public void myMethod() { method3();// 调用自己定义的重写的方法 super.method3();// 调用的是父类中声明的 // 调用接口中的默认方法 CompareA.super.method3(); CompareB.super.method3(); } }
接口冲突的解决方式:重写接口中发生冲突的方法
interface Filial {// 孝顺的 default void help() { System.out.println("老妈,我来救你了"); } } interface Spoony {// 痴情的 default void help() { System.out.println("媳妇,别怕,我来了"); } } class Father { public void help() { System.out.println("儿子,就我媳妇!"); } } class Man extends Father implements Filial, Spoony { @Override public void help() { System.out.println("我该就谁呢?"); Filial.super.help(); Spoony.super.help(); } }
2. 类的内部成员之五:内部类
2.1 什么是内部类
- 当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
- 在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
- Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
- Inner class的名字不能与包含它的外部类类名相同;
分类:
- 成员内部类(static成员内部类和非static成员内部类)
- 局部内部类(不谈修饰符)、匿名内部类
成员内部类作为类的成员的角色:
- 和外部类不同,Inner class还可以声明为private或protected;
- 可以调用外部类的结构
- Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;
成员内部类作为类的角色:
- 可以在内部定义属性、方法、构造器等结构
- 可以声明为abstract类 ,因此可以被其它的内部类继承
- 可以声明为final的
- 编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)
【注意】
- 非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员。
- 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式
- 成员内部类可以直接使用外部类的所有成员,包括私有的数据
- 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的
如何使用局部内部类
- 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
- 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
局部内部类的特点
- 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
- 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。
- 局部内部类可以使用外部类的成员,包括私有的。
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
- 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
- 局部内部类不能使用static修饰,因此也不能包含静态成员
2.2 匿名内部类
- 匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
- 格式:
new 父类构造器(实参列表)|实现接口(){
//匿名内部类的类体部分
}
匿名内部类的特点
- 匿名内部类必须继承父类或实现接口
- 匿名内部类只能有一个对象
- 匿名内部类对象只能使用多态形式引用
2.3 内部类代码演示
/* * 类的内部成员之五:内部类 * 1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类 * * 2.内部类的分类:成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内) * * 3.成员内部类: * 一方面,作为外部类的成员: * >调用外部类的结构 * >可以被static修饰 * >可以被4种不同的权限修饰 * * 另一方面,作为一个类: * > 类内可以定义属性、方法、构造器等 * > 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承 * > 可以被abstract修饰 * * * 4.关注如下的3个问题 * 4.1 如何实例化成员内部类的对象 * 4.2 如何在成员内部类中区分调用外部类的结构 * 4.3 开发中局部内部类的使用 见《InnerClassTest1.java》 * */ public class InnerClassTest { public static void main(String[] args) { // 创建Dog实例(静态的成员内部类): Person.Dog dog = new Person.Dog(); dog.show();// 卡拉是条狗 // 创建Bird实例(非静态的成员内部类): // Person.Bird bird = new Person.Bird();//错误的 Person p = new Person(); Person.Bird bird = p.new Bird(); bird.sing(); // 我是一只小小鸟 // 人:吃饭 // 人:吃饭 System.out.println(); bird.display("黄鹂"); // 黄鹂 // 杜鹃 // 小明 } } class Person { String name = "小明"; int age; public void eat() { System.out.println("人:吃饭"); } // 静态成员内部类 static class Dog { String name; int age; public void show() { System.out.println("卡拉是条狗"); // eat(); } } // 非静态成员内部类 class Bird { String name = "杜鹃"; public Bird() { } public void sing() { System.out.println("我是一只小小鸟"); Person.this.eat();// 调用外部类的非静态属性 eat(); System.out.println(age); } public void display(String name) { System.out.println(name);// 方法的形参 System.out.println(this.name);// 内部类的属性 System.out.println(Person.this.name);// 外部类的属性 } } public void method() { // 局部内部类 class AA { } } { // 局部内部类 class BB { } } public Person() { // 局部内部类 class CC { } } }
public class InnerClassTest1 { // 开发中很少见 public void method() { // 局部内部类 class AA { } } // 返回一个实现了Comparable接口的类的对象 public Comparable getComparable() { // 创建一个实现了Comparable接口的类:局部内部类 // 方式一: // class MyComparable implements Comparable{ // // @Override // public int compareTo(Object o) { // return 0; // } // // } // // return new MyComparable(); // 方式二: return new Comparable() { @Override public int compareTo(Object o) { return 0; } }; } }
结语
本人会持续更新文章的哦!希望大家一键三连,你们的鼓励就是作者不断更新的动力