6 String s = new String("xxx");创建了几个String对象?
这道题想考察什么?
在开发中常用的字符串String
考察的知识点
Java基础,JVM常量池与对象内存分配
考生应该如何回答
首先代码String s = new String("xxx")
中包含关键字new
, 我们都知道此关键字是创建类的实例对象。JVM在运行期执行new指令因此这会在堆中创建一个String对象。
其次,在String的构造方法中传递了"xxx"字符串,此处的"xxx"是一个字符串常量。JVM会首先从字符串常量池中尝试获取其对应的引用。如果不存在,则会在堆中创建"xxx"的字符串对象,并将其引用保存到字符串常量池然后返回。
因此,如果xxx
这个字符串常量不存在,则创建两个String对象;而如果存在则只会创建一个String对象。
7 finally中的代码一定会执行吗?try里有return,finally还执行么
这道题想考察什么?
对Java语言的深层次理解,避免在开发时写出"问题"代码
考察的知识点
JVM执行流程
考生应该如何回答
在Java官方文档中对finally的描述如下:
The `finally` block *always* executes when the `try` block exits.
大致意思是:finally代码块中的内容一定会得到执行。
JVM规范里面同样也有明确说明
If the try clause executes a return, the compiled code does the following:
1. Saves the return value (if any) in a local variable.
2. Executes a jsr to the code for the finally clause.
3. Upon return from the finally clause, returns the value saved in the local variable.
意思是如果在try中存在return的情况下,会把try中return的值存到栈帧的局部变量表中,然后去执行finally语句块,最后再从局部变量表中取回return的值返回。另外,当try和finally里都有return时,会忽略try的return,而使用finally的return。
特殊情况
在正常情况下,finally中的代码一定会得到执行,但是如果我们将执行try-catch-finally 代码块的线程设置为守护线程,或者在fianlly之前调用System.exit
结束当前虚拟机,那么finally则不会得到执行:
try{
System.exit(0);
}catch (Exception e){
}finally {
}
Thread t1 = new Thread(){
@Override
public void run(){
//try-catch-finally
}
};
t1.setDaemon(true);//设置为守护进程
t1.start();
8 Java异常机制中,异常Exception与错误Error区别
这道题想考察什么?
在开发时需要时候需要自定义异常时,应该选择定义Excption还是Error?编写的代码触发Excption或者Error分别代表什么?
考察的知识点
Java异常机制
考生应该如何回答
在Java中存在一个Throwable
可抛出类,Throwable
有两个重要的子类,一个是Error,另一个则是Exception。
![](https://img.haomeiwen.com/i27607674/e2b26bdd7c2886d6.png)
Error
是程序不能处理的错误,表示程序中较严重问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError等等。这些错误发生时,JVM一般会选择线程终止。这些错误是不可查的,它们在程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
Exception
是程序可以处理的异常。而Exception又分为运行时异常(RuntimeException)与非运行时异常。
-
运行异常
运行时异常,又称不受检查异常 。所谓的不受检查,指的是Java编译检查时不会告诉我们有这个异常,需要在运行时候才会暴露出来,比如下标越界,空指针异常等。
-
非运行时异常
RuntimeException之外的异常我们统称为非运行时异常,比如IOException、SQLException,是必须进行处理的异常(检查异常) ,如果不处理(throw到上层或者try-catch),程序就不能编译通过 。
9 序列Parcelable,Serializable的区别?(阿里)
详细讲解
享学课堂移动互联网系统课程:架构师筑基必备技能《NDK专题-JNI实战篇》
这道题想考察什么?
掌握序列化接口实现原理,针对不同场景在工作中合理运用
考察的知识点
Parcelable原理
Serializable原理
考生应该如何回答
序列化 是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。Serializable是Java提供的序列化机制,而 Parcelable则是Android提供的适合于内存中进行传输的序列化方式。
Serializable
Serializable是Java中提供的一个 序列化接口,然而这个接口并没有任何方法需要实现者实现。
public interface Serializable {
}
这表示Serializable接口知识用来标识当前类可以被序列化与反序列化。
基本使用
实现了Serializable接口的类对象能够通过 ObjectOutputStream 将需要序列化数据写入到流中,因为 Java IO 是一种装饰者模式,因此可以通过 ObjectOutStream 包装 FileOutStream 将数据写入到文件中或者包装 ByteArrayOutStream 将数据写入到内存中。也可以通过 ObjectInputStream 从磁盘或者内存读取数据然后转化为指定的对象即可(反序列化)。
try {
TestBean serialization = new TestBean("a","b");
//序列化
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("/path/xxx"));
os.writeObject(serialization);
//反序列化
ObjectInputStream is = new ObjectInputStream(new FileInputStream("/path/xxx"));
TestBean deserialization = (TestBean) is.readObject();
} catch (IOException e) {
e.printStackTrace();
}
实现了Serializable接口的类中成员属性除基本数据类型外,即引用类型,也需要实现Serializable接口,否则将在序列化时抛出java.io.NotSerializableException
异常。
public class TestBean implements Serializable {
private String name;
private String pwd;
//Gson未实现Serializable接口,TestBean实例对象在序列化时抛出NotSerializableException
private Gson gson = new Gson();
public TestBean(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
public TestBean() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
因此,如果需要对某个类进行序列化时,对于类中不需要进行序列化与反序列化的属性,可以使用 transient 关键字声明。
private transient Gson gson = new Gson();
serialVersionUID
在实现了Serializable接口的类中,应该为此类定义一个serialVersionUID属性:
private static final long serialVersionUID = 1L;
虽然不定义程序依然能够正常运行。 但是Java序列化的机制是通过判断类的serialVersionUID来验证的版本一致的。
序列化操作时会把当前类的serialVersionUID写入到序列化文件中,当反序列化时系统会自动检测文件中的serialVersionUID,判断它是否与当前类中的serialVersionUID一致。如果一致说明序列化文件的版本与当前类的版本是一样的,可以反序列化成功,否则就失败。
例如在A程序中TestBean类的serialVersionUID=1L,而在程序B中TestBean类的serialVersionUID=2L。 那么A程序序列化输出的数据,在B程序中就无法反序列化为TestBean对象。
Parcelable
Parcelable是Android为我们提供的序列化的接口。相对于Java的Serializable,Parcelable的使用稍显复杂:
public class TestBean implements Parcelable {
private String name;
private String pwd;
public TestBean(String name, String pwd) {
this.name = name;
this.pwd = pwd;
}
public TestBean() {
}
public int describeContents() {
return 0;
}
//序列化
public void writeToParcel(Parcel out, int flags) {
out.writeString(name);
out.writeString(pwd);
}
public static final Parcelable.Creator<TestBean> CREATOR
= new Parcelable.Creator<TestBean>(){
public TestBean createFromParcel(Parcel in) {
return new TestBean(in);
}
public MyParcelable[] newArray(int size) {
return new TestBean[size];
}
}
private TestBean(Parcel in) {
// 反序列化:按序列化顺序读取
name = in.readString();
pwd = in.readString();
}
}
Parcelable接口的实现类是通过Parcel写入和恢复数据的,并且必须要有一个非空的静态变量 CREATOR。
Parcel
Parcel其实就是一个数据载体,可以将序列化之后的数据写入到一个共享内存中,其他进程通过Parcel可以从这块共享内存中读出字节流,并反序列化成对象。
![](https://img.haomeiwen.com/i27607674/a878e10943c6c8a4.png)
Parcel可以读写原始数据类型,也可以读写实现了Parcelable对象。
因此Parcelable实现序列化的原理就是将一个完整的对象进行分解,而分解后的每一部分都是基本数据类型或者其他实现了Parcelable/Serializable的类型,从而实现传递对象的功能。
区别
Parcelable和Serializable都是实现序列化并且在Android中都可以使用Intent进行数据传递。Serializable是Java的实现方式,实现过程中会频繁的IO操作,但是实现方式简单。而Parcelable是Android提供的方式,效率比较高(号称比Serializable快10倍),但是实现起来复杂一些 。
如果只需要在内存中进行数据传输是,序列化应该选择Parcelable,而如果需要存储到设备或者网络传输上应该选择Serializable。这是因为Android不同版本Parcelable数据规则可能不同,所以不推荐使用Parcelable进行数据持久化。
10 为什么Intent传递对象为什么需要序列化?(阿里)
这道题想考察什么?
掌握序列化的意义与Android数据传输的原理
考察的知识点
序列化
Binder
考生应该如何回答
在Android中使用Intent传输数据除了基本数据类型之外,对于其他类型对象需要此类型实现了Serializable或者Parcelable序列化接口才能进行传输。
以startActivity为例:
Intent intent = new Intent(context,OtherActivity.class);
//字符串实现了Serializable序列化
intent.putExtra("a","享学");
//Message实现了Parcelable序列化
intent.putExtra("b",new android.os.Message());
//错误:上下文context并未实现序列化
intent.putExtra("c",context);
startActivity(intent);
Intent传输数据本质上是使用Binder来完成的。Intent启动组件需要借助AMS完成,因此startActivity
会离开当前应用进程,进入AMS所在的system_server进程进行跨进程通信。这就意味着传输的对象需要在不同进程之间进行传输。
为了保护不同进程互不干扰,进程隔离让system_server进程无法直接获取应用进程内存中的对象。因此必须通过类似于复制的手段,将应用进程的对象传递给system_server进程,再由system_server进程传递给应用中的OtherActivity
。
根据《9 序列Parcelable,Serializable的区别?》可知,Serializable会利用IO将对象写入到文件中;而Parcelable则会将对象写入到Parcel中,两种方式都可以解决跨进程的数据传递。因此Intent传递的对象需要实现Serializable或者Parcelable序列化。
文末
整理不易,白嫖太易!有需要的读者朋友们可以关注一下。以上都可分享~
网友评论