面试题目总结(一)

1.java有什么特性,继承有什么用处,多态有什么用处?

Java的四大特性分别是封装,继承,多态与抽象。

封装的概念:把对象的属性和方法结合成一个独立的整体,隐藏实现细节,并提供对外访问的接口。

封装的好处

(1) 隐藏实现细节  (2)安全性 (3)增加代码的复用性 (4)模块化

继承的概念:从已知的一个类中派生出新的一个类,叫子类。子类实现了父类所有非私有化属性和方法,

并能根据自己的实际需求扩展出新的行为。

继承的好处:

(1):继承是传递的,容易在其基础上构造,建立和扩充出新的类。

(2):能减少数据和代码的冗余度。

(3):大大增加了代码的维护性。

多态的概念:多个不同的对象对同一消息作出响应,同一消息根据不同的对象而采用各种不同的行为方法。

多态的好处:主要是利于扩展。

(参考:https://blog.csdn.net/hs2201056/article/details/61461751

2.反射是什么,在哪里用到,怎么利用反射创建一个对象

概念:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。反射带来的两大弊端可能就是安全和性能问题。

使用到反射:

  • 1.功能清单文件: 配置应用组件的全类名
  • 2.布局文件: 视图标签
  • 3. 显示意图: 指定类的Class对象
  • 4. 调用系统隐藏的API: 使用Class.forName("全类名")调用

API:

  • Class类:代表一个类,位于java.lang包下
  • Field类:代表类的成员变量(成员变量也称为类的属性)
  • Method类:代表类的方法
  • Constructor类:代表类的构造方法
  • Array类:提供了动态创建数组,以及访问数组的元素的静态方法

一.获取Class对象
1.使用Class的forName()方法
2.如果是对象,通过对象的getClass()方法则返回该类的Class对象
3.也可以直接调用类的class属性。

二.创建对象
1.使用Class对象的newInstance()方法来创建类的实例,这种方式要求该Class对象的对应类有默认构造器,执行newInstance()实际上是利用默认构造器来创建该类的实例。

2.先使用Class对象获取到Constructor对象,在调用Constructor对象的newInstance()方法来创建对应Class对象对应类的实例。采用这种方法可以指定构造函数来创建。

//1.源头:获取Class对象,用三种方式
   Phone iPhone=new Phone();
//1.1.对象.getClass();获取对象
 Class<?> clazz1 = iPhone.getClass();
 //1.2.类.class
 clazz1=Phone.class;
//1.3.Class.forName("包名.类名");
 clazz1 = Class.forName("test.Phone");

//2.创建对象
//2.1通过newInstence()
 Phone instance1 = (Phone) clazz1.newInstance();
//2.2先调用构造器,再通过newInstence()创建
Object instance2 = clazz1.getConstructor().newInstance();

3.代理模式与装饰模式的区别,手写一个静态代理,一个动态代理

作用

  • 隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
  • 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类。

具体代码参考:https://blog.csdn.net/u014473112/article/details/88955944?utm_source=app

代理模式与装饰着模式区别:

代理模式:让别人帮助你做你并不关心的事情

装饰器模式:为让自己的能力增强,使得增强后的自己能够使用更多的方法,拓展在自己基础之上的功能的。

装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。换句话说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

4.对象加载的过程,属性先加载还是方法先加载?

父类静态变量

父类静态代码块

子类静态代码块

子类静态变量

父类普通代码块

父类的变量

父类构造方法

父类构造代码块

子类普通代码块

子类变量

子类构造方法

子类构造代码块

总结:

1.(静态变量和静态代码块)和(普通代码块和成员变量)看编写的顺序加载 如果静态代码块先加载然后打印静态变量会打印null.普通代码块同理。

2.局部代码块和局部变量按编写顺序加载,构造代码块同理。

2.子类和父类的方法只有调用才加载。

5.垃圾回收机制与jvm结构

垃圾回收机制切入点:可达性分析/GC Root对象/回收垃圾使用的算法/JVM分代回收策略/回收过程要停顿所有Java线程

参考:https://blog.csdn.net/qq_29882585/article/details/108564030

JVM结构切入点:程序计数器/虚拟机栈/本地方法栈/方法区/堆相关信息。区分线程私有数据区和线程共享数据区

参考https://blog.csdn.net/qq_29882585/article/details/108563194

6.自定义View,事件分发机制讲一讲

View相关:Activity的构成,最外层为Activity,使用windowManger创建window,phonewindow为window的唯一实现类,PhoneView对象会创建一个PhoneView内部类DecorView,ViewRoot对应ViewRootImpl类,是连接WindowManager和DecorView的纽带。 在ActivityThread中,当Activity对象被创建完毕时,会将DecorView添加到Window中,同时会创建ViewRootImpl,且ViewRootImpl和DecorView会建立关联。ActivityThread类会调用handleResumeActivity方法将顶层视图DecorView添加到PhoneWindow窗口。之后视图所有的绘制都在viewrootimpl中实现。

切入点:onMeasure()、onLayout()、onDraw()

参考:https://blog.csdn.net/qq_29882585/article/details/108422805

           https://blog.csdn.net/jacklam200/article/details/50039189/

           https://www.jianshu.com/p/7e589ddb634a

事件分发机制相关:

切入点:定义、解决的问题、顺序、核心方法

              Activity的分发机制、ViewGroup的事件分发机制、View的事件分发机制

参考:https://blog.csdn.net/qq_29882585/article/details/108182951

7.http与https有什么区别

切入点:数据加密传输过程、CA证书等

参考:https://blog.csdn.net/qq_29882585/article/details/107595054

8.Activity启动模式,以及各启动模式生命周期问题

参考:https://blog.csdn.net/qq_29882585/article/details/107599869

9.静态方法,静态对象为什么不能继承?

       首先静态属性和静态方法是可以被子类继承的,但静态属性不能被子类重写。重写的本质是动态绑定,即根据运行时对象的类型来决定调用哪个方法,而不是根据编译时的类型。静态方法属于类的,在编译阶段已经静态绑定到类上,表现出来就是通过类名.方法名进行访问;所以静态方法无法被子类重写。

10.Activity怎么启动Service,Activity与Service交互,Service与Thread的区别

Service作为Android的四大组件之一,和Activity相同,是有生命周期的,它一般被看成运行于后台,没有界面的“Activity”。

生命周期:onCreate(),onStart(),onDestory(),onBind(),onUnbind(),startService(),bindService()。

startService():如果一个Service被某个Activity 使用 startService 方法启动,不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行,但它依旧运行于main线程。如果这个Service被startService方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例。该Service将会一直在后台运行,即使启动它的Activity已经退出,它直到某个activity调用stopService,或自身调用的stopSelf方法才会结束服务。当然如果系统资源不足,android系统也可能结束服务。

bindService():如果一个Service被某个Activity 调用 bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法不会被调用。当连接建立之后,Service将会一直运行,除非调用unbindService 方法断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统才会自动停止Service,对应onDestroy将被调用。

还有一中复杂用法,就是同时使用startService和bindService方式启动服务。如果一个Service又被启动又被绑定,则该Service将会一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,Service的onStart便会调用多少次。调用unbindService将不会停止Service,而必须由外界的activity调用 stopService 或 Service自身调用stopSelf 来停止服务。

Activity与Service交互

扩展 Binder 类 :在service类中进行添加一个binder内部类,我们通过前台进行绑定后,当绑定后成功后,客户端收到binder 后,可利用他直接访问 Binder 实现中以及Service 中可用的公共方法。如果我们的服务只是自有应用的后台工作线程,则优先采用这种方法。前提:service服务端与客户端相同的进程中运行。

使用 Messenger :这是执行进程间通信 (IPC) 的最简单方法,因为 Messenger 会在单一线程中创建包含所有请求的队列,也就是说Messenger是以串行的方式处理客户端发来的消息,这样我们就不必对服务进行线程安全设计了。

使用 AIDL :如果我们想让服务同时处理多个请求,则应该使用 AIDL。 在此情况下,服务必须具备多线程处理能力,并采用线程安全式设计。使用AIDL必须创建一个定义编程接口的 .aidl 文件。Android SDK 工具利用该文件生成一个实现接口并处理 IPC 的抽象类,随后可在服务内对其进行扩展。

保证Service不被杀掉:(1)onStartCommand方法,返回START_STICKY(2)提升service优先级(3)onDestroy方法里重启service(service +broadcast  方式,就是当service走ondestory的时候,发送一个自定义的广播,当收到广播的时候,重新启动service)(4)Application加上Persistent属性

具体代码参考:https://blog.csdn.net/weixin_39460667/article/details/82770164

线程是一个动态执行的过程,它也有一个从产生到死亡的过程。它的生命周期有五种状态:
● 新建(new Thread)
当创建Thread类的一个实例时,此线程进入新建状态或未启动状态。
例如:Thread thread=new Thread();

● 就绪(runnable)
线程已经被启动,正在等待被分配给CPU时间片,也就是说此时线程正在就绪队列中排队等候得到CPU资源。
例如:thread.start();

● 运行(running)
线程获得CPU资源正在执行任务,正在运行run()方法,此时除非此线程自动放弃CPU资源或者有优先级更高的线程进入,否则线程将一直运行到结束。

● 死亡(dead)
当线程执行完毕或被其它线程杀死,线程就进入死亡状态,这时线程不可能再进入就绪状态等待执行。
自然终止:正常运行run()方法后终止
异常终止:调用stop()方法让一个线程终止运行

● 堵塞(blocked)
由于某种原因导致正在运行的线程让出CPU并暂停自己的执行,即进入堵塞状态。
正在睡眠:用sleep(long t) 方法可使线程进入睡眠方式。一个睡眠着的线程在指定的时间过去可进入就绪状态。
正在等待:调用wait()方法。(在此状态下,调用motify()方法线程会回到就绪状态)
被另一个线程所阻塞:调用suspend()方法。(在此状态下,调用resume()方法恢复)

常用的方法有:
● void run()
创建该类的子类时必须实现此方法。

● void start()
启动线程

● static void sleep(long t)
释放CPU的执行权t秒,但不释放锁。

● final void wait()
释放CPU的执行权,释放锁

● static void yied()
可以对当前线程进行临时暂停(让线程将资源释放出来)

在使用Thread启动一个子线程来干一些费时的操作时,子线程一般是由Activity来启动执行的(假如说没有Service组件),而Thread子线程 的运行是独立于 Activity 的,那么当一个 Activity 被 finish 之后,如果你没有主动停止 Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 并不会结束,它会一直执行下去。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用,你就无法对其进行控制。
另一方面,你也没有办法在不同的 Activity 中对同一Thread 进行控制。
举个例子:如果你的 Thread 需要不停地过一段时间就要连接服务器一次做某种同步,该 Thread 需要在 Activity 退出后也在运行。这个时候你就没有办法在您启动的 Activity 里面控制之前Activity创建的 Thread,这样这个子线程就相当于一个“野线程”了,你无法对其进行状态监听和控制。那这个时候就可以创建并启动一个 Service ,在 Service 里面就可以一直创建,运行并控制该 Thread了,不用担心Service退出之后无法再控制Thread,因为Service会一直运行在后台,它没有Activity的界面,不会“显式”的退出。这样便解决了上面使用Thread存在的问题。

参考:https://www.cnblogs.com/laoxiao79/p/8485867.html

 

 

 

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值