赞
踩
1、抽象类可以提供成员方法的实现细节,而接口中只能存在 public 抽象方法;
2、抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的;
3、接口中不能含有构造器、静态代码块以及静态方法,而抽象类可以有构造器、静态代码块和静态方法;
4、一个类只能继承一个抽象类,而一个类却可以实现多个接口;
5、抽象类访问速度比接口速度要快,因为接口需要时间去寻找在类中具体实现的方法;
6、如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。
7、如果你往接口中添加方法,那么你必须改变实现该接口的类。
8、接口更多的为了约束类的行为,可用于解耦,而抽象类更加侧重于代码复用。
1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,
此为浅拷贝。
2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
1、Exception是java程序运行中可预料的异常情况,咱们可以获取到这种异常,并且对这种异常进行业务外的处理。
2、Error是java程序运行中不可预料的异常情况,这种异常发生以后,会直接导致JVM不可处理或者不可恢复的情况。所以这
种异常不可能抓取到,比如OutOfMemoryError、NoClassDefFoundError等。
Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。
应用场景:1. 逆向代码,例如反编译2. 与注解相结合的框架,如 Retrofit3. 单纯的反射机制应用框架,例如 EventBus(事件总线)4. 动态生成类框架 例如Gson
Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。局限性:如在代码中定义的List和List等类型,在编译后都会变成List。JVM看到的只是List,而由泛型附加的类型信息对JVM 来说是不可见的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法避免在运行时刻出现类型转 换异常的情况。类型擦除也是Java的泛型实现方法与C++模版机制实现方式之间的重要区别。
三种注解:source、class、runtime。分别在源码,编译时,运行时存活自定义的source注解,可以用来对一些方法或者参数进行约束,比如说指定线程,指定参数类型class注解是配合apt编写注解处理器, 对注解的类或者变量进行解析生成.class文件 辅助工作 比方说 arouter,在注解处理器中生成代码,帮你做路径和activity的路由表,butterknife的注解帮你做findviewbyid的工作,runtime注解 则是在runtime时还能存在的,通常配合反射机制,把注解标注的对象拿到进行操作,比方说 retrofit,通过反射机制拿到注解的,接口和接口中的方法,在通过动态代理生成接口的实现类。
成员变量:生命周期伴随类对象,类对象回收时回收,存在堆里。
静态变量:不回收,在方法区随着类的加载而加载,随着类的消失而消失,由于类需要非常长时间的不使用,不利用,不关联,才有可能会被回收机制回收,所以静态成员变量的生命周期特别长,除非是共享数据,否则不建议使用静态;
局部变量:方法调用时创建 方法结束时被标记为可回收,存在栈里
privatefinalcharvalue[];
public String(char value[]) {
this.value=Arrays.copyOf(value,value.length);
}
public int length()
{ return value.length;
}
有四种:静态内部类、非静态内部类、局部内部类、匿名内部类
1.多态是继封装、继承之后,面向对象的第三大特性。
2.多态现实意义理解:
1)现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个
具体的同学张三既是学生也是人,即出现两种形态。
2)Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。
3)多态体现为父类引用变量可以指向子类对象。
4)前提条件:必须有子父类关系。
5)定义格式:父类类型 变量名=new 子类类型();
6)理解:多态是同一个行为具有多个不同表现形式或形态的能力,多态就是同一个接口,使用不同的实例而执行不同操作。
1、多态成员变量:编译运行看左边
Fu f=new Zi(); System.out.println(f.num);//f是Fu中的值,只能取到父中的值
- 1
- 2
2、多态成员方法:编译看左边,运行看右边
System.out.println(f1.show());//f1的门面类型是Fu,但实际类型是Zi, 所以调用的是重写后的方法。
- 1
- 2
作用:用来判断某个对象是否属于某种数据类型。
Fu f2=new Son(); if(f1 instanceof Zi){ System.out.println("f1是Zi的类型"); } else{ System.out.println("f1是Son的类型"); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
多态的转型分为向上转型和向下转型两种:
1、向上转型:多态本身就是向上转型过的过程
使用格式:父类类型 变量名=new 子类类型();
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。
2、向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。
实际概念区别:
区别1:不同的修饰符修饰(interface),(extends)
区别2:在面向对象编程中可以有多继承!但是只支持接口的多继承,不支持’继承’的多继承,而继承在java中具有单根性,子类只能继承一个父类
区别3:在接口中只能定义全局常量,和抽象方法,而在继承中可以定义属性方法,变量,常量等…
区别4:某个接口被类实现时,在类中一定要实现接口中的抽象方法而继承想调用那个方法就调用那个方法,毫无压力
1、线程池的重用:
线程的创建和销毁的开销是巨大的,而通过线程池的重用大大减少了这些不必要的开销,当然既然少了这么多消费内存的开销,其线程执行速度也是突飞猛进的提升。
2、控制线程池的并发数:
初学新手可能对并发这个词语比较陌生,特此我也是结合百度百科和必生所学得出最优解释,万万记着并发可跟并行不一样。
Java的泛型是伪泛型,编译时会进行泛型擦除
因此List<Number>和 List<Integer> 最终的类型都被擦除了,无论是List<String> 还是 List<Object> 都是List类型。
既然存在泛型擦除,但是下面的代码无法通过编译检查:
List<String> strs = new ArrayList<Integer>();
List<Object> objects = strs;
编译器会帮我我们检查明显的代码问题,因此上述代码会报错,这是编译器的行为,但是如果我们将代码改为:
List<String> strs = (List)new ArrayList<Integer>();
List<Object> objects = (List)strs;
注意,每条语句我们增加了强转声明。此时编译器能够成功完成编译。因此List<String>其实能够强转为List<Object>。但是存在隐患:
List<String> strs = (List)new ArrayList<Integer>();
List<Object> objects = (List)strs;
objects.add(123);
String str = strs.get(0);
上述代码使用objects(List<Object> )向集合中增加整型数据:123。然后通过 strs获取数据时,因为其类型为List<String>,但是真实数据类型为整型。此时就会发生运行时异常:
Exception in thread "main" java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String
Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 注解是元数据的一种形式,提供有关于程序但不属于程序本身的数据。注解本身没有特殊意义,对它们注解的代码的操作没有直接影响。
按照**@Retention** 元注解定义的注解保留级,注解可以一般常见于以下场景使用:
RetentionPolicy.SOURCE
,作用于源码级别的注解,在类中使用SOURCE
级别的注解,其编译之后的class中会被丢弃。可提供给Lint 检查、APT等场景使用。
在Android开发中,support-annotations
与androidx.annotation
中均有提供@IntDef
注解,此注解的定义如下:
@Retention(SOURCE) //源码级别注解
@Target({ANNOTATION_TYPE})
public @interface IntDef {
int[] value() default {};
boolean flag() default false;
boolean open() default false;
}
Java中Enum(枚举)的实质是特殊单例的静态成员变量,在运行期所有枚举类作为单例,全部加载到内存中。比常量多5到10倍的内存占用。
此注解的意义在于能够取代枚举,实现如方法入参限制。
如:我们定义方法test
,此方法接收参数teacher
需要在:Lance、Alvin中选择一个。如果使用枚举能够实现为:
public enum Teacher{
LANCE,ALVIN
}
public void test(Teacher teacher) {
}
而现在为了进行内存优化,我们现在不再使用枚举,则方法定义为:
public static final int LANCE = 1;
public static final int ALVIN = 2;
public void test(int teacher) {
}
然而此时,调用test
方法由于采用基本数据类型int,将无法进行类型限定。此时使用@IntDef增加自定义注解:
public static final int LANCE = 1;
public static final int ALVIN = 2;
@IntDef(value = {LANCE, ALVIN}) //限定为LANCE,ALVIN
@Target(ElementType.PARAMETER) //作用于参数的注解
@Retention(RetentionPolicy.SOURCE) //源码级别注解
public @interface Teacher {
}
public void test(@Teacher int teacher) {
}
此时,我们再去调用test
方法,如果传递的参数不是LANCE
或者ALVIN
则会显示 Inspection 警告(编译不会报错)。
SOURCE另一种更常见的应用场景是结合APT使用。APT全称为:“Anotation Processor Tools”,意为注解处理器。顾名思义,其用于处理注解。编写好的Java源文件,需要经过javac
的编译,翻译为虚拟机能够加载解析的字节码Class文件。注解处理器是 javac 自带的一个工具,用来在编译时期扫描处理注解信息。你可以为某些注解注册自己的注解处理器。 注册的注解处理器由javac
调起,并将注解信息传递给注解处理器进行处理。
注解处理器是对注解应用最为广泛的场景。在Glide、EventBus3、Butterknifer、Tinker、ARouter等等常用框架中都有注解处理器的身影。但是你可能会发现,这些框架中对注解的定义并不是
SOURCE
级别,更多的是CLASS
级别,其实:**CLASS包含了SOURCE,RUNTIME包含SOURCE、CLASS。**所以CLASS是包含了SOURCE的场景,RUNTIME则包含了所有保留级的注解使用场景。所以对于APT来说,不管使用何种保留时都可以。
定义为CLASS
的注解,会保留在class文件中,但是会被虚拟机忽略(即无法在运行期反射获取注解)。此时完全符合此种注解的应用场景为字节码操作。如:AspectJ、热修复Roubust等框架。
在Android开发中,保留在class,但是会在dex被抛弃
注解保留至运行期,意味着我们能够在运行期间结合反射技术获取注解中的所有信息。如Retofit,借助反射获取获取用户定义在注解中的请求配置信息,基于获取的这些请求配置完成对Request请求的构建。
答:
用户对上述几种状态的变更有着不同的期望,对于前两项,用户期望应用重新回到前台时保持着之前的状态,如果用户在屏幕翻转之前正在向输入框中输入数据,在屏幕翻转之后不希望已经输入的数据被删除,用户同样期望在切换到QQ回复好友消息后,即使之前的应用被系统销毁,但当用户重新返回应用后输入框中的文本依然存在。当用户手动销毁应用之后,用户期望下一次重新打开时应用以空白状态进行显示。
但是问题来了,针对上述三种情况,系统默认会销毁Activity从而小村存储在Activity实例中的所有界面状态。当然对于第三种情况着正是用户期望的,但我们需要通过一些方式来保存应用的某些状态以保证在发生配置变更或系统自动销毁Activity的时候恢复界面瞬态。
Android为我们提出了解决方案。我们可以通过使用ViewModel和onSaveInstanceState()保留页面瞬态。
ViewModel将数据保存在内存中,并与一个Actitvity相关联,在配置更改期间保存在内存中,系统会自动将ViewModel与发生配置更改后产生的新Actitivy实例相关联。
画草图:
onSaveInstanceState()回调在系统终止应用时被调用,我们可以在这个回调中保存页面瞬态。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KhHj1fxG-1684741434870)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230519213819512.png)]
除了使用onSaveInstanceState在系统销毁进程时保存数据,我们还可以使用SavedStateHandle对象保存数据,保存在SavedStateHandle中的数据会在进程被系统终止后继续保留。
ViewModel通过其构造函数接收SavedStateHandle对象,要设置ViewModel接收SavedStateHandle对象,需要向ViewModelProvider中传递SavedStateViewModelFactory对象,具体用法如下:
myViewModel = new ViewModelProvider(this, new SavedStateViewModelFactory(getApplication(), this))
.get(MyViewModel.class);
然后在自己实现的ViewModel的子类中添加构造方法:
public class MyViewModel extends ViewModel {
private SavedStateHandle hanlder;
public MyViewModel(SavedStateHandle hanlder) {
this.hanlder = hanlder;
}
}
简单来说,Binder 是android系统工程师为android 定制的一个跨进程通信方法,当然它也不是android 系统原创的,是参考了OpenBinder的实现而引进到Google的。Binder是综合了android系统的特点,从性能,设计架构,安全性等几个方面的综合平衡而设计的,具体的关于Binder的实现细节,朋友们可以参考 上面的题目 《描述下Binder机制原理》进行系统学习。
应该从几个方面与传统IPC机制做对比。
通过上面几个比较,特别是安全性这块,所以最终Android选择使用Binder机制进行通信。
首先,如果Handler的Callback存在,若Callback返回true,handleMessage则不会执行;若Callback返回false,则handleMessage仍然会执行。Handler对于消息的处理都会在Handler#dispatchMessage
中完成分发,具体细节分析如下代码所示:
public void dispatchMessage(Message msg) { if (msg.callback != null) { // 1. 设置了Message.Callback(Runnable) handleCallback(msg); } else { if (mCallback != null) { // 2. 设置了 Handler.Callback(Callback ) if (mCallback.handleMessage(msg)) { return; } } // 3. 未设置 Handler.Callback 或 返回 false handleMessage(msg); } } public interface Callback { public boolean handleMessage(Message msg); }
我们一起来看一下 Callback的源码,Handler.Callback的定义如下:
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
Handler.Callback#handleMessage
在处理Message后需要返回boolean类型的结果,而此返回值如果为true,那么在Handler#dispatchMessage
中会直接return:
if (mCallback.handleMessage(msg)) {
return;
}
因此Handler#handleMessage
则不会执行。
篇幅原因,暂时只放了部分面试题内容,具体已经整理成了PDF文档,有需要的点击下方二维码免费领取。
友情提示:所有的面试题目都不是一成不变的,面试题目只是给大家一个借鉴作用,最主要的是给自己增加知识的储备,有备无患。
希望正在准备面试的朋友们能顺顺利利找到自己心仪的工作!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。