Java常见面试题(三)

目录

1、Java 和 C++的区别?

2、什么是 Java 程序的主类?应用程序和小程序的主类有何不同?

3、import java 和 javax 有什么区别?

4、为什么说 Java 语言“编译与解释并存”?

5、标识符和关键字的区别是什么?

6、为什么 Java 中只有值传递?

7、深拷贝 vs 浅拷贝?

8、构造器 Constructor 是否可被 override?

9、在 Java 中定义一个不做事且没有参数的构造方法的作用?

10、Object 类的常见方法?

11、Java 序列化中如果有些字段不想进行序列化,怎么办?

12、try - catch - finally的作用?

13、乐观锁与悲观锁是什么?

14、计算机网络的五层体系结构?

15、操作系统为什么要有用户态与内核态?

16、Linux的目录结构?

17、Java的四种引用,强弱软虚?

18、Java创建对象有几种方式?

19、概述对 synchronized 关键字的了解?

20、什么是线程安全?

21、构造方法能不能显式调用?

22、String类的常用方法有那些?

23、普通类与抽象类有什么区别?

24、接口有什么特点?


1、Java 和 C++的区别?

  • 两者都是面向对象的语言,都支持封装、继承和多态
  • Java 不提供指针来直接访问内存,程序内存更加安全
  • Java 的类是单继承的,C++ 支持多重继承;虽然 Java的类不可以多继承,但是接口可以多继承
  • Java 有自动内存管理机制,不需要程序员手动释放无用内存
  • 在 C 语言中,字符串或字符数组最后都会有一个额外的字符‘\0’来表示结束。Java 语言中没有结束符

2、什么是 Java 程序的主类?应用程序和小程序的主类有何不同?

一个程序中可以有多个类,但只能有一个类是主类。在 Java 应用程序中,这个主类是指包含 main() 方法的类。而在 Java 小程序中,这个主类是一个继承自系统类 JApplet 或 Applet 的子类

应用程序的主类不一定要求是 public 类,但小程序的主类要求必须是 public 类。主类是 Java 程序执行的入口点

3、import java 和 javax 有什么区别?

JavaAPI 所必需的包是 java 开头的包,javax 只是扩展 API 包来使用,实际上 java 和 javax 没有区别

4、为什么说 Java 语言“编译与解释并存”?

高级编程语言按照程序的执行方式分为编译型和解释型两种。

编译型语言是指编译器针对特定的操作系统将源代码一次性翻译成可被该平台执行的机器码;解释型语言是指解释器对源程序逐行解释成特定平台的机器码并立即执行。Java 语言既具有编译型语言的特征,也具有解释型语言的特征,因为 Java 程序要经过先编译,后解释两个步骤,由 Java 编写的程序需要先经过编译步骤,生成字节码(*.class 文件),这种字节码必须由 Java 解释器来解释执行

5、标识符和关键字的区别是什么?

编写程序的时候,需要大量地为程序、类、变量、方法等取名字,于是就有了标识符,标识符就是一个名字。有一些标识符,Java 语言已经赋予了其特殊的含义,只能用于特定的地 方,这种特殊的标识符就是关键字

6、为什么 Java 中只有值传递?

按值调用表示方法接收的是调用者提供的值,而按引用调用表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值

总结:

  • Java 程序设计语言对对象采用的不是引用调用,对象引用是按值传递的
  • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)
  • 一个方法可以改变一个对象参数的状态
  • 一个方法不能让对象参数引用一个新的对象

7、深拷贝 vs 浅拷贝?

  • 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递的拷贝
  • 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容

8、构造器 Constructor 是否可被 override?

Constructor 不能被 override (重写),但是可以 overload (重载),可以看到一个类中有多个构造函数的情况

9、在 Java 中定义一个不做事且没有参数的构造方法的作用?

Java 程序在执行子类的构造方法之前,如果没有用 super() 来调用父类特定的构造方法,则会调用父类中 “没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 super() 来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行

10、Object 类的常见方法?

public final native Class<?> getClass() //native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写

public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap

public boolean equals(Object obj) //用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等

protected native Object clone() throws CloneNotSupportedException
/* naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass()为true。
Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常 */

public String toString() //返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法

public final native void notify() //native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个

public final native void notifyAll() //native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程

public final native void wait(long timeout) throws InterruptedException //native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间

public final void wait(long timeout, int nanos) throws InterruptedException //多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)所以超时的时间还需要加上nanos毫秒

public final void wait() throws InterruptedException //跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念

protected void finalize() throws Throwable { } //实例被垃圾回收器回收的时候触发的操作

11、Java 序列化中如果有些字段不想进行序列化,怎么办?

对于不想进行序列化的变量,使用 transient 关键字修饰

transient 关键字的作用:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方法

12、try - catch - finally的作用?

try 块:用于捕获异常。其后可接零个或多个 catch 块,如果没有 catch 块,则必须跟一个 finally 块

catch 块:用于处理 try 捕获到的异常

finally 块:无论是否捕获或处理异常,finally 块里的语句都会被执行。当在 try 块或 catch 块中 遇到 return 语句时,finally 语句块将在方法返回之前被执行

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

  1. 在 finally 语句块第一行发生了异常。 因为在其他行,finally 块还是会得到执行
  2. 在前面的代码中用了 System.exit(int)已退出程序,exit 是带参函数;若该语句在异常语句之后,finally 会执行
  3. 程序所在的线程死亡
  4. 关闭 CPU

注意:当 try语句和 finally语句中都有 return语句时,在方法返回之前,finally语句的内容将被执行,并且 finally语句的返回值将会覆盖原始的返回值

13、乐观锁与悲观锁是什么?

乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量。版本号机制:一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功

悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁 (共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程),使用 synchronized实现

乐观锁适用于写比较少的情况下 (多读场景),即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以一般多写的场景下用悲观锁就比较合适

14、计算机网络的五层体系结构?

物理层的任务:透明地传送比特流。也可以将物理层的主要任务描述为确定与传输媒体的接口的一些特性,即:机械特性 (接口所用接线器的一些物理属性如形状尺寸),电气特性 (接口电缆的各条线上出现的电压的范围),功能特性 (某条线上出现的某一电平的电压的意义),过程特性 (对于不同功能能的各种可能事件的出现顺序)

数据链路层:

  • 数据链路层使用的主要是点对点信道和广播信道两种。点对点协议PPP是数据链路层使用最多的一种协议,它的特点是:简单,只检测差错而不去纠正差错,不使用序号,也不进行流量控制,可同时支持多种网络层协议
  • 数据链路层传输的协议数据单元是帧,数据链路层的三个基本问题是:封装成帧、透明传输、差错检测
  • MAC地址 (Media Access Control或者Medium Access Control):意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。在OSI模型中,第三层网络层负责 IP地址,第二层数据链路层则负责 MAC地址。因此一个主机会有一个MAC地址,而每个网络位置会有一个专属于它的IP地址 。地址是识别某个系统的重要标识符,“名字指出我们所要寻找的资源,地址指出资源所在的地方,路由告诉我们如何到达该处”
  • 计算机与外接局域网通信需要通过通信适配器 (或网络适配器),它又称为网络接口卡或网卡,计算器的硬件地址就在适配器的ROM中;以太网的适配器具有过滤功能,它只接收单播帧,广播帧和多播帧;使用集线器可以在物理层扩展以太网 (扩展后的以太网仍然是一个网络)

网络层:TCP/IP协议中的网络层向上只提供简单灵活的,无连接的,尽最大努力交付的数据报服务。网络层不提供服务质量的承诺,不保证分组交付的时限所传送的分组可能出错,丢失,重复和失序。进程之间通信的可靠性由运输层负责

运输层:运输层提供应用进程之间的逻辑通信,也就是说,运输层之间的通信并不是真正在两个运输层之间直接传输数据。运输层向应用层屏蔽了下面网络的细节 (如网络拓补,所采用的路由选择协议等),它使应用进程之间看起来好像两个运输层实体之间有一条端到端的逻辑通信信道

应用层:万维网客户程序与服务器之间进行交互使用的协议是超文本传输协议HTTP,HTTP使用TCP连接进行可靠传输。但HTTP本身是无连接、无状态的。HTTP/1.1协议使用了持续连接 (分为非流水线方式和流水线方式)

15、操作系统为什么要有用户态与内核态?

  • 内核态(核心态、特权态):内核态是操作系统内核运行的模式。内核态控制计算机的硬件资源,如硬件设备,文件系统等等,并为上层应用程序提供执行环境
  • 用户态:用户态是用户应用程序运行的状态。应用程序必须依托于内核态运行,因此用户态的态的操作权限比内核态是要低的, 如磁盘,文件等,访问操作都是受限的

在cpu的所有指令中,有些指令是非常危险的,如果使用不当,将会造成系统崩溃等后果。为了避免这种情况发生,cpu将指令划分为特权级(内核态)指令和非特权级(用户态)指令。对于那些危险的指令只允许内核及其相关模块调用,对于那些不会造成危险的指令,就允许用户应用程序调用

16、Linux的目录结构?

17、Java的四种引用,强弱软虚?

强引用:平常中使用最多的引用,强引用在程序内存不足 (OOM)的时候也不会被回收,使用方式:

String str = new String("str");

软引用:在程序内存不足时,会被回收,使用方式:

// 注意:wrf这个引用也是强引用,它是指向SoftReference这个对象的
// 这里的软引用指的是指向new String("str")的引用,也就是SoftReference类中T
SoftReference<String> wrf = new SoftReference<String>(new String("str"));

// 可用场景:创建缓存的时候,创建的对象放进缓存中,当内存不足时,JVM就会回收早先创建的对象

弱引用:只要JVM垃圾回收器发现了它,就会将之回收,使用方式:

WeakReference<String> wrf = new WeakReference<String>(str);

// 可用场景:Java源码中的 java.util.WeakHashMap 中的 key 就是使用弱引用
// 一旦我不需要某个引用,JVM会自动帮我处理它,这样我就不需要做其它操作

虚引用:回收机制跟弱引用差不多,但是它被回收之前,会被放入 ReferenceQueue 中。注意,其它引用是被JVM回收后才被传入 ReferenceQueue 中的。由于这个机制,所以虚引用大多被用于引用销毁前的处理工作。还有就是,虚引用创建的时候,必须带有 ReferenceQueue ,使用例子:

PhantomReference<String> prf = new PhantomReference<String>(new
String("str"), new ReferenceQueue<>());

// 可用场景:对象销毁前的一些操作,比如说资源释放等

18、Java创建对象有几种方式?

1. new创建新对象:User user = new User();

2. 通过反射机制,调用 java.lang.Class 或者 java.lang.reflect.Constructor类的 newInstance()实例方法

Class c = Class.forName(subClassName);

(1)java.lang.Class.newInstance()

User user = (User)c.newInstance(); //不带参数

(2)java.lang.reflect.Constructor类的newInstance()

Constructor con = c.getConstructor(String.class);

User user = (User) con.newInstance("name");

3. 采用clone机制 (浅拷贝)

User user1 = new User();
User user2 = null;

user2 = (User) user1.clone();

4. 通过序列化机制

// 序列化:将对象状态转化为可保持或传输的格式的过程,被序列化的对象必须implments Serializable
// 反序列化:将流转化成对象的过程

public class Test {
    //序列化对象到文件
    public static void serialize(String fileName) {
        try {
            //创建一个对象输出流,讲对象输出到文件   
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
            
            User user = new User();
            out.writeObject(user);  //序列化一个对象   

            out.close();
        } catch (Exception x) {
            System.out.println(x.toString());
        }
    }

    //从文件反序列化到对象   
    public static void deserialize(String fileName) {
        try {
            //创建一个对象输入流,从文件读取对象   
            ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));

            //读取UserInfo对象并调用它的toString()方法   
            User user = (User) (in.readObject());
            System.out.println(user.toString());

            in.close();
        } catch (Exception x) {
            System.out.println(x.toString());
        }
    }

    public static void main(String[] args) {
        
        serialize("D:\\test.txt");
        System.out.println("序列化完毕");

        deserialize("D:\\test.txt");
        System.out.println("反序列化完毕");
    }
}

19、概述对 synchronized 关键字的了解?

可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码。当两个并发线程访问同一个对象 object的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问object的一个加锁代码块时,另一个线程仍可以访问该object中的非加锁代码块

20、什么是线程安全?

代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的

21、构造方法能不能显式调用?

不行,构造器只能在创建时自动调用,构造函数名字必须与类名相同

22、String类的常用方法有那些?

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

23、普通类与抽象类有什么区别?

  1. 普通类不能包含抽象方法,抽象类可以包含抽象方法
  2. 抽象类不能直接实例化,普通类可以直接实例化

24、接口有什么特点?

  • 接口中声明全是public static final修饰的常量
  • 接口中所有方法都是抽象方法
  • 接口是没有构造方法的
  • 接口也不能直接实例化
  • 接口可以多继承


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

South.return

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值