【面试】javase

java基础

1.equals 与 == 区别

  • == 是java的一个关系运算符,是来检查两边的值是否相等。

    • 如果两边是基本类型,则比较的是值是否相等
    • 如果两边是引用对象,则比较该引用的地址值是否相等
    public boolean equals(Object obj) {
            return (this == obj);
        }
    
  • equals 是java Object类中的一个方法,

    • 如果我们没有重写 这个方法,底层还是比较这两个引用的地址值,通过这个来判断两个对象通常是没有意义的。
    • 所以我们自己的类应该按照自己的逻辑判断两个对象是否相等,去重写equals,比如String的equals方法就是逐会比较字符。

2. final, finally, finalize 的区别

  • final是java的一个修饰符,可以修饰方法、变量、类等。被他修饰的方法不可以被重写;变量只可以被赋值一次就不可以改变;被他修饰的类是不可变类,不能被继承

  • finally是java的一个关键字,是异常处理的一部分,一般就try-catch-finally ,finally代码块中的语句是一定会被执行的。我们常常会在里面进行一些连接的关闭,确保资源的利用。

  • finalize 是Object 类中的一个方法,他是以protected修饰的一个空方法,也就是说要我们重写其中的逻辑。这里主要是关于垃圾回收的一些逻辑,当对象没有GC-Root引用时,就会去看看有没有必要执行finalize(), 如果finalize()被调用过 或者 子类没有覆盖 这个类,则就不会执行这个方法。

    我们可以重写该方法让Gc-root能链到该对象从而达到对象的自救。所以这个方法我们程序员一般不主动调用。都由jvm来掌控。jdk9已经废弃了这个方法

3.重载和重写的区别

  • 重载是一个方法的参数个数不同或者参数类型不同
  • 重写是子类修改父类方法的逻辑,通过子类实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这是面向对象编程的多态性的一种表现。

区别

  • 重写是需要继承,重载不用

  • 重写的方法的访问权限必要大于等于父类方法,子类返回值类型应比父类返回值类型小或相等,只能比父类抛异常抛得更小或相等,不能坑爹hh

  • 重载和返回值类型、权限修饰符没有任何关系,之和参数有关。

4. 两个对象的hashCode()相同,则 equals()是否也一定为 true?

  • 两个对象的equals()相等,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

  • 两个对象的equals()不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求一定生成不同的整数结果。但是,为不相等的对象生成不同整数结果可以提高哈希表的性能。

5.接口和抽象类区别

抽象类是从多个类抽象出来的,如果将这个类抽象得更具体,就可以提炼出更特殊得抽象类"接口",也就是接口抽象级别更高

  • 接口中没有构造器,抽象类中有构造器,但是并不是来实例对象的,而是拿来子类调用的。

  • 抽象类之中的方法都是抽象方法,都以隐式或显示public abstract修饰; 抽象类可以没有抽象方法

  • 抽象类中可以有普通成员变量,接口中变量只能是静态常量

  • 接口可以多继承,抽象类只能单继承。

6.BIO、NIO、AIO 有什么区别?

这几种都是java的IO模式,分别是同步非阻塞IO、异步非阻塞IO。

这三个的区别

  • BIO是线程发起IO请求后,不管有没有IO操作,一个连接一个线程,从发起请求后线程就一直阻塞住,直到操作结束,如果这个连接不做事情就会导致资源的浪费。
  • BIO是线程发起IO请求后,一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。用户进程也需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问。
  • AIO:线程发起 IO 请求,立即返回;内存做好 IO 操作的准备之后,做 IO 操作,直到操作完成或者失败,通过调用注册的回调函数通知线程做 IO 操作完成或者失败。

BIO 是一个连接一个线程。,NIO 是一个请求一个线程。,AIO 是一个有效请求一个线程。

7.String,Stringbuffer,StringBuilder的区别

String

  • String是一个用finall修饰不可变类,一旦被创建就不可以被修改。

  • jdk1.8及以前String底层使用是char[],1.9开始使用byte[]。

    首先byte是单字节,char是双字节。官方发现,绝大数的字符串都是英文和标点符号,所以只需要一个字节就可以存储(可使用Latin-1编码方案),如果使用char,所有的字符进来都是占双字节比较占用空间。

    新版String会大幅降低内存占用,内存占用减少引发另一个好处:减少GC次数(这里也会提升效率)。某些情况会效率有所下降。总体来说优点远大于缺点。

  • String的每一次的改变都会使在常量池创建新的对象,而不是在原有的基础上去修改,所以如果有.频繁的字符串修改操作,用String不是一个好的选择。

  • 当用String类拼接字符串时, 每次都会生成一个StringBuilder对象, 然后调用两次append()方法把字

    符串拼接好, 最后通过StringBuilder的toString()方法new出一个新的字符串对象。

Stringbuffer,StringBuilder

  • 和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象
  • StringBuffer 是线程安全的,StringBuilder 是线程不安全的,所以效率要比StringBuffer 低一点。

8.java有几种基本类型,分别占用空间大小

八大基本数据类型byte,short,int,long,float,double,boolean,char。分别对应 ==1 2 4 8 4 8 8 2== 字节

整形 : byte short int long;

浮点型 : float double

字符型 :char

布尔型 :boolean

9.Comparator 和Comparable区别

Comparable

  • 而Comparable位于包 java.lang下。
  • jdk源码是这样描述Comparable的

该接口对实现它的每个类的对象强加了总排序。 这种排序称为类的自然排序,类的compareTo方法称为其自然比较方法。

  • Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口) 自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序, 这里的自然顺序就是实现Comparable接口设定的排序方式。

Comparator

  • Comparator位于包java.util下
  • Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
  • jdk中的描述

一个比较函数,它对某些对象集合进行总排序。 比较器可以传递给排序方法(例如Collections.sort或Arrays.sort )以允许精确控制排序顺序。 比较器还可用于控制某些数据结构(例如sorted sets或sorted maps )的顺序,或为没有natural ordering的对象集合提供natural ordering 。

10. String类能被继承吗,为什么。

不能,他是以final修饰的类,是不可以被继承 的。

为什么要这么设计?

  • 效率性,String 类作为最常用的类之一,禁止被继承和重写,可以提高效率。
  • 安全性,String 类中有很多调用底层的本地方法,调用了操作系统的 API,如果方法可以重写,可能被植入恶意代码,破坏程序。

11. 说说Java中多态的实现原理==*==

12. Java泛型和类型擦除==*==

类型擦除

Class c1 = new ArrayList<Integer>().getClass();
Class c2 = new ArrayList<String>().getClass();
System.out.println(c1 == c2);//true

ArrayList <Integer>ArrayList <String> 很容易被认为是不同的类型。但是这里输出结果是true,这是因为Java泛型是使用擦除实现的,不管是ArrayList<Integer>() 还是new ArrayList<String>(),在编译生成的字节码中都不包含泛型中的类型参数,即都擦除成了ArrayList,也就是被擦除成“原生类型”,这就是泛型擦除。

泛型解析

13. int和Integer 有什么区别,还有Integer缓存的实现

  • int 是一个基本数据类型,Integer是int 的包装类

  • int 默认为0,Integer是一个引用类型,默认是null

  • Integer的缓存机制: Integer是对小数据(-128127)是有缓存的,再jvm初始化的时候,数据-128127之间的数字便被缓存到了本地内存中,如果初始化-128~127之间的数字,会直接从内存中取出,不需要新建一个对象.

14. 说说反射的用途及实现原理,Java获取反射的三种方法==*==

15. 面向对象的特征

面向对象的三大特征:

  • 封装
  • 继承
  • 多态

16. &和&&的区别

  • 按位与, a&b 表示把a和b都转换成二进制数,再进行与的运算;
  • &和&&都是逻辑运算符号,&&又叫短路运算符
  • 逻辑与,a&& b ,a&b 都表示当且仅当两个操作数均为 true时,其结果才为 true,否则为false。
  • 逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true,整个表达式的值才是true。但是,&&之所以称为短路运算,是因为如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。

17. Java中IO流分为几种?

  • Java中的流分为两种:一种是字节流,另一种是字符流。
  • IO流分别由四个抽象类来表示(两输入两输出):InputStream,OutputStream,Reader,Writer。

18. 讲讲类的实例化顺序,比如父类静态数据,构造函数,子类静态数据,构造函数。

  • 父类的静态块
  • 子类的静态块
  • 父类的非静态块
  • 父类的构造器
  • 子类的非静态块
  • 子类的构造器

19. Java创建对象有几种方式

  1. new
  2. 使用反射,使用Class.forName("").newInstance()创建对象。
  3. 调用对象的clone()方法。
  4. 运用反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法.
  5. unsafe?

20. 守护线程是什么?用什么方法实现守护线程

在Java中有两类线程:User Thread(用户线程)、Daemon Thread(守护线程)

  • 守护线程是运行在后台的一种特殊线程
  • 它会周期性的执行某种任务,或等待某些任务的发生并采取相应的措施
  • java中的垃圾回收就是特殊的守护线程。

21.notify()和 notifyAll()有什么区别?

  • notify是唤醒一个处于该对象wait的线程,而notifyAll是唤醒所有处于该对象wait的线程。
  • 但是唤醒不等于就能执行了,需要得到锁对象才能有权利继续执行,而锁只有一把,所以多个线程被唤醒时需要争取该锁。

22.notify()和 notifyAll()有什么区别?

  • notify是唤醒一个处于该对象wait的线程,而notifyAll是唤醒所有处于该对象wait的线程。
  • 但是唤醒不等于就能执行了,需要得到锁对象才能有权利继续执行,而锁只有一把,所以多个线程被唤醒时需要争取该锁。

23.深拷贝和浅拷贝区别

浅拷贝

复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化。

深拷贝

将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变。

有两种方式实现深拷贝

  1. 实现Cloneable接口,并且重写Object类中的clone()方法,若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝。
  2. 实现Serializable接口序列化

24.JDK 和 JRE 有什么区别?

  • JDK java开发工具包,包含了jre,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具

  • JRE java运行时环境,包含了java虚拟机,java基础类库。是使用java语言编写的程序运行所需要的软件环境,是提供给想运行java程序的用户使用的。

25.什么是值传递和引用传递?

  • java中,如果传递的是基本数据类型,都行值传递,每一个传递值过去的都相当于一个副本,改变该副本不会对原来的值产生影响
  • 如果传递的是引用型变量来说,传递的就是该引用对象地址的一个副本,对引用对象进行修改会导致原对象的改变。

26.Java支持多继承么,为什么?

不可以。

​ 多继承带来很多复杂性,容易在各种操作过程中产生问题,比如强制类型转换、构造函数链接等,而最重要的原因是,实际上需要多继承的场景非常少,所以为了保持事情的简单和直观,干脆不支持多继承。

27.构造器是否可被重写?

不可以

​ 构造器是不能被继承的,因为每个类的类名都不相同,而构造器名称与类名相同,所以根本谈不上继承。 又由于构造器不能继承,所以就不能被重写。但是,在同一个类中,构造器是可以被重载的。

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

​ 在Java中,char类型占2个字节,而且Java默认采用Unicode编码,一个Unicode码是16位,所以一个Unicode码占两个字节,Java中无论汉子还是英文字母都是用Unicode编码来表示的。所以,在Java中,char类型变量可以存储一个中文汉字。

29. object中定义了哪些方法?

  • getClass(); 获取类结构信息
  • hashCode() 获取哈希码
  • equals(Object) 默认比较对象的地址值是否相等,子类可以重写比较规则
  • clone() 用于对象克隆
  • toString() 把对象转变成字符串
  • notify() 多线程中唤醒功能
  • notifyAll() 多线程中唤醒所有等待线程的功能
  • wait() 让持有对象锁的线程进入等待
  • wait(long timeout) 让持有对象锁的线程进入等待,设置超时毫秒数时间
  • wait(long timeout, int nanos) 让持有对象锁的线程进入等待,设置超时纳秒数时间
  • finalize() 垃圾回收前执行的方法

30.hashCode的作用是什么?

hashCode的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode是用来在散列存储结构中确定对象的存储地址的;

31. 简述一下面向对象的”六原则一法则”。

  • 单一职责原则:一个类只做它该做的事情。
  • 开闭原则:软件实体应当对扩展开放,对修改关闭。
  • 依赖倒转原则:面向接口编程。
  • 接口隔离原则:接口要小而专,绝不能大而全。
  • 合成聚合复用原则:优先使用聚合或合成关系复用代码。
  • 迪米特法则:迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。

32. java中的Math.round(-1.5) 等于多少呢?

JDK 中的 java.lang.Math 类:

  • round() :返回四舍五入,负 .5 小数返回较大整数,如 -1.5 返回 -1。四舍五入:+0.5下取整
  • ceil() :返回小数所在两整数间的较大值,如 -1.5 返回 -1.0。
  • floor() :返回小数所在两整数间的较小值,如 -1.5 返回 -2.0。

33. 如何将字符串反转呢?

  • 使用 StringBuilder 或 StringBuffer 的 reverse 方法,本质都调用了它们的父类 AbstractStringBuilder 的 reverse 方法实现。(JDK1.8)
  • 使用chatAt函数,倒过来输出;

34. 描述动态代理的几种实现方式,它们分别有什么优缺点

  • JDK动态代理

  • CGLIB动态代理

  • JDK原声动态代理时java原声支持的、不需要任何外部依赖、但是它只能基于接口进行代理

  • CGLIB通过继承的方式进行代理、无论目标对象没有没实现接口都可以代理,但是无法处理final的情况

35. 匿名内部类是什么?如何访问在其外面定义的变量呢?

匿名内部类还有以下特点:

  • 没有名字
  • 匿名内部类必须继承一个抽象类或者实现一个接口。
  • 匿名内部类不能定义任何静态成员和静态方法。
  • 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
  • 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
  • 匿名内部类不能访问外部类方法中的局部变量,除非该变量被声明为final类型

36.64位jvm int长度是多少

32 位和 64 位的 JVM 中,int 类型变量的长度是相同的,都是 32 位或者 4 个字节(一个字节8位)

37.java中,为何方法wait(),notify() 和 notifyAll() 是在 Object 类中定义的,而非在 Thread 类中定义?

因为synchronized中的这把锁可以是任意对象,所以任意对象都可以调用wait()和notify();所以wait和notify属于Object。

​ 专业说:因为这些方法在操作同步线程时,都必须要标识它们操作线程的锁,只有同一个锁上的被等待线程,可以被同一个锁上的notify唤醒,不可以对不同锁中的线程进行唤醒。

​ 也就是说,等待和唤醒必须是同一个锁。而锁可以是任意对象,所以可以被任意对象调用的方法是定义在object类中。

38.为什么 char 数组比 String 更适合存储密码?

​ 由于字符串在 Java 中是不可变的,如果你将密码存储为纯文本,它将在内存中可用,直到垃圾收集器清除它,并且为了可重用性,会存在 String在字符串池中, 它很可能会保留在内存中持续很长时间,从而构成安全威胁。

​ 由于任何有权访问内存转储的人都可以以明文形式找到密码,这是另一个原因,你应该始终使用加密密码而不是纯文本。

​ 由于字符串是不可变的,所以不能更改字符串的内容,因为任何更改都会产生新的字符串,而如果你使用char[],你就可以将所有元素设置为空白或零。

因此,在字符数组中存储密码可以明显降低窃取密码的安全风险。

39.什么是serialVersionUID?如果你不定义这个,会发生什么?

​ serialVersionUID是一个private static final long型ID,当它被印在对象上时,它通常是对象的哈希码,你可以使用serialver这个JDK工具来查看序列化对象的serialVersionUID。SerialVerionUID用于对象的版本控制。也可以在类文件中指定serialVersionUID。不指定serialVersionUID的后果是,当你添加或修改类中的任何字段时,则已序列化类将无法恢复,因为为新类和旧序列化对象生成的serialVersionUID将有所不同。Java序列化过程依赖于正确的序列化对象恢复状态,并在序列化对象序列版本不匹配的情况下引发java.io.InvalidClassException无效类异常。

40.如果类中的一个成员未实现可序列化接口,会发生什么情况?

​ 如果尝试序列化实现可序列化的类的对象,但该对象包含对不可序列化类的引用,则在运行时将引发不可序列化异常NotSerializableException,在可序列化类中添加新字段时要注意。

41.simpledateformat线程为什么不安全

在多线程环境下,当多个线程同时使用相同的SimpleDateFormat对象(如static修饰)的话,如调用format方法时,多个线程会同时调用calender.setTime方法,导致time被别的线程修改,因此线程是不安全的。

解决方案:

  • 将SimpleDateFormat定义成局部变量

  • 加一把线程同步锁:synchronized(lock)

  • 使用ThreadLocal,每个线程都拥有自己的SimpleDateFormat对象副本。

42.java枚举类是否可以继承

​ 枚举类使用enum定义后在编译后默认继承了java.lang.Enum类,而不是普通的继承Object类。enum声明类继承了Serializable和Comparable两个接口。且采用enum声明后,该类会被编译器加上final声明(同String),故该类是无法继承的。

全部评论

相关推荐

ArisRobert:统一解释一下,第4点的意思是,公司按需通知员工,没被通知到的员工是没法去上班的,所以只要没被通知到,就自动离职。就是一种比较抽象的裁员。
点赞 评论 收藏
分享
霁华Tel:秋招结束了,好累。我自编了一篇对话,语言别人看不懂,我觉得有某种力量在控制我的身体,我明明觉得有些东西就在眼前,但身边的人却说啥也没有,有神秘人通过电视,手机等在暗暗的给我发信号,我有时候会突然觉得身体的某一部分不属于我了。面对不同的人或场合,我表现出不一样的自己,以至于都不知道自己到底是什么样子的人。我觉得我已经做的很好,不需要其他人的建议和批评,我有些时候难以控制的兴奋,但是呼吸都让人开心。
点赞 评论 收藏
分享
评论
1
收藏
分享
牛客网
牛客企业服务