什么是多态呢?
接口的多种不同的实现方式即为多态。
多态性是允许你将父对象设置成为一个或更多的他的子对象相等的技术。
我们在程序中定义的引用变量所指向的具体类型和通过该引用变量的方法调用在编程的时候并不确定,当处于运行期间才确定。就是这个引用变量究竟指向哪一个实例对象,在编译期间是不确定的,只有运行期才能确定,这样不用修改源码就可以把变量绑定到不同的类实例上,让程序拥有了多个运行状态,这就是多态。
反射
反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力
反射是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。
在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。 java中的Class三种获取方式:
//使用Class类的静态方法forName(),用类的名字获取一个Class实例
Class<?> bookClass = Class.forName("cc.abto.demo.Book");
//利用对象调用getClass()方法获取该对象的Class实例
Book book = new Book();
Class<? extends Book> bookClass = book.getClass();
//运用.class的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例
Class<Book> bookClass = Book.class;
Class<Integer> type = Integer.TYPE;
简单总结这些定义,那就是反射可以让我们获得一个类的所有信息,包括私有属性和私有方法,那在java中如何使用发射呢。
public class Book implements Serializable
{
private int id=1;
private String name="android";
private String author="wf";
private String getName()
{
return name;
}
}
String s = null;
try
{
Class<?> bookClass = Class.forName("com.example.myapplication.Book");//完整类名
Object book = bookClass.newInstance();//获得实例
Method getAuthor = bookClass.getDeclaredMethod("getName");//获得私有方法
getAuthor.setAccessible(true);//调用方法前,设置访问标志
s = (String) getAuthor.invoke(book);//使用方法
Log.d("TAG", "onCreate: "+s);
}
catch (Exception e)
{
e.printStackTrace();
}
这里我们随便创建一个类来演示。比如说创建一个Book类:
反射不仅可以让我们获得隐藏的方法和属性,还可以让对象的实例化从编译时转化为运行时,因为我们可以通过Class.forName(“com.example.myapplication.Boo”).newInstance()的方法来生成新的实例,而这边的"com.example.myapplication.Boo"是一个字符串,完全可以用变量来代替,再结合抽象工厂模式什么的,我们就可以很大程度上对程序应用中的功能模块进行解耦合。
EventBus
当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
事件的发送和接收,主要是通过subscriptionsByEventType这个非常重要的列表,我们将订阅即接收事件的方法存储在这个列表,发布事件的时候在列表中查询出相对应的方法并执行~
观察者模式
其中Subject维护其观察者,并通常通过调用其方法之一来自动通知它们任何状态更改。
android gilde原理
android 注解
http 和 https区别
为什么用 mvp mvvm
MVP模式通过Presenter实现数据和视图之间的交互,简化了Activity的职责。同时即避免了View和Model的直接联系,又通过Presenter实现两者之间的沟通。
总结:MVP模式减少了Activity的职责,简化了Activity中的代码,将复杂的逻辑代码提取到了Presenter中进行处理,模块职责划分明显,层次清晰。与之对应的好处就是,耦合度更低,更方便的进行测试。
手写算法题。一共有几个,面试官会随机抽一个作为题目。
给出一个序列包含n个正整数的序列A,然后给出一个正整数x,你可以对序列进行任意次操作的,每次操作你可以选择序列中的一个数字,让其与x做按位或运算。你的目的是让这个序列中的众数出现的次数最多。
请问众数最多出现多少次?
1.Activity的生命周期、加载模式。 什么时候会用到singleTask?
2.Handler机制 子线程可以创建handler吗?一个线程是否只有一个Looper? 如何保证一个线程只有一个Looper?
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
答:可以在子线程创建,前提条件需要调用Looper.prepare()
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
答:只能有一个。通过ThreadLocal来保证
3.多线程的方式有哪些?
Android提供了四种常用的操作多线程的方式,分别是:
-
Handler+Thread
答:HandlerThread 是继承Thread 并从写了run 方法,在run方法中创建了Looper,并执行loop方法,获取消息后需要传递给工作线程的Handler处理消息,创建工作线程Handler需用HandlerThread的getLooper方法,拿到工作线程的Looper。 -
AsyncTask
public abstract class AsyncTask<Params, Progress, Result> {
...
}
// 类中参数为3种泛型类型
// 整体作用:控制AsyncTask子类执行线程任务时各个阶段的返回类型
// 具体说明:
// a. Params:开始异步任务执行时传入的参数类型,对应excute()中传递的参数
// b. Progress:异步任务执行过程中,返回下载进度值的类型
// c. Result:异步任务执行完成后,返回的结果类型,与doInBackground()的返回值类型保持一致
// 注:
// a. 使用时并不是所有类型都被使用
// b. 若无被使用,可用java.lang.Void类型代替
// c. 若有不同业务,需额外再写1个AsyncTask的子类
}
-
ThreadPoolExecutor
-
线程池的初始化大小和最大的大小
这个是指最初分配给线程池的线程数量,以及线程池中允许的最大线程数量。在线程池中拥有的线程数量主要取决于你的设备的CPU内核数。
这个数字可以从系统环境中获得:
public class PhotoManager {
...
/*
* Gets the number of available cores
* (not always the same as the maximum number of cores)
*/
private static int NUMBER_OF_CORES =
Runtime.getRuntime().availableProcessors();
}
这个数字可能并不反映设备的物理核心数量,因为一些设备根据系统负载关闭了一个或多个CPU内核,对于这样的设备,availableProcessors()方法返回的是处于活动状态的内核数量,可能少于设备的实际内核总数。
2.线程保持活动状态的持续时间和时间单位
这个是指线程被关闭前保持空闲状态的持续时间。这个持续时间通过时间单位值进行解译,是TimeUnit()中定义的常量之一。
3.一个任务队列
这个传入的队列由ThreadPoolExecutor获取的Runnable对象组成。为了执行一个线程中的代码,一个线程池管理者从先进先出的队列中取出一个Runnable对象且把它附加到一个线程。当你创建线程池时需要提供一个队列对象,这个队列对象类必须实现BlockingQueue接口。
private PhotoManager() {
...
// Sets the amount of time an idle thread waits before terminating
private static final int KEEP_ALIVE_TIME = 1;
// Sets the Time Unit to seconds
private static final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
// Creates a thread pool manager
mDecodeThreadPool = new ThreadPoolExecutor(
NUMBER_OF_CORES, // Initial pool size
NUMBER_OF_CORES, // Max pool size
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
mDecodeWorkQueue);
}
- IntentService
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
IntentService 是继承Service,IntentService 默认创建HandlerThread,并创建工作线程的Handler,调用onHandleIntent,这个方式是工作线程方法,我们继承IntentService 只需要重写onHandleIntent就可以。
4.生产者消费者模式
5.wait 和 sleep的区别
答:sleep和wait的区别:
1、sleep是Thread的静态方法,wait是Object的方法,任何对象实例都能调用。
2、sleep不会释放锁,它也不需要占用锁。wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)。
3、它们都可以被interrupted方法中断。
6.String、StringBuffer 、StringBuilder的区别
要注意的是,String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。我们来看一下这张对String操作时内存变化的图:
我们可以看到,初始String值为“hello”,然后在这个字符串后面加上新的字符串“world”,这个过程是需要重新在栈堆内存中开辟内存空间的,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存空间,不得不说这是对内存空间的极大浪费。为了应对经常性的字符串相关的操作,谷歌引入了两个新的类
StringBuffer类和StringBuild类来对此种变化字符串进行处理。
当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
7.ANR异常发生条件,如何分析ANR ?
8.自定义View和ViewGroup
9.事件处理 分发,拦截,处理。
10.GC算法
11.四大引用 强,软,弱,虚,并说明下合适GC
12.动画 View动画,属性动画,帧动画。再说下View和属性动画区别。
13.JVM
14.原理屏幕适配相关问题
差不多就问了这几个问题,其他的忘记了,其中美团的手写算法在业界算是比较出名,很多小伙伴可能卡在手写算法上。然后就是一些Android和Java的细节性东西,这些基础内容只要有一点工作经验的都基本能说得上来。
算法复试
1、算法。连续问了好几个,都是数组,层层递进的,但是我忘了,只记得最后是找出数组
2、中重复的数字
3、进程和线程的区别
4、程序在运行时操作系统除了分配内存空间还有什么
5.二叉树的中序遍历,非递归
6.存一个通讯录,包括增删改查,用什么数据结构?
7.二叉树的中序遍历,非递归?
#美团二面:技术面
1.Http和Https的区别?
2.看过哪些源码?Glide原理?
3.OkHttp原理?
4.Retrofit原理?为何用代理?代理的作用是什么?
5.ButterKnife原理?用到反射吗?为什么?6.eventbus的原理。
7.Handler原理
8.Binder原理
9.ANR异常如何查找并分析?
10.JVM内存模型?性能调优?
11.垃圾收集算法有哪些?G1算法?
12.加密算法有哪些?对称加密和非对称加密的区别?
13.TCP的三次握手?两次行不行?为什么?TCP攻击知道吗?如何进行攻击?
14.性能优化方面
15.会对代码进行review吗?何时review?怎么review?
16.项目中遇到的让你棘手的问题?多久解决,怎么解决?
17.平常如何学习?何时学习?怎么学习?学习渠道?
二面跟比一面比起来,会更加深入,偏向原理性质。
所以大家平时的编码过程中,要多思考,多看源码,要理解实现方式,而不要一味的去写代码完成需求,长此以往的话未来很容易被后浪淘汰的。
这里必须得感谢一下我毕业后的第一个领导张哥,多亏张哥那会就告诉我一定要多看源码,不然这里已经挂了…
美团三面:
1.前两轮面试感觉如何?
2.热修复
3.插件化组件化
4.动态化
5.Kotlin
6.Flutter
7.聊了一下之前的公司和项目
8.你觉得小团队好还是大团队好?
9.说说自己的优缺点发展方向
10.职业生涯规划 是先讲究宽度还是讲究深度,为什么?
11.为什么离职?
12.其他小问题:哪里人啊?现在工资怎样?要求如何,何时到岗?有什么问题要问我的吗?