基础高频问题

  • 1、面向对象以及Java三大特性的理解?
  • 2、接口和抽象类的区别
  • 3、Java的内部类
  • 4、访问修饰符权限
  • 5、==与equals()的区别
  • 6、HashCode的作用
  • 7、Java创建对象的方式
  • 8、反射实现的方式
  • 9、异常体系结构
  • 异常的处理方式
  • 10、深拷贝和浅拷贝
  • 11、final和static
  • 12、序列化
  • 什么是java序列化,如何实现java序列化?或者请解释 Serializable接口的作用
  • 13、String类和Files类的常用方法
  • 14、Java的io分为几种
  • BIO、NIO、AIO


1、面向对象以及Java三大特性的理解?

面向对象

面向对象思想将客观世界中的事物描述为对象,并通过抽象思维方法将需要解决的实际问题分解为人民易于理解的对象模型,然后通过这些对象模型来构建应用程序的功能。 面向过程就是通过一步一步调用函数去完成相应的功能。而面向对象就是把功能地实现拆分为步骤,每个步骤就是一个对象,这个对象专门做这个事情。复用性大大提升。更能体现人类地思考方式。
其具有四大特征,封装,抽象,继承,多态。

Java的3大特性理解

封装:

把描述一个对象的属性和行为的代码封装在一个模块中,也就是一个类中,属性用变量,行为用方法,方法可以访问同一个对象中的属性。
抽象:
把现实中的对象抽象为类,分为过程抽象和数据抽象

  • 数据抽象–>鸟有翅膀、羽毛等(类的属性)
  • 过程抽象–> 鸟会飞,会叫(类的方法)

继承
继承:子类继承父类的特征和行为。子类可以有父类的方法,属性(非private)。子类也可以对父类进行扩展,也可以重写父类的方法。缺点就是提高代码之间的耦合性。
多态
顾名思义就是多种状态

  • 现实生活中,学生是人类的一种,老师,医生也是人类的一种,这就是人类的多种身份上的状态。
  • 在Java中也有多态的特性。
    1、类中继承体现
    例如:Student 类继承 Person 类
    Student student=new Student() 这时是一个状态
    Person person=new Student()这个时候又是另一个状态。
    2、方法体现(方法重载)
    在一个类中的两个方法
void add(int a,int b){...}
void add(double a,double b){...}

这两个方法虽然方法名相同,但是在传入不同类型的参数的时候就会是不同的调用过程。这也是多态的体现。
3、接口体现,一个接口可以有多个实现类,在实例化不同的实现类,也会有不同的实现方式。

2、接口和抽象类的区别

没有具体的内容,就是抽象。

类(接口)中成员的区别

抽象类:
1、有构造方法用于子类的实例化使用;
2、可以定义成员变量和常量
3、成员方法可以是抽象的(用abstract修饰)也可以是非抽象的

接口
1、没有构造方法
2、只能定义常量 默认是public static final修饰的
3、jdk1.7的时候只能定义抽象方法默认 public abstract修饰,jdk1.8之后可以定义default 或static修饰的有具体实现的方法。

具体实现方式的区别

类与类:
继承关系,只能单继承。可以多层继承。

类与接口:
实现关系,可以单实现,也可以多实现。
类还可以在继承一个类的同时实现多个接口。

接口与接口:
继承关系,可以单继承,也可以多继承

为什么要这么干

抽象类:就是一个继承体系中的共性内容的抽象。
接口:大致相同的一类功能的集合。

如果是注重某一种功能的实现。这种实现方式有很多种,里面的功能性质差不多,但是数量很大,就建议用接口。
但是如果是有自己的细节,数据仅仅需要扩展一下,这时候就用抽象类。
所以说:关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。

3、Java的内部类

成员内部类

类比成员方法,不能拥有静态域但是可以访问外部类的静态域

静态内部类

定义在外部类的内部,使用static修饰,类比静态方法,静态内部类不需要外部类对象产生就能使用,不能访问外部类的成员域,但能访问静态域

局部内部类(定义在方法内部)

对外部完全隐藏,因此方法内部类不能有任何访问修饰符

方法内部类没有访问形参是,这个形参是可以在方法中随意修改的,一旦方法内部类中使用了形参,这个形参必须被声明为final。

匿名内部类

实例化一个抽象类,或接口地时候使用。

4、访问修饰符权限

1.private:及私有的,对访问权限限制最窄的修饰符。被private修饰的属性以及方法只能被该类的对象访问。它的子类也不可以访问,更不支持跨包访问。
就好比自己地隐私一样,除了自己(本类),别人都不能查看

2.protected:及保护访问权限,是介于public和private之间的一种访问修饰。被protected修饰的属性及方法只能被类本身的方法和子类访问。(子类在不同的包中也可以访问)

3.public:及共有的,是访问权限限制最宽的修饰符。被public修饰的类、属性、及方法不仅可以跨类访问,而且可以跨包访问。

4.default:及默认的,不加任何访问修饰符。常被叫做“默认访问权限”或者“包访问权限”。无任修饰符时,只支持在同一个包中进行访问。

private修饰的如何访问呢?
private通过反射获取,可以设置setAccessable为true实现

5、==与equals()的区别

首先严格来说这两个本来就没有可比性。==是Java的比较运算符,但是equals()是Java Object类中的方法,代码如下。

public boolean equals(Object obj) {
        return (this == obj);
    }

== 比较基本数据类型的时候就是比较数值是否相等;
比较引用数据类型的时候就是比较引用是否相等。
特殊

String str1="aa";
String str2="aa";

按理来说String是引用类型,但是这时候str1==str2是返回true,因为没有用new关键字 此时的值存放在常量池,按常量处理,所以返回true。

但是用equals()的时候取决于要比较的引用类型有没有重写equals()方法。如果没有重写,那么就默认继承Object类,使用Object中的equals方法和==效果一样。重写了就按照重写的规则比较。

6、HashCode的作用

java的集合有两类,一类是List,还有一类是Set。前者有序可重复,后者无序不重复。当我们在set中插入的时候怎么判断是否已经存在该元素呢,可以通过equals方法。但是如果元素太多,用这样的方法就会比较慢。
于是有人发明了哈希算法来提高集合中查找元素的效率。 这种方式将集合分成若干个存储区域,每个对象可以计算出一个哈希码,可以将哈希码分组,每组分别对应某个存储区域,根据一个对象的哈希码就可以确定该对象应该存储的那个区域。
hashCode方法可以这样理解:它返回的就是根据对象的内存地址换算出的一个值。这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。
如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

7、Java创建对象的方式

new创建新对象
通过反射机制
采用clone机制
通过序列化机制

8、反射实现的方式

1)Class.forName(“类的路径”);
2)类名.class
3)对象名.getClass()
4)基本类型的包装类,可以调用包装类的Type属性来获得该包装类的Class对象
反射优缺点:
优点:
1、能够运行时动态获取类的实例,提高灵活性;
2、与动态编译结合
缺点:
1、使用反射性能较低,需要解析字节码,将内存中的对象进行解析。
解决方案:
1、通过setAccessible(true)关闭JDK的安全检查来提升反射速度;
2、多次创建一个类的实例时,有缓存会快很多
3、ReflectASM工具类,通过字节码生成的方式加快反射速度
2、相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)

9、异常体系结构

JAVA复试面试问题 java复试一般面试什么_面试


Java可抛出(Throwable)的结构分为三种类型:被检查的异常(CheckedException)运行时异常(RuntimeException)错误(Error)

1、运行时异常
定义:RuntimeException及其子类都被称为运行时异常。
特点:Java编译器不会检查它。也就是说,当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。

常见的运行时异常:
ClassCastException (类转换异常)
IndexOutOfBoundsException (数组越界)
NullPointerException (空指针异常)

2、被检查异常
定义:Exception类本身,以及Exception的子类中除了"运行时异常"之外的其它子类都属于被检查异常。
特点 : Java编译器会检查它。 此类异常,要么通过throws进行声明抛出,要么通过try-catch进行捕获处理,否则不能通过编译。例如,CloneNotSupportedException就属于被检查异常。
常见的被检查时异常:
IOException
FileNotFoundException
SQLException

3、错误
定义 : Error类及其子类。
特点 : 和运行时异常一样,编译器也不会对错误进行检查。
当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误。程序本身无法修复些错误的。例如,VirtualMachineError就属于错误。出现这种错误会导致程序终止运行。OutOfMemoryError、ThreadDeath。
Java虚拟机规范规定JVM的内存分为了好几块,比如堆,栈,程序计数器,方法区等

异常的处理方式

异常处理方式有抛出异常和使用try catch语句块捕获异常两种方式。
(1)抛出异常:遇到异常时不进行具体的处理,直接将异常抛给调用者,让调用者自己根据情况处理。抛出异常的三种形式:throws、throw和系统自动抛出异常。其中throws作用在方法上,用于定义方法可能抛出的异常;throw作用在方法内,表示明确抛出一个异常。

(2)使用try catch捕获并处理异常:使用费try catch 捕获异常能够有针对性的处理每种可能出现的异常,并在捕获到异常后根据不同的情况做不同的处理。其使用过程比较简单:用try catch语句块将可能出现异常的代码包起来。

10、深拷贝和浅拷贝

浅拷贝:按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。(浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象。)
深拷贝:在拷贝引用类型成员变量时,为引用类型的数据成员另辟了一个独立的内存空间,实现真正内容上的拷贝。(深拷贝把要复制的对象所引用的对象都复制了一遍。)

11、final和static

final

被final修饰的类不可以被继承
被final修饰的方法不可以被重写
被final修饰的变量不可以被改变.如果修饰引用,那么表示引用不可变,引用指向的内容可变.
被final修饰的方法,JVM会尝试将其内联,以提高运行效率
被final修饰的常量,在编译阶段会存入常量池中.

static

所有的人都知道static关键字这两个基本的用法:静态变量和静态方法.也就是被static所修饰的变量/方法都属于类的静态资源,类实例所共享.除了静态变量和静态方法之外,static也用于静态块,多用于初始化操作:

区别

JAVA复试面试问题 java复试一般面试什么_Java_02

12、序列化

为什么有些java类要实现Serializable接口
为了网络进行传输或者持久化
什么是序列化
将对象的状态信息转换为可以存储或传输的形式的过程
除了实现Serializable接口还有什么序列化方式
Json序列化
FastJson序列化
ProtoBuff序列化

什么是java序列化,如何实现java序列化?或者请解释 Serializable接口的作用

我们有时候将一个java对象变成字节流的形式传出去或者从一个字节流中恢复成一个java对象,例如,要将java对象存储到硬盘或者传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个java对象变成某个格式的字节流再传输。
但是,jre本身就提供了这种支持,我们可以调用 OutputStream 的 writeObject 方法来做,如果要让java帮我们做,要被传输的对象必须实现 serializable 接口,这样,javac编译时就会进行特殊处理,编译的类才可以被 writeObject 方法操作,这就是所谓的序列化。需要被序列化的类必须实现
Serializable 接口,该接口是一个mini接口,其中没有需要实现方法,implements Serializable只是为了标注该对象是可被序列化的。
例如,在web开发中,如果对象被保存在了Session中,tomcat在重启时要把Session对象序列化到硬盘,这个对象就必须实现Serializable接口。如果对象要经过分布式系统进行网络传输,被传输的对象就必须实现Serializable接口。

13、String类和Files类的常用方法

String类

  • indexOf():返回指定字符的索引。
  • charAt():返回指定索引处的字符。
  • replace():字符串替换。
  • trim():去除字符串两端空白。
  • split():分割字符串,返回一个分割后的字符串数组。
  • getBytes():返回字符串的 byte 类型数组。
  • length():返回字符串长度。
  • toLowerCase():将字符串转成小写字母。
  • toUpperCase():将字符串转成大写字符。
  • substring():截取字符串。
  • equals():字符串比较。

Files类

  • Files. exists():检测文件路径是否存在。
  • Files. createFile():创建文件。
  • Files. createDirectory():创建文件夹。
  • Files. delete():删除一个文件或目录。
  • Files. copy():复制文件。
  • Files. move():移动文件。
  • Files. size():查看文件个数。
  • Files. read():读取文件。
  • Files. write():写入文件。

14、Java的io分为几种

按功能来分:输入流( input )、输出流( output )。
按类型来分:字节流和字符流。
字节流和字符流的区别是:字节流按 8 位传输以字节为单位输入输出数据,字符流按 16 位传输以字符为单位输入输出数据。

BIO、NIO、AIO

BIO (Blocking I/O)
同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。

NIO (New I/O)
NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。
它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

AIO (Asynchronous I/O)
AIO 它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。