Java面经

1.什么是面向对象

#概念,继承,封装,多态

 

2.继承和实现的区别  多实现的原理 

      继承:如果多个类的某个部分的功能相同,那么可以抽象出一个类出来,把他们的相同部分都放到父类里,让他们都继承这个类。

   实现:如果多个类处理的目标是一样的,但是处理的方法方式不同,那么就定义一个接口,也就是一个标准,让他们的实现这个接口,各自实现自己具体的处理方法来处理那个目标。

     联系:继承和接口都能实现代码重用,提高开发效率。提现了实物的传递性,继承关系达到复用的目的。

     区别:单继承,多实现。在接口中只能定义全局常量(static final),和无实现的方法。

 

3.java中为什么要单继承,多实现

a.若为多继承,那么当多个父类中有重复的属性或者方法时,子类的调用父类相同的方法结果会含糊不清,因此用了单继承。

b.若实现的多个接口中有重复的方法也没关系,因为实现类中必须重写接口中的方法,所以调用时还是调用的实现类中重写的方法。

c.接口中,所有属性都是 static final修饰的,即常量。即使存在一定的冲突也会在编译时提示出错。

多实现的原理:接口中的方法和属性都是public abstract的,子类必须重写方法。动态绑定。

 

4.子父类

多态的实现基础是子父类重写,重载

子父类可以有重写的方法,父类有privatedefault方法(子类访问不到)。子类可以用父类的重写、publicprotected方法。子类可以有自己独特的方法。

类修饰符级别:publicprotecteddefaultprivate

private和构造方法不能被继承,即只能通过本类的对象调用,子类对象都不行。

final方法虽然可以被继承,但不能被重写(覆盖)。

static方法可以被子类继承,但是不能被子类重写(覆盖)。

如果多继承,子类构造函数该初始化哪个父类的构造呢。同名函数的调用时哪个呢。

 

5.静态绑定与动态绑定

      绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来

      所有私有方法、静态方法、构造器及初始化方法<clinit>都是采用静态绑定机制。在编译器阶段就已经指明了调用方法在常量池中的符号引用,JVM运行的时候只需要进行一次常量池解析即可。

      动态绑定:编译器此时依然不知道对象的类型,但方法调用机制能自己去调查,找到正确的方法主体。提供一些机制,可在运行期间判断对象的类型,并分别调用适当的方法。

     如果子类改写了父类的方法,那么子类和父类的那些同名的方法共享一个方法表项。

     方法调用步骤:根据对象得到该对象对应的方法表,根据偏移量15查看有无重写(override)该方法,如果重写,则可以直接调用(Girl的方法表的speak项指向自身的方法而非父类);如果没有重写,则需要拿到按照继承关系从下往上的基类(这里是Person类)的方法表,同样按照这个偏移量15查看有无该方法。

 

6.继承和接口的区别

继承只能单继承,接口可以多实现。

继承是增强父类的方法。

接口是丰富类的方法,让类拥有更多的方法(功能)。

接口不能有字段,接口不能带对象状态

使用接口制定协议,然后用不同的实现来实现具体行为。

继承的两个类必须有父子关系,接口不必要则更灵活。

 

7.a=a+b, a+=b的区别

a=a+b 当类型不匹配的时候,编译器会通知你报错了。

a+=b 类型不一致的情况下,会自动转换,编译器不会报错。

在两个变量的数据类型一样时:a+=b 和a=a+b 是没有区别的。但是当两个变量的数据类型不同时,就需要考虑一下数据类型自动转换的问题了。

 

8. float 型 float f=3.4 是否正确

         不正确。精度不准确,应该用强制类型转换,如下所示:float f=(float)3.4 或float f = 3.4f。在java里面,没小数点的默认是int, 小数默认是 double

         int转成long系统自动转换没有问题,因为后者精度更高,但是double转成float就不能自动转换了,所以后面得加上一个f

         数一下有效数字位数(整数位+小数位),7位以内的用float,15位以内的用double 但是还有一点小小的区别:

float f =  (float) 62345678.912345;  // => 6.234568E7  共 7 位

float f2 =  (float) 12345678.912345; // => 1.2345679E7 共 8 位

(精度问题,float精度为7--8位,8位的情况是第一位是1,当是2时进位后面的精度丢失?)

 

9.i++和++i

      i++ 先赋值再计算,++i 先计算再赋值。

      五个i=++i,是i在内存自增一,然后进寄存器,最后赋值的时候i赋值就是1,第二个就是2,第五个就是5!而五个i=i++, 是赋值之后再自增1,一直i=0这个值先进寄存器,然后i在内存自增1,最后赋值的时候寄存器出来的0值会冲掉1值成为最终结果,所以无论多少个结果都会是0

 

10.Java断言

       断言概述,编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设。可以将断言看作是异常处理的一种高级形式。

断言可以有两种形式

a.assert Expression1

b.assert Expression1:Expression2

其中Expression1应该总是一个布尔值,Expression2是断言失败时输出的失败消息的字符串。

 

11.try,catch,finally中return语句

在以下4种特殊情况下,finally块不会被执行:

a、在finally语句块第一行发生了异常。 因为在其他行,finally块还是会得到执行

b、在前面的代码中用了System.exit(int)已退出程序。 exit是带参函数 ;若该语句在异常语句之后,finally会执行

c、程序所在的线程死亡。

d、关闭CPU

关于返回值:

如果try语句里有return,返回的是try语句块中变量值。 详细执行过程如下:

a、如果有返回值,就把返回值保存到局部变量中;

b、执行jsr指令跳到finally语句里执行;

c、执行完finally语句后,返回之前保存在局部变量表里的值。

d、如果try,finally语句里均有return,忽略try的return,而使用finally的return

 

12.代码块初始化加载顺序。

父类静态,子类静态,父类构造,子类构造。

 

13.String类中有哪些方法

#charAt,contains,substring,split,toCharArray, valueOf, toUpperCase.

#String replace(char oldChar, char newChar), int indexOf(String str)

boolean startsWith(String prefix)测试此字符串是否以指定的前缀开始。

 

14.全部修饰符

类:public , abstract, final, 缺省,   不能有private

方法:4个权限修饰符,static,final,synchronized,absract.

成员变量:volatile不能有abstract4个权限修饰符,static,final.

 

15.为什么少用反射

    #不能使用JIT,性能下降。

       反射的类型是动态解析的,这将导致JVM无法实施某些特定的优化(具体来说,就是我们常说的JIT优化),在性能敏感和频繁调用的方法上,应该尽量避免使用反射。

为了提高热点代码的执行效率,在运行时,虚拟机将会把这些代码编译成与本地平台相关的机器码,并进行各种层次的优化,完成这个任务的编译器称为即时编译器(Just In Time Compiler),简称 JIT 编译器。之所以不一次性全部编译,是因为有一些代码只运行一次,没必要编译,直接解释运行就可以。如果编译成机器码那岂不是和 C、C++差不多了,不能跨平台“一次编译,到处运行”。

 

16、Object类有哪些方法

#equals, hashcode, clone, toString,  getClass,  wait/notify/notifyAll

object()空参构造,Java中规定在类定义过程中,对于未定义构造函数的类,默认会有一个无参数的构造函数,子类构造会默认调用父类的空构造。

clone()得到某一个对象的克隆,Object o2 =  o1.clone()。

getClass()是一个native方法,返回的是此Object对象的类对象/运行时类对象Class<?>。效果与Object.class相同。Java中有专门定义了一个类,Class,去描述其他类所具有的特性,因此,从此角度去看,类本身也都是属于Class类的对象。为与经常意义上的对象相区分,在此称之为"类对象"。

equals()  ==与equals在Java中经常被使用,大家也都知道==与equals的区别:==表示的是变量值完成相同(对于基础类型,地址中存储的是值,引用类型则存储指向实际对象的地址);equals表示的是对象的内容完全相同,就是用的==。重写equals()方法必须重写hasCode()方法。

hascode()方法返回一个整形数值,表示该对象的哈希码值。hashCode()方法的作用,其主要用于增强哈希表的性能。不相等的两个对象,hashCode()返回的哈希码可能相同。

toString()方法返回该对象的字符串表示。例如:com.corn.objectsummary.User@27ef。

wait(...) / notify() / notifyAll()方法,这几个方法主要用于java多线程之间的协作。wait():调用此方法所在的当前线程等待,直到在其他线程上调用此方法的主调(某一对象)的notify()/notifyAll()方法。

空finalize( ),Object中定义finalize方法表明Java中每一个对象都将具有finalize这种行为。

 

17、处理Hash冲突的方法。

#开放定址法,再哈希法,拉链法,公共溢出区

开放定址法:这种方法也称再散列法,其基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi。

再哈希法:这种方法是同时构造多个不同的哈希函数。发生Hash冲突时,采用不用的Hash函数技术哈希值。

链地址法:这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表。链地址法适用于经常进行插入和删除的情况。

建立公共溢出区:这种方法的基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

 

18.内部类

      外部类调用内部类的方法,直接在外部类建立内部类的对象。

      其它类调用内部类的方法,通过外部类对象建立内部类的对象。

 

19.StringBuilder,StringBuffer

#StringBuilder线性不安全,StringBuffer线性安全

  在单线程情况下,如有大量的字符串操作情况,应该使用StringBuilder来操作字符串。不能使用String"+"来拼接而是使用,避免产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。如JSON的封装等。

    在多线程情况下,如有大量的字符串操作情况,应该使用StringBuffer。

 

21.面向对象的设计原则

#单一职责,开闭,里式替换,依赖倒置,接口隔离,迪米特

      单一职责原则——SRP

      开闭原则——OCP:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

      里式替换原则——LSP:通俗点说,只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何异常。 但是反过来就不行了,因为子类可以扩展父类没有的功能,同时子类还不能改变父类原有的功能。

     依赖倒置原则——DIP:高层模块不应该依赖底层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

     接口隔离原则——ISP:客户端不应该依赖它不需要的接口。

     迪米特原则——LOD:一个对象应该对其他对象有最少的了解。

 

22.jdk1.8下bin中内容

     其中bin目录里面存放了JDK的各种工具命令,即JDK开发工具的可执行文件。

     javac.exe      Java编译器,将Java源代码换成字节代码

     java.exe       Java解释器,直接从类文件执行Java应用程序代码

      jar: jar文件管理工具,主要用于打包压缩、解压jar文件。

      javap: Java反编译工具,主要用于根据Java字节码文件反汇编为Java源代码文件。     

     jconsole: 图形化用户界面的监测工具,主要用于监测并显示运行于Java平台上的应用程序的性能和资源占用等信息。

     jvisualvm: JVM监测、故障排除、分析工具,主要以图形化界面的方式提供运行于指定虚拟机的Java应用程序的详细信息。

     jmap: Java内存映射工具(Java Memory Map),主要用于打印指定Java进程、核心文件或远程调试服务器的共享对象内存映射或堆内存细节。

     jstack: 堆栈跟踪工具,主要用于打印指定Java进程、核心文件或远程调试服务器的Java线程的堆栈跟踪信息Java。

     jstat: JVM统计监测工具(JVM Statistics Monitoring Tool),主要用于监测并显示JVM的性能统计信息,包括gc统计信息。

    jhat: Java堆分析工具(Java Heap Analysis Tool),用于分析Java堆内存中的对象信息。

    jdb: Java调试工具(Java Debugger),主要用于对Java应用进行断点调试。

 

23.jdk1.8新特性

#lmada,接口增强,注解,日期

      Lambda表达式(也称为闭包),它允许我们将函数当成参数传递给某个方法,或者把代码本身当作数据处理。

    Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法和抽象方法之间的区别在于抽象方法需要实现,而默认方法不需要。往现存接口中添加新的(default)方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。

   重复注解,一个方法或者类有多个功能时可重复注解。

   Java 8引入了新的Date-Time API(JSR 310)来改进时间 日期的处理。

 

 

24.值传递和引用传递

       值传递:在方法被调用时,实参通过形参把它的内容副本传入方法内部,此时形参接收到的内容是实参值的一个拷贝,因此在方法内对形参的任何操作,都仅仅是对这个副本的操作,不影响原始值的内容。

      引用传递:”引用”也就是指向(直接真实内容的地址值,在方法调用时,实参的地址通过方法调用被传递给相应的形参,在方法体内,形参和实参指向同一块内存地址,对形参的操作会影响的真实内容。

      实参和形参的传递仅发生在栈帧之间。

      引用传递,在Java中并不存在。无论是基本类型和是引用类型,在实参传入形参时,都是值传递,也就是说传递的都是一个(栈帧中的)副本,而不是内容本身。

       局部变量是在栈帧中分配变量和值的。

 

 

25.深拷贝与浅拷贝

        浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享

    深拷贝:深拷贝把要复制的对象的变量和所引用的对象都复制了一遍。

26.序列化的底层怎么实现的

#字节序列持久化、远程通信,ObjectOutputStream 、FileOutputStream

      Java序列化是指把Java对象转换为字节序列的过程(以便在网络上传输或者保存在本地文件中,实现了数据的持久化,实现了数据远程通信),而Java反序列化是指把字节序列恢复为Java对象的过程。

序列化

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\object.out"));

oos.writeObject(new User("xuliugen", "123456", "male"));

反序列化

ObjectInputStream ois= new ObjectInputStream(new FileInputStream("object.out"));

User user = (User) ois.readObject();

 

27.int的范围

 -2^31   2^31-1

 

28.字节与字符的区别

#储存单位,符号

      字节(Byte):字节是通过网络传输信息(或在硬盘或内存中存储信息)的单位。1个字节等于8位二进制,它是一个8位的二进制数,是一个很具体的存储空间。

        字符:ANSI中的字符采用8bit,而UNICODE中的字符采用16bit。按照ANSI编码标准,标点符号、数字、大小写字母都占一个字节,汉字占2个字节。按照UNICODE标准所有字符都占2个字节。

 

29.基本语法判断

Integer  r = new Integer(100);

Integer  r2 = new Integer(100);

False true

 

String s = "";         建立一个新的引用,会分配内存,内存中储存空串。

String s2 = null;    建立一个空的引用,不会分配内存。

False  false

 

30. BIO NIO AIO说一下?epoll了解吗?用过吗?具体调用OS什么方法?webSocket呢?

    Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码。只需要使用Java的API就可以了。

 

同步与异步

同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。

异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。

同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。

阻塞和非阻塞

阻塞: 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。

非阻塞: 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。

举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在那里傻等着水开(同步阻塞)。等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时来看看水开了没有(同步非阻塞)。后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情,你需要去倒水了(异步非阻塞)。

 

BIO (Blocking I/O)

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

NIO 简介

NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。

AIO 是异步IO的缩写,AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

 

31.同步和阻塞的区别

       对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回,它还会抢占cpu去执行其他逻辑,也会主动检测io是否准备好。同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。

在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值