面向对象面试题

对象

异常

java中所有的异常都继承自Throwable,只有继承自Throwable的类才能被Throws抛出,thrwable类分为Exption和Error俩个,其中Error时比较少见的致命错误,而Exption下还分为checked异常也叫编译时异常,这写异常必须要进行处理,还有一种异常时再运行时产生的成为uncheckd异常也叫运行时异常,这种异常即使不编写异常处理代码,依然可以通过编译。

对象创建的过程

首先在堆中创建一个对象,将对象引用入栈.复制一份对象的引用,利用对象引用调用构造方法,将对象的引用赋值给变量

Object o=new Object();占用了多少内存

32位的java是4字节的对象头,还有8字节的实例数据,对象内存必须是八的倍数,因此在关闭压缩普通对象的指针的时候,为12字节.而64位系统中8字节是对象头,16字节是实例数据,因此总内存大小是24字节

java基础数据类型的字节占用

对象类型字节
boolean1
byte1
short2
char2
int4
float4
long8
double8

对象在内存中的布局

对象在内存中分为对象头实例数据和对齐数据

其中对象头分为mark word和klass pointer

mark word存储了对象的哈希码和gc分代年龄

klass pointer是对象指向它们的元数据类型的指针.虚拟机通过它来确定这个对象是哪个类的实例

什么是内部类?内部类的作用

内部类分为实例内部类,静态内部类,局部内部类,匿名内部类.内部类顾名思义就是累当中定义的类

内部类增强了封装,把类隐藏在了外部类当中,不允许其他类访问这个内部类,增加了代码的可维护性

四个内部类的理解

实例内部类:是直接定义在类当中的一个类,,在内部咧实例类当中不能有静态成员,外部类不能直接访问内部类的成员

静态内部类:静态内部类不需要创建外部类对象可以直接获取,静态类中可以定义静态和非静态的成员

局部内部类:定义在方法中的内部类,不能使用修饰符只能在定义的方法中使用,不能包含静态方法

匿名内部类:没有构造器,必须要使用父类或者接口实现才能进行定义,在安卓中开发中使用的比较多

接口和抽象类的区别

  • 接口中可以定义抽象方法也可以定义普通方法
  • 类只能单继承而接口可以多继承
  • 抽象类中可以有构造方法,接口中不能有构造方法
  • 虽然俩者都可以定义静态成员变量,抽象类中的成员静态变量的访问类型可以任意,但接口中定义的变量只能是public static

接口更多的是在系统架构设计方面发挥作用,主要用于定义模块之间的通信规则.而抽象类在代码实现方面发挥作用,可以实现代码的重用

静态属性和静态方法是否可以被继承?是否可以被重写?以及原因?

今天属性和静态方法可以被继承但是没有被重写而是被隐藏,静态方法时属于类的,调用的时候直接通过类名.方法名完成,不需要继承机制就可以调用.如果还想调用父类的静态方法,直接父类名.方法名即可

闭包和局部内部类区别

java中的闭包可以用接口与内部类实现,闭包的价值在于可以作为第一集对象进行传递和保存

java中没有直接实现闭包的方式,通常是使用接口与内部类配合进行实现,局部内部类是内部类的一种.俩者并无实际的关联.

utf-8和jbk编码占多少个字节

utf-8是不定长的,大多数情况下中文占3个字节,gbk一个中文占用俩个字节

序列化方式

把对象以流的方式写到文件中保存,叫写对象的序列化

被序列化的类要实现Serializable这个接口,实现了serializable接口的类会添加一个标记,进行序列化的时候会对这个标记进行检查.

之后调用ObjectOutputStream传入FileOutputStream进行实例化,调用实例化对象中的writeObject()方法传入要进行序列化的对象就能完成序列化了

哪些情况下的对象会被垃圾回收机制处理掉?

java使用的是可达性分析算法,判断一个有没有到GC Roots的引用链,当一个对象到GC Roots没有任何引用链时,则证明此对象不可用。会等待垃圾回收。当cpu空闲时,或者内存不够用时,会执行GC操作进行垃圾回收

静态代理和动态代理的区别,什么场景使用?

静态代理和动态代理的区别是静态代理在进行编译的时候class文件纠结存在了,而动态代理是用反射机制创建而成

因此静态代理的效率更高,代理模式可以让业务逻辑的代码更加纯粹,不用去关注一些公共的业务,并且公共业务发生扩展的时候方便集中管理.spring的aop机制就是采用动态代理的机制来实现面向切面编程.

可以用作日志,事务,访问统计等场景.

java中实现多态的机制是什么

是父类或接口定义的引用变量可以指向子类或者实现类的实例对象,而程序调用的方法在运行期间才动态绑定,就是引用变量所指向的具体实现对象方法,也就是内存里正在运行的那个对象方法,而不是引用变量中定义的方法

说一下泛型原理和好处,并举例说明

在java中的泛型是伪泛型,在生成java字节码的时候是不包含泛型中的类信息的.使用泛型的时候加上类型参数,会在编译的时候去掉,这个过程就称为,类型擦除

泛型的好处是在编译的时候检查类型安全,并且所有强制转换都是隐式的,提高了代码的重用率。

举例:可以直接通过反射拿到对应的字节码,这样就能绕过类型检测

解析和分派的认识

解析和分派属于方法调用内容,方法调用阶段唯一的任务就是确定被调用方法的版本,暂时还不涉及方法内部的运行过程

解析

java中调用的目标方法,在class文件中都是常量池中符号的引用,在类加载的阶段,会将其中一部分符号引用转换为直接使用.这种解析能成立的前提是:方法在程序运行之前就有一个可确定的调用版本,并且在运行期内是不可变的,即编译期可知,运行期不可变,这类目标方法的调用称之位解析

分派

分派是多态性的体现,java虚拟机底层提供了开发中重载和重写的底层实现.其中重载数据静态分派,重写属于动态分派.解析调用一定是一个静态的过程,在编译期就完全确定,在类加载的阶段就将设计的符号引用全部转变为可以直接引用,不会延迟到运行期再去完成

java创建对象的几种方式

java提供了以下四种创建对象的方式

  • new创建新对象
  • 反射创建对象
  • 采用clone创建
  • 通过序列号创建

关键字

final、finally与finalize的区别

在java中final可以修饰类,方法和变量

  • 当final修饰类的时候表示该类不能被其他类集成
  • 当修饰方法可以对方法进行锁定,子类不能对于方法重写或者修改
  • 修饰变量代表常量只能被赋值一次,如果是一个成员变量,该变量一定要在声明的时候初始化

finally是作为异常处理的一部分,只能用在try/catch的语句中,表示被finally包裹的代码块一定会执行(大部分情况下)

finalizefinalize()是在java.lang.Object里定义的,也就是说每一个对象都有这么个方法。这个方法在gc启动,该对象被回收的时候被调用。其实gc可以回收大部分的对象.一般用来释放非java资源,如文件资源数据库连接等

Serializable 和Parcelable 的区别

serializable是java自带的序列化标记接口,实现该接口的类才能完成序列化与反序列化

但serializable频繁的IO操作在内存序列化的开销比较大,而内存资源对于android系统比较宝贵,因此android提供了Parcelable接口来实现序列化操作,Parcelable性能好,内存开销小,但缺点是使用起来比较麻烦

泛型中extends和super的区别

extends是设置泛型的上线,用来限定元素的类型必须得指定类型或其子类

super是设置泛型的下限,用来限定元素的类型必须叙事指定元素或其父类

说一下String类的了解,为什么String要设计成不可变的

String类是java提供的字符串类,他的本质其实是char类型的数组,是一个定长的字符串,在java.lang包下,在代码中直接出现用双引号引起来的字符串则是String类的匿名对象.

字符串常量池优化:字符串常量池是java堆内存中一个特殊的存储区域,当创建一个String对象的时候,加入字符串已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象.假若设计成可变的会导致各种逻辑错误,比如改变一个对象会影响到另一个独立对象,它是一种常量池的优化手段

哈希码java中哈希码被频繁的使用,比如在hashmap等容器中.字符串不变性保证了hash码的的唯一性,可以放心进行缓存,这是一种性能优化手段,意味着每次不会重新去计算哈希码.

敏感信息String会被用来存放一些例如数据库密码,文件路径等的敏感信息,假若String不是固定不变的,将会引起各种安全隐患,(比如String在其他地方被修改了)

Last modification:April 21, 2022
如果觉得我的文章对你有用,请随意赞赏