【Android -- 面试】复习指南之 Java 基础

在这里插入图片描述

1、谈谈对java多态的理解?

多态是指父类的某个方法被子类重写时,可以产生自己的功能行为,同一个操作作用于不同对象,可以有不同的解释,产生不同的执行结果。

多态的三个必要条件:

  • 继承父类。
  • 重写父类的方法。
  • 父类的引用指向子类对象。

什么是多态?

面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点。

多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)

实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

多态的作用:消除类型之间的耦合关系。

现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。

多态的好处

1.可替换性(substitutability)。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

2.可扩充性(extensibility)。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

3.接口性(interface-ability)。多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。

4.灵活性(flexibility)。它在应用中体现了灵活多样的操作,提高了使用效率。

5.简化性(simplicity)。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

Java中多态的实现方式:接口实现,继承父类进行方法重写,同一个类中进行方法重载。

2、你所知道的设计模式有哪些?

答:Java 中一般认为有23种设计模式,我们不需要所有的都会,但是其中常用的种设计模式应该去掌握。下面列出了所有的设计模式。要掌握的设计模式我单独列出来了,当然能掌握的越多越好。

创建型(5):描述怎么创建对象
  • 1.单例模式
  • 2.原型模式:对象的拷贝
  • 3.建造者模式
  • 4.工厂模式:建立一个工厂方法来制造新的对象
  • 5.抽象工厂模式:
结构型(7):描述如何将类或对象按某种规则组成更大的结构
  • 1.桥接模式:对于两个或以上纬度独立变化的场景,将抽象与具体实现分离,实例:用不同颜色画不同形状
  • 2.外观模式:对外有一个统一接口,外部不用关心内部子系统的具体实现,这是"迪米特原则"的典型应用
  • 3.适配器模式:改变类的接口,使原本由于接口不匹配而无法一起工作的两个类能够在一工作,实例:RecycleView 的 Adapter 不管什么类型的 View 都返回 ViewHolder
  • 4.代理模式:由代理对象控制对原对象的引用,包括静态代理和动态代理
  • 5.组合模式:将对象组成树形结构,用于对单个对象和组合对象的使用具有一致性,实例:ViewGroup
  • 6.装饰模式:对对象包装一层,动态的增加一些额外功能,实例:ContextWrapper 包装 Context
  • 7.享元模式:复用对象,实例:java 的常量池(比如 String),线程池,Message.obtain 等
行为型(11):描述类或对象之间怎么相互协作,怎样分配指责
  • 1.观察者模式:一对多依赖关系,多个观察者可以同时监听某一个对象,实例:jetpack 的 lifeCycle 添加生命周期观察者
  • 2.中介者模式:定义一个中介对象封装一系列对象的交互,解耦这些对象,实例:MVP 的 P
  • 3.访问者模式:将作用于某数据结构中各元素的操作分离出来封装成独立的类,对这些元素添加新的操作,但不改变原数据结构,实例:asm 中的 classVisitor 中再分别对类注解、变量、方法等进行处理
  • 4.状态模式:行为由状态决定,不同状态下由不同行为,与策略模式类似,实例:不同状态下有同一种操作的不同行为的子类实现
  • 5.命令模式:将一个请求封装为一个对象发出,交给别的对象去处理请求,实例:Handler 发送定义好的消息事件
  • 6.策略模式:将一系列的算法封装起来,方便替换,实例:动画的时间插值器
  • 7.责任链模式:让多个对象都有机会处理一个事件,实例:View 事件传递机制
  • 8.备忘录模式:保存对象之前的状态,方便后面恢复
  • 9.迭代器模式:提供一种方法遍历容器中的元素,而不需要暴露该对象的内部表示,实例:集合的迭代器
  • 10.解释器模式:多次出现的问题有一定规律,就可以归纳成一种简单的语言来解释,实例:AndroidManifest 文件、GLES 着色器语言
  • 11.模版方法模式:定义一套固定步骤,方便直接执行,实例:AsyncTask
动态代理原理及实现
  • InvocationHandler 接口,动态代理类需要实现这个接口
  • Proxy.newProxyInstance,用于动态创建代理对象
  • Retrofit 应用:Retrofit 通过动态代理,为我们定义的请求接口都生成一个动态代理对象,实现请求

具体可见我的设计模式总结笔记

3、通过静态内部类实现单例模式有哪些优点?

  1. 不用 synchronized ,节省时间。
  2. 调用 getInstance() 的时候才会创建对象,不调用不创建,节省空间,这有点像传说中的懒汉式。

4、静态代理和动态代理的区别,什么场景使用?

静态代理与动态代理的区别在于代理类生成的时间不同,即根据程序运行前代理类是否已经存在,可以将代理分为静态代理和动态代理。如果需要对多个类进行代理,并且代理的功能都是一样的,用静态代理重复编写代理类就非常的麻烦,可以用动态代理动态的生成代理类。


    // 为目标对象生成代理对象
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InvocationHandler() {
    
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("开启事务");
    
                        // 执行目标对象方法
                        Object returnValue = method.invoke(target, args);
    
                        System.out.println("提交事务");
                        return null;
                    }
                });
    }
  • 静态代理使用场景:四大组件同AIDL与AMS进行跨进程通信
  • 动态代理使用场景:Retrofit使用了动态代理极大地提升了扩展性和可维护性。

5、简单工厂、工厂方法、抽象工厂、Builder模式的区别?

  • 简单工厂模式:一个工厂方法创建不同类型的对象。
  • 工厂方法模式:一个具体的工厂类负责创建一个具体对象类型。
  • 抽象工厂模式:一个具体的工厂类负责创建一系列相关的对象。
  • Builder模式:对象的构建与表示分离,它更注重对象的创建过程。

6、装饰模式和代理模式有哪些区别 ?与桥接模式相比呢?

  • 1、装饰模式是以客户端透明的方式扩展对象的功能,是继承关系的一个替代方案;而代理模式则是给一个对象提供一个代理对象,并由代理对象来控制对原有对象的引用。
  • 2、装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,但不对对象本身的功能进行增加。
  • 3、桥接模式的作用于代理、装饰截然不同,它主要是为了应对某个类族有多个变化维度导致子类类型急剧增多的场景。通过桥接模式将多个变化维度隔离开,使得它们可以独立地变化,最后通过组合使它们应对多维变化,减少子类的数量和复杂度。

7、外观模式和中介模式的区别?

外观模式重点是对外封装统一的高层接口,便于用户使用;而中介模式则是避免多个互相协作的对象直接引用,它们之间的交互通过一个中介对象进行,从而使得它们耦合松散,能够易于应对变化。

8、策略模式和状态模式的区别?

虽然两者的类型结构是一致的,但是它们的本质却是不一样的。策略模式重在整个算法的替换,也就是策略的替换,而状态模式则是通过状态来改变行为。

9、适配器模式,装饰者模式,外观模式的异同?

这三个模式的相同之处是,它们都作用于用户与真实被使用的类或系统之间,作一个中间层,起到了让用户间接地调用真实的类的作用。它们的不同之外在于,如上所述的应用场合不同和本质的思想不同。

代理与外观的主要区别在于,代理对象代表一个单一对象,而外观对象代表一个子系统,代理的客户对象无法直接访问对象,由代理提供单独的目标对象的访问,而通常外观对象提供对子系统各元件功能的简化的共同层次的调用接口。代理是一种原来对象的代表,其它需要与这个对象打交道的操作都是和这个代表交涉的。而适配器则不需要虚构出一个代表者,只需要为应付特定使用目的,将原来的类进行一些组合。

外观与适配器都是对现存系统的封装。外观定义的新的接口,而适配器则是复用一个原有的接口,适配器是使两个已有的接口协同工作,而外观则是为现存系统提供一个更为方便的访问接口。如果硬要说外观是适配,那么适配器有用来适配对象的,而外观是用来适配整个子系统的。也就是说,外观所针对的对象的粒度更大。

代理模式提供与真实的类一致的接口,意在用代理类来处理真实的类,实现一些特定的服务或真实类的部分功能,Facade(外观)模式注重简化接口,Adapter(适配器)模式注重转换接口。

10、代码的坏味道:

1、代码重复:

代码重复几乎是最常见的异味了。他也是Refactoring 的主要目标之一。代码重复往往来自于copy-and-paste 的编程风格。

2、方法过长:

一个方法应当具有自我独立的意图,不要把几个意图放在一起。

3、类提供的功能太多:

把太多的责任交给了一个类,一个类应该仅提供一个单一的功能。

4、数据泥团:

某些数据通常像孩子一样成群玩耍:一起出现在很多类的成员变量中,一起出现在许多方法的参数中……,这些数据或许应该自己独立形成对象。 比如以单例的形式对外提供自己的实例。

5、冗赘类:

一个干活不多的类。类的维护需要额外的开销,如果一个类承担了太少的责任,应当消除它。

6、需要太多注释:

经常觉得要写很多注释表示你的代码难以理解。如果这种感觉太多,表示你需要Refactoring。

11、是否能从Android中举几个例子说说用到了什么设计模式 ?

AlertDialog、Notification源码中使用了Bulider(建造者)模式完成参数的初始化:

在AlertDialog的Builder模式中并没有看到Direcotr角色的出现,其实在很多场景中,Android并没有完全按照GOF的经典设计模式来实现,而是做了一些修改,使得这个模式更易于使用。这个的AlertDialog.Builder同时扮演了上下文中提到的builder、ConcreteBuilder、Director的角色,简化了Builder模式的设计。当模块比较稳定,不存在一些变化时,可以在经典模式实现的基础上做出一些精简,而不是照搬GOF上的经典实现,更不要生搬硬套,使程序失去架构之美。

定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。即将配置从目标类中隔离出来,避免过多的setter方法。

优点:

  • 1、良好的封装性,使用建造者模式可以使客户端不必知道产品内部组成的细节。
  • 2、建造者独立,容易扩展。

缺点:

  • 会产生多余的Builder对象以及Director对象,消耗内存。
日常开发的BaseActivity抽象工厂模式:

定义:为创建一组相关或者是相互依赖的对象提供一个接口,而不需要指定它们的具体类。

主题切换的应用:

比如我们的应用中有两套主题,分别为亮色主题LightTheme和暗色主题DarkTheme,这两种主题我们可以通过一个抽象的类或接口来定义,而在对应主题下我们又有各类不同的UI元素,比如Button、TextView、Dialog、ActionBar等,这些UI元素都会分别对应不同的主题,这些UI元素我们也可以通过抽象的类或接口定义,抽象的主题、具体的主题、抽象的UI元素和具体的UI元素之间的关系就是抽象工厂模式最好的体现。

优点:

  • 分离接口与实现,面向接口编程,使其从具体的产品实现中解耦,同时基于接口与实现的分离,使抽象该工厂方法模式在切换产品类时更加灵活、容易。

缺点:

  • 类文件的爆炸性增加。
  • 新的产品类不易扩展。
Okhttp内部使用了责任链模式来完成每个Interceptor拦截器的调用:

定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。

ViewGroup事件传递的递归调用就类似一条责任链,一旦其寻找到责任者,那么将由责任者持有并消费掉该次事件,具体体现在View的onTouchEvent方法中返回值的设置,如果onTouchEvent返回false,那么意味着当前View不会是该次事件的责任人,将不会对其持有;如果为true则相反,此时View会持有该事件并不再向下传递。

优点:

将请求者和处理者关系解耦,提供代码的灵活性。

缺点:

对链中请求处理者的遍历中,如果处理者太多,那么遍历必定会影响性能,特别是在一些递归调用中,要慎重。

RxJava的观察者模式:

定义:定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

ListView/RecyclerView的Adapter的notifyDataSetChanged方法、广播、事件总线机制。

观察者模式主要的作用就是对象解耦,将观察者与被观察者完全隔离,只依赖于Observer和Observable抽象。

优点:

  • 观察者和被观察者之间是抽象耦合,应对业务变化。
  • 增强系统灵活性、可扩展性。

缺点:

  • 在Java中消息的通知默认是顺序执行,一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般考虑采用异步的方式。
AIDL代理模式:

定义:为其他对象提供一种代理以控制对这个对象的访问。

静态代理:代码运行前代理类的class编译文件就已经存在。

动态代理:通过反射动态地生成代理者的对象。代理谁将会在执行阶段决定。将原来代理类所做的工作由InvocationHandler来处理。

使用场景:

  • 当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。

缺点:

  • 对类的增加。
ListView/RecyclerView/GridView的适配器模式:

适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

使用场景:

  • 接口不兼容。
  • 想要建立一个可以重复使用的类。
  • 需要一个统一的输出接口,而输入端的类型不可预知。

优点:

  • 更好的复用性:复用现有的功能。
  • 更好的扩展性:扩展现有的功能。

缺点:

  • 过多地使用适配器,会让系统非常零乱,不易于整体把握。例如,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统如果出现太多这种情况,无异于一场灾难。
Context/ContextImpl外观模式:

要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行,门面模式提供一个高层次的接口,使得子系统更易于使用。

使用场景:

  • 为一个复杂子系统提供一个简单接口。

优点:

  • 对客户程序隐藏子系统细节,因而减少了客户对于子系统的耦合,能够拥抱变化。
  • 外观类对子系统的接口封装,使得系统更易用使用。

缺点:

  • 外观类接口膨胀。
  • 外观类没有遵循开闭原则,当业务出现变更时,可能需要直接修改外观类。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kevin-Dev

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值