阿里面经之解答by cmershen(1)——Java的基本特性,面向对象的六大特征等
来源:互联网 发布:手机如何进入淘宝店铺 编辑:程序博客网 时间:2024/05/22 22:15
在牛客网上看到一份阿里面经,真假先不谈,就其中总结概括的知识点和常见问题还是不错的,在面试中也是经常会被问到的。
美中不足的是,里面的解答有的太过冗杂,有的则太过简略。本学妹按自己的理解,将这些问题重新整理,给出一份自己的理解,与读者共同学习共同进步。
1.自我介绍(略)
2.做过的项目(就说dts好啦~~)
(以下是重点的开始)
3.Java的四个基本特性:抽象,封装,继承,多态,对多态的理解以及项目中哪些地方用到多态
原po的解释太过繁杂,根本记不住
抽象:将一类对象的共同特征抽象成类。包括数据抽象(即成员变量)和行为抽象(即方法)。
继承:将已知类和继承信息合并起来创建新类的过程。
封装:隐藏内部的实现逻辑,只向外界提供最简单的接口的过程。
多态:允许不同子类型的对象,对同一消息做出不同的响应。
3.1 多态的理解
方法重载和重写:重载是同一个类中,同名方法有不同的参数列表 例如:
f(arg1,arg2) { ...}f(arg1,arg2,arg3) { ...}
方法重写:
是在子类中重写父类已有的方法或抽象方法,例如:
class ClassA { public void f() { System.out.println("ClassA f()"); }}class ClassB extends ClassA { public void f() { System.out.println("ClassB f()"); }}
要实现多态需要做的两件事:方法重写,对象造型(ClassA b = new ClassB();
)
项目中多态的应用:
在dts中的抽象语法树部分使用过多态,类SimpleNode代表抽象语法树的节点,但抽象语法树有许多种类型的节点,所以SimpleNode类中有一些抽象方法,在不同类型的节点中分别使用不同的实现类实现不同的处理逻辑。
(其实根本就不是这样的,编一个吧,DTS的设计模式无力吐槽。。。)
4.面向对象和面向过程的区别?用面向过程可以实现面向对象吗?
面向过程以事件为中心,分析出解决问题的步骤,然后用函数把这些步骤实现。
面向对象以类和对象为中心。
举例:”汽车发动“和”汽车停止“
对于面向对象来说是这样的:
Class Car { ... void start(); void stop();}Car c=new Car();c.start();c.stop();
对于面向过程来说是这样的:
void start(Car* c)void stop(Car* c)
5.重载和重写如何确定调用哪个函数?
重载:发生在同一个类中,同名方法具有不同参数,根据调用函数时的入口参数,选择与之对应的重载函数。
重写:发生在父类与子类之间,根据不同的子类对象确定调用哪个方法。
6.面向对象开发的六个基本原则:
(1)单一职责(SRP):There should never be more than one reason for a class to change.
即一个类只有一个引起变化的原因。
举例:一个调制解调器有四个功能,分别为拨号,挂断,接受消息,发送消息。
public class Modem { public void dial(); public void hangup(); public void receive(); public void send();}
实际上Dial(拨通电话)和Hangup(挂电话)是属于连接的范畴,而Receive(收到信息)和Send(发送信息)是属于数据传送的范畴。这里类包括两个职责,显然违反了SRP。
因此要重构Modem类,从中抽象出两个接口,一个专门负责连接,另一个专门负责数据传送。依赖Modem类的元素要做相应的细化,根据职责的不同分别依赖不同的接口。如下:
public interface IConnection { public void dial(); public void hangup();}public interface IDataTransfer { public void receive(); public void send();}public class Modem implements IConnection,IDataTransfer{}
这样无论单独修改连接部分还是单独修改数据传送部分,都彼此互不影响。
(2)里氏替换原则:“Subtypes must be substitutable for their base types”
也就是说子类必须能够替换成他们的基类。
举例:一个士兵用枪(手枪、步枪、机枪)射击杀人可描述为:
public class Soldier { public void killEnemy(AbstractGun gun) { gun.shoot(); }}public abstract class Gun { public void shoot();}public class HandGun extends Gun{ public void shoot() { System.out.println("HandGun shoot!"); }}public class Rifle extends Gun{ public void shoot() { System.out.println("Rifle shoot!"); }}public class MachineGun extends Gun{ public void shoot() { System.out.println("MachineGun shoot!"); }}
如果public void killEnemy(AbstractGun gun)
中不能调用父类AbstractGun,则违反了里氏代换原则。
(3)依赖倒置原则(Dependence Inversion Principle DIP )
所谓依赖倒置原则就是要依赖于抽象,不要依赖于具体。简单的说就是对抽象进行编程,不要对实现进行编程。面向对象的开发很好的解决了这个问题,一般的情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变化,只要抽象不变,客户程序就不需要变化。
例如一个自动驾驶系统可以在福特车和本田车上使用,提供了三个方法:开车,停车,转弯。
如果不考虑依赖倒置原则来实现,应该这样写:
public class HondaCar { public void Run() { System.out.println("本田车启动了!"); } public void Turn() { System.out.println("本田车拐弯了!"); } public void Stop() { System.out.println("本田车停止了!"); }}public class FordCar { public void Run() { System.out.println("福特车启动了!"); } public void Turn() { System.out.println("福特车拐弯了!"); } public void Stop() { System.out.println("福特车停止了!"); }}public class AutoSystem { public enum CarType{ Ford,Honda} private HondaCar hondacar=new HondaCar(); private FordCar fordcar=new FordCar(); private CarType type; public AutoSystem(CarType carType) { this.type = carType; } public void RunCar() { if (this.type == CarType.Honda) hondacar.Run(); else if (this.type == CarType.Ford) fordcar.Run(); } public void StopCar() { if (this.type == CarType.Honda) hondacar.Stop(); else if (this.type == CarType.Ford) fordcar.Stop(); } public void TurnCar() { if (this.type == CarType.Honda) hondacar.Turn(); else if (this.type == CarType.Ford) fordcar.Turn(); }}
若该自动驾驶系统增加了对宝马车的支持,则需要增加BMWCar类,并在AutoSystem里按规律增加支持BMWCar的语句。如果又增加了10种,20种车的支持呢?如果不只是Run,Stop,Turn三种功能,而是100种,10000种功能呢?改动量将会变得极大。
这样我们需要抽象出来,使得Run,Stop,Turn三个函数只与车接口耦合,而不直接依赖具体车型,应该重构以上功能如下:
public interface ICar { public void Run(); public void Turn(); public void Stop();}public class HondaCar implements ICar{ public void Run() { System.out.println("本田车启动了!"); } public void Turn() { System.out.println("本田车拐弯了!"); } public void Stop() { System.out.println("本田车停止了!"); }}public class FordCar implements ICar{ public void Run() { System.out.println("福特车启动了!"); } public void Turn() { System.out.println("福特车拐弯了!"); } public void Stop() { System.out.println("福特车停止了!"); }}public class AutoSystem { public ICar car; public AutoSystem(ICar car) { this.car=car; } public void runCar() { this.car.run(); } public void stopCar() { this.car.stop(); } public void turnCar() { this.car.turn(); }}
这样AutoSystem只与ICar耦合,无论增加多少种车,也不需改变AutoSystem类,只需新增加ICar接口的实现类即可。
4合成聚合复用:子类是超类的一个特殊种类,而不是超类的一个角色。区分“Has-A”和“Is-A”。只有“Is-A”关系才符合继承关系,“Has-A”关系应当用聚合来描述。
尽量使用聚合而不是继承,只有严格满足“Is-A”关系才使用继承。
5.开放封闭原则:Software entities(classes,modules,functions etc) should open for extension ,but close for modification.
软件实体应该对扩展开放,而对修改封闭。
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立其工作,而不要对类做任何修改。
举例:
银行业务系统有3种功能,存款、取款、转账。若不考虑OCP,则这样设计:
public class BankProcess{ public void Deposite(); public void Withdraw(); public void Transfer();}public class BankStaff{ private BankProcess bankpro = new BankProcess(); public void BankHandle(Client client) { switch (client.Type) { case "deposite": bankpro.Deposite(); break; case "withdraw": bankpro.Withdraw(); break; case "transfer": bankpro.Transfer(); break; } }}
如果该系统升级,增加了第四种功能,那么BankProcess和BankStaff类都要修改。正确的做法是把三种业务抽象成接口,当业务员依赖于固定的抽象时,对修改就是封闭的,而通过继承和多态继承,从抽象体中扩展出新的实现,就是对扩展的开放。
6接口隔离原则(ISP)
接口隔离原则 认为:”使用多个专门的接口比使用单一的总接口要好”。因为接口如果能够保持粒度够小,就能保证它足够稳定,正如单一职责原则所标榜的那样。多个专门的接口就好比采用活字制版,可以随时拼版拆版,既利于修改,又利于文字的重用。而单一的总接口就是雕版印刷,显得笨重,实现殊为不易;一旦发现错字别字,就很难修改,往往需要整块雕版重新雕刻。
迪米特法则:一个类应该对其他类有尽可能少的了解。简称为“不要和陌生人说话”。
(DTS中的应用:遍历控制流图时使用观察者模式。)
- 阿里面经之解答by cmershen(1)——Java的基本特性,面向对象的六大特征等
- 阿里面经之解答 by cmershen(5)——内存泄露,java.util.concurrent包
- 阿里面经之解答 by cmershen(2)——static/final,HashMap/Hashtable/ConcurrentHashMap
- 阿里面经之解答 by cmershen(4)——线程池
- 阿里面经之解答 by cmershen(3)——String/StringBuffer/StringBuilder,Java序列化,线程安全,线程同步,ThreadLocal
- 面向对象的特征之—多态
- 面向对象的三大特性?(java面试题)
- Java基础之面向对象的特征。
- Java之面向对象的特征
- JAVA面向对象高级特性之继承(1)常见问题解答
- 设计模式之——面向对象的六大原则
- 面向对象的六大原则之 —— 单一原则
- 面向对象的六大原则之 —— 开闭原则
- 面向对象的六大原则之 —— 迪米特原则
- 面向对象的基本特性
- java之面向对象的三个特性
- Java面向对象的特征
- java面向对象的特征
- 常见的 libphp5.so文件无法生成的问题
- .so文件-64位/32位使用问题
- sftp登录linux Received message too long (or "Bad packet length") 原因,已解决
- 手机被偷后如何让小偷不能用
- Android N上一些新特性的介绍
- 阿里面经之解答by cmershen(1)——Java的基本特性,面向对象的六大特征等
- 学会爬虫需要的相关知识积累
- 高并发系统之限流特技:有了它,京东6.18如虎添翼!
- js日期格式化,扩展功能
- 基于Awstats的Tomcat8-Java8日志分析
- Java中ArrayList和LinkedList区别
- tomcat源码解析(一)--启动与Server.xml文件的解析
- 序列化 文件 Serialize
- Java设计模式——原型模式