每日五题---java面试题220803


1、描述一下 JVM 加载 class 文件 的原理机制?

返回目录
JVM 中类的装载是由 类加载器(ClassLoader) 和 它的子类来实现的, Java中的类加载器是一个重要的 Java 运行时系统组件,它负责在运行时查找和装入文件中的类。

由于 Java 的跨平台性,经过编译的 Java 源程序并不是一个可执行程序,而是一个或多个类文件。当Java 程序需要使用某个类时,JVM 会确保这个类已经被加载、连接(验证、准备和解析)和初始化。类的加载是指把类的 .class 文件中的数据读入到内存中,通常是创建一个字节数组读入.class 文件,然后产生与所加载类对应的 Class 对象。加载完成后,Class 对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后 JVM 对类进行初始化,包括:1)如果类存在直接的父类并且这个类还没有初始化,那么就先初始化父类;2)如果类中存在初始化语句,就依次执行这些初始化语句。

类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap扩展加载器(Extension系统加载器(System)用户自定义加载器(Java.Lang.ClassLoader 的子类)。从 Java 2(JDK1.2)开始,类加载过程采取了[父亲委托机制](JVM中类加载器的父委托机制 - 走看看 (zoukankan.com))(PDM)。PDM 更好的保证了 Java 平台的安全性,在该机制中,JVM 自带的 BootStrap 是根加载器,其他的加载器都有且仅有一个父类加载器。类的加载首先请求父类加载器,父类加载器无能为力时才由其子类加载器自行加载。JVM 不会向 Java 程序提供对 Bootstrap 的引用。下面是关于几个类加载器的说明。

  • Bootstrap: 一般用本地代码实现,负责加载 JVM 基础核心类库(rt.jar)
  • Extension:从 java.ext.dirs 系统属性所指定的目录中加载类库,它的父加载器是 Bootstrap;
  • System:又叫应用类加载器,其父类是 Extension。 它是应用最广泛的类加载器。 它从环境变量 classpath 或 系统属性 java.class.path 所指定的目录中记载类,是用户自定义加载器的默认父类加载器。

2、char 型变量中能不能存贮一个中文汉字,为什么?

返回目录
char 类型可以存储一个中文汉字, 因为 Java 中使用的编码是 Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个 char 类型占 2 个 字符(16比特),所以放一个中文是没问题的。

补充:使用 Unicode 意味着字符在 JVM 内部和外部有不同的表现形式,在 JVM 内部都是 Unicode, 当这个字符被从 JVM 内部转移到外部时(例如存入文件系统中),需要进行编码转换。所以 Java 中有字节流和字符流,以及在字符流和字节流之间进行转换的转换流,如 InputStreamReaderOutputStreamReader, 这两个类是字节流和字符流之间的适配器类,承担了编码 转换的任务;对于 C 程序员来说,要完成这样的编码转换恐怕要依赖于 union(联合体/共用体)共享内存的特征来实现 了。

3、抽象类(abstract class) 和接扣 (interface)有什么异同?

返回目录

  • 相同点

    • 都不能被实例化
    • 接扣的实现类或抽象类的子类都只有实现接口或抽象类中的方法后才能被实例化
  • 不同点

    1. 接口只有定义,其方法不能在接口中实现,只有实现接口的类才能实现接口中定义的方法,而抽象类可以有定义与实现,即其方法可以在抽象类中被实现。

    2. 接口需要实现(用 implements),但抽象类只能被继承(用 extends)。一个类可以实现多个接口,但一个类只能继承一个抽象类,因此使用接口可以间接达到多重继承的目的。

    3. 接口强调特定功能的实现,其设计理念是“has-a”关系;而抽象类强调所属关系,其设计理念为“is-a”关系。

    4. 接口中定义的成员变量默认为 public static final, 只能够有静态的不能被修改的数据成员,而且,必须给其赋初值,其所有成员方法都是 public、 abstract的,而且只能被这两个关键字修饰。而抽象类可以有自己的数据成员变量,也可以有非抽象的成员方法,而且抽象类中的成员变量默认为 default (本包可见),当然也可以被定义为 private、protected 和public, 这些成员变量可以在子类中被重新定义,也可以被重新赋值,抽象类中的抽象方法(其前有 abstract 修饰)不能用 private、static、synchronized、native 等访问修饰符修饰,同时方法必须以分号结尾,并且不带花括号。所以,当功能需要累积时,用抽象类;不需要累积时,用接口。

    5. 接口被运用于实现比较常见的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于日后重新对里面的代码进行修改。

简单点说。接口是一种特殊形式的抽象类,使用接口完全有可能实现与抽象类相同的操作,但一般而言,抽象类多用于在同类事物中有无法具体描述的方法的场景,所以当子类和父类之间存在有逻辑上的层次结构时,推荐使用抽象类;而接口多用于不同类之间,定义不同类之间的通信规则,所以当希望支持差别较大的两个或者多对象之间的特定交互行为时,应该使用接口。此外,接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。抽象类也可以有静态的 mian 方法。

4、静态嵌套类(Static Nested Class)和内部类(Inner Class) 的不同?

返回目录
[666–>答案点击此处]((1条消息) Java - 静态嵌套类(Static Nested Class)和内部类(Inner Class)的不同?_LiveEveryDay的博客-CSDN博客)

  • 通常的内部类需要在外部类实例化后才能被实例化

  • java中非静态内部类对象的创建要依赖其外部类对象,静态方法中没有this,也就是说没有所谓的外部类对象,因此无法创建内部类对象。如果要在静态方法中创建内部类对象,可以这样做:

    new Outer().new Inner();
    

5、Java 中会存在内存泄漏吗,请简单描述。

返回目录
理论上 Java 因为有垃圾回收机制(GC)不会存在内存泄漏问题(这也是 Java 被广泛使用于服务器端编程的一个重要原因);然而在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄漏的发生。例如 Hibernate 的 Session(一级缓存)中对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄漏。下面的例子中的代码也会导致内存泄漏。

package day220803;

import java.util.Arrays;
import java.util.EmptyStackException;

/**
 * @ProjectName: java_test_01
 * @Package: day220803
 * @ClassName: MyStack
 * @Author: [Lucky Star]
 * @Date: 2022/8/3 22:24
 * @Version: V1.0
 **/
public class MyStack<T> {
    private T[] elements;
    private int size = 0;
    private static final int INIT_CAPACITY = 16;
    public MyStack(){
        elements = (T[]) new Object[INIT_CAPACITY];
    }
    public void push(T elem) {
        ensureCapacity();
    }
    public T pop(){
        if (size == 0)
        throw new EmptyStackException();
        return elements[--size];

    }
    private void ensureCapacity(){
        if (elements.length == size){
            elements = Arrays.copyOf(elements, 2 * size +1);
        }
    }
}

上面的代码实现了一个栈(先进后出(FILO))结构,乍看之下似乎没有什么明显的问题,它甚至可以通过你编写的各种单元测试。然而其中的pop 方法却存在内存泄漏的问题,当我们用 pop 方法弹出栈中的对象时,该对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,因为栈内部维护这对这些对对象的过期引用(obsolete reference)。在支持垃圾回收的语言中,内存泄漏是很隐蔽的,这种内存泄漏其实就是无意识的对象保持。如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象,也不会处理该对象引用的其他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大的影响,极端情况下会引发 Disk Paging(物理内存与硬盘的虚拟内存交换数据),甚至造成 内存溢出(OutOfMemoryError)。

源链接-掘金

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值