Day15
抽象类和抽象方法
随着继承的传递,类变得越来越具体,父类则更加一般,有时父类设计得非常抽象,以至于没有具体的实例,这样的类叫做 抽象类
关键字:abstract
abstract:抽象的
abstract使用
可以用来修饰的结构:类,方法
-
修饰类:抽象类
- 不能实例化
- 抽象类中一定有构造器,便于子类实例化(涉及子类实例化的全过程)
- 开发中都会提供抽象类的子类,让子类实例化,完成相关操作
-
修饰方法:抽象方法(只能存在于抽象类)
-
没有方法体(不加大括号)
-
包含抽象方法的类一定是抽象类,反之,不一定
-
子类重写了父类所有的 抽象方法,则可以实例化
子类没有重写所有的抽象方法,则说明该子类也是抽象类,需要使用abstract修饰
-
-
使用注意点:
- abstract不能用来修饰:属性,构造器等
- abstarct不能用来修饰私有方法,静态方法,final方法,final类
考虑Object类和抽象类的关系
抽象类的匿名子类
上代码
abstract class Person{
public Person(){}
}
class Worker extends Person{
}
Worker worker = new Worker();
method(worker);// 非匿名的类,非匿名的对象
method1(new Worker());// 非匿名的类,非匿名的对象
Person p = new Person(){
@override
...
} // 匿名的类,非匿名的对象
// 创建类一个匿名子类 的对象 p
method2(new Person(){
@override
...
}); // 匿名子类,匿名对象
模板方法设计模式(TemplateMethod)
解决的问题:
- 当功能内部的一部分实现是确定的 ,一部分是不确定的,这时可以把不确定的部分暴露出去
- 换句话说,在软件开发中,整体步骤很固定,一边部分可以抽象出来,供给不同子类实现,这是一种模板模式。
接口
和类是并列 的关系
概述
- java不支持多重继承,有了接口,可以得到多重继承的效果
- 有时必须从几个类中抽取共同的行为特征,而他们之间没有is-a关系,仅仅具有具有相同的行为特征而已。eg:打印机,扫描仪,摄像头,键盘,,,,都支持USB连接
- 接口就是规范,定义的是一组规则,体现的是现实中“如果你要—则必须能----”的思想。继承是一种是不是的关系,接口是一种能不能的关系
- 接口的本质就是 契约,标准,规范。
使用
-
接口使用关键字:interface 来定义
-
Java中 接口和类 是并列的两个 结构
-
如何定义接口:定义接口中的成员
- JDK7及以前:只能定义全局常量和抽象方法
- 全局常量:public static final,但是书写时可以省略
- 抽象方法:public abstract,但是书写时可以省略
- JDK8:除了定义全局常量和抽象方法外,还可以定义静态方法,默认方法(略)
- JDK7及以前:只能定义全局常量和抽象方法
-
接口中不能定义构造器,意味着接口不可以实例化
-
Java开发中,接口通过类实现(关键字:implements)的方式使用
如果实现类覆盖了接口中的所有抽象方法,则此实现类可以实例化
如果实现类没有覆盖接口的所有抽象方法,则此实现类仍为抽象类
-
Java类可以实现多个接口,弥补了单继承的局限
class AA extends BB implements CC,DD,XX 先继承再类实现
-
接口和接口之间可以继承,可以多继承
-
接口的具体使用体现了多态性
-
接口可以看作一种规范
抽象类和接口由什么异同?
class USBTest{
public static void main(String[] args){
Computer com = new Computer();
FlashDisk fd = new FlashDisk();
Printer pt = new Printer();
com.transferDate(fd);
com.transferDate(pt);
}
}
interface USB{
//常量:长,宽,最大最小速度等
public void start();
public void stop();
}
class FlashDisk implements USB{
public void start(){
System.out.println("U盘开始工作");
}
public void stop(){
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
public void start(){
System.out.println("打印机开始工作");
}
public void stop(){
System.out.println("打印机结束工作");
}
}
class Computer{
public void transferDate(USB usb){
usb.start();
System.out.println("具体细节");
usb.stop();
}
}
接口的应用
代理模式Proxy
代理模式是java开发中使用较多的一种设计模式,代理设计就是为其他对象提供一种代理以控制对这个对象的访问
/**
* 接口的一系列使用
*/
public class day15 {
public void proxyTest(){
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browser();
}
}
/**
* 接口的代理模式 Proxy
*/
interface NetWork{
public void browser();
}
class Server implements NetWork{
@Override
public void browser() {
System.out.println("在真实的服务器上访问网络");
}
}
class ProxyServer implements NetWork{
private NetWork network;
public ProxyServer(NetWork network){
this.network = network;
}
@Override
public void browser() {
network.browser();
}
}
Server和ProxyServer都 是 NetWork的实现类,通过重写,ProxyServer可以调用browser方法,从而调用Server的方法,但是并没有显式地调用Server的方法,实现了代理
- 安全代理,屏蔽对真实角色的访问
- 远程代理,通过代理类处理远程方法调用
- 延迟加载,先加载轻量级代理对象,真正需要的时候,再加载真实对象
分类:
-
静态代理:静态定义代理类
-
动态代理:动态生成代理类
jdk自带的动态代理,需要反射等知识
引用一个类调用另一个类
eg:让别人买菜
工厂设计模式
接口的应用:工厂模式
工厂模式:实现了创建者和调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的
其实,设计模式和面向对象设计原则都是为了使得开发项目更加容易扩展和维护,解决方式就是一个“分工”。社会的发展也是这样,分工越来越细
原始社会的人,什么都要会,自己种田,自己打猎,自己织衣服。。。
现在的人,可以只会一样,其他都不会,只会java也能活,不会做饭,不会开车。。。
面向对象的设计原则
1、单一职责原则
定义:
一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。
单一职责原则是实现高内聚、低耦合的指导方针,是最简单却最难运用的原则,需要设计人员发现类的不同职责并将其分离2、开闭原则
定义:
软件实体应当对扩展开放,对修改关闭。
指软件实体应尽量在不修改原有代码的情况下进行扩展。3、里氏替换原则
定义:
所有引用基类的地方必须能透明地使用其子类的对象。
里氏替换原则表明,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立。
在运用里氏替换原则时,应该将父类设计为抽象类或者接口,让子类继承父类或实现父类接口,并实现在父类中声明的方法。4、依赖倒转原则
定义:
高层模块不应该依赖底层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
依赖倒转原则要求:要针对接口编程,不要针对实现编程。5、接口隔离原则
定义:
客户端不应该依赖那些它不需要的接口。
在使用接口隔离原则的时候,需要注意控制接口的粒度,接口不能太小,如果太小会导致系统中接口泛滥,不利于维护;接口也不能太大,太大的接口将违背接口隔离原则,灵活性较差,使用起来不方便。6、合成复用原则
定义:
优先使用对象组合,而不是继承来达到复用的目的。
一般而言,如果两个类之间是"Has-A"关系应使用组合或聚合,如果是"Is-A"关系可使用继承。7、迪米特法则-又称最少知识原则
定义:
每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
工厂模式的分类
- 简单工厂模式:用来生产同一等级结构中的任意产品(对新增的产品需要修改已有代码)
- 工厂方法模式:用来生产同一等级结构中的固定产品(支持增加任意产品)
- 抽象工厂模式:用来生产不同产品族的全部产品(对于增加 的产品无能为力,支持增加产品族)
核心本质:实例化对象,用工厂方法代替new操作,将选择实现类,创建对象统一管理和控制,从而将调用者和我们实现类解耦
(后续中类名为xxxFactory的一般是工厂类)
----后续详细了解-----
接口面试题
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sygbKjl2-1612622451282)(/home/creator/Workstation/mymark/Java学习.assets/Screenshot_20210202_165320.png)]
x的调用 模糊
调用B,父类中的x 使用 super.x
调用A,中的x 使用 A.x(接口中的属性均为全局静态常量)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-90jbfW8Q-1612622451285)(/home/creator/Workstation/mymark/Java学习.assets/Screenshot_20210202_165915.png)]
- 重写同名接口方法,重写一个就够,错误不在play的重写上
- 接口中的属性均为全局静态常量,不能被重新赋值!
JDK8新增特性
定义静态方法,默认方法
public interface CompareA{
public static void method(){
//...
}
public default void method2(){
//...
}
default void method3(){
//...
}
}
知识点:
-
接口中的静态方法只能由接口调用,不能由实现类调用
-
接口中的默认方法可以直接调用,如果实现类重写了默认方法,则调用重写的方法
-
如果子类(或者实现类)继承的父类和实现的接口中实现了同名同参数的方法,子类如果没有重写该方法,则调用父类中的同名同参方法(类优先原则)
-
如果实现类实现的多个接口中出现了同名同参数的默认方法,那么在实现类没有重写该方法的条件下,则报错,称为接口冲突,则接口必须重写该方法。
-
如何在子类(或者实现类)中调用父类,接口中被重写的方法?
class SubClass extends SuperClass implements Interface1,Interface2{
//…
public void method3(){
}
public void mythod(){
method3(); // 调用自己的
super.method3();//调用父类的
Interface1.super.method3();//调用接口1的
Interface2.super.method3();//调用接口2的
}
}
内部类
当一个事务的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事务提供服务,那么整个内部的完整结构最好使用内部类
在java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类
inner class 一般用在定义它的类或语句块之内,在外部类中引用必须给出完整的名称
==inner class 的名字不能与包含它的外部类类名相同
分类:
- 成员内部类:(static成员内部类和非static成员内部类)
- 局部内部类(方法块,方法,构造器) :(不涉及修饰符),匿名内部类
成员内部类
作为外部类的成员
- 可以调用外部类的属性
- 可以被static修饰
- 可以被四种权限修饰符修饰
作为一个类
- 可以定义成员属性,方法,构造器······
- 可以被final修饰(不可以被继承)
- 可以被abstract修饰(不可以被实例化)
3个问题
- 如何实例化成员内部类的对象
- 如何在成员内部类中调用外部类的结构
- 开发中局部内部类的使用
// 内部类
class PersonTemp{
String name;
int age;
public void eat(){
System.out.println("人:吃饭");
}
//静态成员内部类
static class Dog{
String name;
int age;
public void show(){
System.out.println("卡拉时一条狗");
// eat(); 不可以调用,Dog先于eat创建
}
}
class Bird{
String name;
public Bird(){
}
public void sing(){
System.out.println("我是一只小小鸟");
PersonTemp.this.eat();// 可以使用这种方法调用外部类的成员方法
}
public void showName(String name){
System.out.println(name); // 方法形式参数
System.out.println(this.name);// 内部类的属性
System.out.println(PersonTemp.this.name);// 外部类的属性
}
}
}
class InnerClassTest{
public void test01(){
// 创建Dog实例对象
PersonTemp.Dog dog = new PersonTemp.Dog();
dog.show();
// 创建Bird实例对象
// PersonTemp.Bird bird = new PersonTemp.Bird(); Wrong !!!
// 静态成员才可以使用类名调用,非静态只能通过对象
PersonTemp persontemp = new PersonTemp();
PersonTemp.Bird bird = persontemp.new Bird(); // 注意,new还可以这样用
}
}
局部内部类的使用
如下代码:
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
// 方式1
/*class MyComparable implements Comparable{
@Override
public int compareTo(Object o){
return 0;
}
}
return new MyComparable();*/
//方法2 ??? 该怎么确定它继承了Comparable?
return new Comparable(){
@Override
public int compareTo(Object o){
return 0;
}
};// 匿名内部类
}