【Android面试】2023最新面试专题三:Java核心基础(下)
  FyeYl0ESQHUh 2023年11月02日 38 0

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。

【Android面试】2023最新面试专题三:Java核心基础(下)_面试题解析

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类的serialVersinotallow=1L,而在程序B中TestBean类的serialVersinotallow=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可以从这块共享内存中读出字节流,并反序列化成对象。

【Android面试】2023最新面试专题三:Java核心基础(下)_Android面试_02

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序列化。


最后有需要的小伙伴,可以点击下方课程链接详细了解!!!

https://edu.51cto.com/course/32703.html

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

FyeYl0ESQHUh