Java基础常见面试题(二)

news2025/1/9 1:33:38

面向对象基础


面向对象和面向过程的区别

面向过程

  • 优点: 性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。

  • 缺点: 没有面向对象易维护、易复用、易扩展。

面向对象

  • 优点: 易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。

  • 缺点: 性能比面向过程低。

两者的主要区别在于解决问题的方式不同:

  • 面向过程把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题。

  • 面向对象会先抽象出对象,然后用对象执行方法的方式解决问题。另外,面向对象开发的程序一般更易维护、易复用、易扩展。

面向过程也需要分配内存,计算内存偏移量,Java性能差的主要原因并不是因为它是面向对象语言,而是Java是半编译语言,最终的执行代码并不是可以直接被CPU执行的二进制机械码。而面向过程语言大多都是直接编译成机械码在电脑上执行,并且其它一些面向过程的脚本语言性能也并不一定比Java好。

创建一个对象用什么运算符?对象实体与对象引用有何不同?

new 运算符,new 创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。

一个对象引用可以指向 0 个或 1 个对象;一个对象可以有 n 个引用指向它。

对象的相等和引用相等的区别

  • 对象的相等一般比较的是内存中存放的内容是否相等。
  • 引用相等一般比较的是他们指向的内存地址是否相等。

类的构造方法的作用是什么?

构造方法是一种特殊的方法,主要作用是完成对象的初始化工作

如果一个类没有声明构造方法,该程序能正确执行吗?

如果一个类没有声明构造方法,也可以执行!因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。如果我们自己添加了类的构造方法(无论是否有参),Java 就不会再添加默认的无参数的构造方法了,我们一直在不知不觉地使用构造方法,这也是为什么我们在创建对象的时候后面要加一个括号(因为要调用无参的构造方法)。如果我们重载了有参的构造方法,记得都要把无参的构造方法也写出来(无论是否用到),因为这可以帮助我们在创建对象的时候少踩坑。

构造方法有哪些特点?是否可被 override?

构造方法特点如下:

  • 名字与类名相同。

  • 没有返回值,但不能用 void 声明构造函数。

  • 生成类的对象时自动执行,无需调用。

构造器不能被继承,因此不能被重写,但可以被重载。每一个类必须有自己的构造函数,负责构造自己这部分的构造。子类不会覆盖父类的构造函数,相反必须一开始调用父类的构造函数。

面向对象三大特征

封装

封装从字面上来理解就是包装的意思,专业点就是信息隐藏,是指利用抽象数据类型将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体,数据被保护在抽象数据类型的内部,尽可能地隐藏内部的细节,只保留一些对外接口使之与外部发生联系。系统的其他对象只能通过包裹在数据外面的已经授权的操作来与这个封装的对象进行交流和交互。也就是说用户是无需知道对象内部的细节,但可以通过该对象对外的提供的接口来访问该对象。

继承

继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。

关于继承如下 3 点请记住:

  1. 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。

  2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

  3. 子类可以用自己的方式实现父类的方法。

多态

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

所以对于多态我们可以总结如下:

指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

对于面向对象而言,多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。

如果想要详细了解这个问题,可以参考这篇文章——面向对象编程三大特性------封装、继承、多态。

Java语言是如何实现多态的?

本质上多态分两种:

  1. 编译时多态(又称静态多态)
  2. 运行时多态(又称动态多态)

重载(overload)就是编译时多态的一个例子,编译时多态在编译时就已经确定,运行的时候调用的是确定的方法。

我们通常所说的多态指的都是运行时多态,也就是编译时不确定究竟调用哪个具体方法,一直延迟到运行时才能确定。 这也是为什么有时候多态方法又被称为延迟方法的原因。

Java实现多态有三个必要条件:继承、重写、向上转型。

继承:在多态中必须存在有继承关系的子类和父类。

重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。

只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。

对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型(而不是引用变量的类型)决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

重载(Overload)和重写(Override)的区别是什么?

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。

  • 重写发生在子类与父类之间, 重写方法返回值和形参都不能改变,与方法返回值和访问修饰符无关,即重写的方法不能根据返回类型进行区分。即外壳不变,核心重写!

  • 重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。最常用的地方就是构造器的重载。

重载的方法能否根据返回值类型进行区分?

不能根据返回值类型来区分重载的方法。因为调用时不指定返回值类型信息,编译器不知道你要调用哪个函数。

float max(int a, int b);
int max(int a, int b);

接口和抽象类有什么共同点和区别?

共同点

  • 都不能被实例化。
  • 都可以包含抽象方法。
  • 都可以有默认实现的方法(Java 8 可以用 default 关键字在接口中定义默认方法)。

区别

语法层面上的区别:

  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的,不能被修改且必须有初始值;
  • 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。

设计层面上的区别:

  • 抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。

  • 设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。

  • 接口主要用于对类的行为进行约束,实现了某个接口就具有了对应的行为。抽象类主要用于代码复用,强调的是所属关系。

如果想要详细了解这个问题,可以参考这篇文章——深入理解Java的接口和抽象类。

抽象类能使用 final 修饰吗?

不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类。

java 创建对象有哪几种方式?

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

前两者都需要显式地调用构造方法。对于clone机制,需要注意浅拷贝和深拷贝的区别,对于序列化机制需要明确其实现原理,在java中序列化可以通过实现Externalizable或者Serializable来实现。

深拷贝和浅拷贝区别了解吗?什么是引用拷贝?

  • 浅拷贝: 浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。

  • 深拷贝 : 深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。

浅拷贝

浅拷贝的示例代码如下,我们这里实现了 Cloneable 接口,并重写了 clone() 方法。

clone() 方法的实现很简单,直接调用的是父类 Object 的 clone() 方法。

public class School implements Cloneable{

    private String schoolName;
    
    // 省略构造函数、Getter&Setter方法
    
    @Override
    protected Object clone() throws CloneNotSupportedException {

        try {
            return (School)super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }
}

public class Student implements Cloneable{

    private School school;

	// 省略构造函数、Getter&Setter方法
	
    @Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            Student student = (Student) super.clone();
            return student;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

}

测试 :

 Student student1 = new Student(new School("第一中学"));

 Student student2 = (Student) student1.clone();

 //true
 System.out.println(student1.getSchool() == student2.getSchool());

从输出结果就可以看出, student1 的克隆对象和 student1 使用的仍然是同一个 School 对象。

深拷贝

这里我们简单对 Student类的 clone() 方法进行修改,连带着要把 Student 对象内部的 School 对象一起复制。

@Override
    protected Object clone() throws CloneNotSupportedException {
        try {
            Student student = (Student) super.clone();
            student.setSchool((School) student.getSchool().clone());
            return student;
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

测试 :

 Student student1 = new Student(new School("第一中学"));

 Student student2 = (Student) student1.clone();

 //false
 System.out.println(student1.getSchool() == student2.getSchool());

从输出结果就可以看出,student1 的克隆对象和 student1 包含的 School 对象已经是不同的了。

那什么是引用拷贝呢?

简单来说,引用拷贝就是两个不同的引用指向同一个对象。

在这里插入图片描述

什么是不可变对象?好处是什么?

不可变对象指对象一旦被创建,状态就不能再改变,任何修改都会创建一个新的对象,如 String、Integer及其它包装类.不可变对象最大的好处是线程安全。

能否创建一个包含可变对象的不可变对象?

当然可以,比如final Person[] persons = new Persion[]{}。persons是不可变对象的引用,但其数组中的Person实例却是可变的。这种情况下需要特别谨慎,不要共享可变对象的引用。这种情况下,如果数据需要变化时,就返回原对象的一个拷贝.

值传递和引用传递的区别的什么?为什么说Java中只有值传递?

值传递(pass by value)是指在调用方法时将实参复制一份传递到方法中,这样当方法对形参进行修改时不会影响到实参。

引用传递(pass by reference)是指在调用方法时将实参的地址直接传递到方法中,那么在方法中对形参所进行的修改,将影响到实参。

值传递和引用传递的关键区别有两点:

  1. 调用方法时有没有对实参进行复制。

  2. 方法内对形参的修改会不会影响到实参。

基本类型作为参数被传递时肯定是值传递;引用类型作为参数被传递时也是值传递,只不过“值”为对应的引用。Java 的确是值传递的。只不过,引用类型在调用有参方法的时候,传递的是对象的引用,并不是对象本身。而对象的引用在传递的过程中并没有发生改变,虽然对象本身发生了变化。

如果想要详细了解这个问题,可以参考这篇文章——Java到底是值传递还是引用传递?

对象相等判断

== 和 equals 区别是什么?

==常用于相同的基本数据类型之间的比较,也可用于相同类型的对象之间的比较;

如果 == 比较的是基本数据类型,那么比较的是两个基本数据类型的值是否相等;
如果 == 是比较的两个对象,那么比较的是两个对象的引用,也就是判断两个对象是否指向了同一块内存区域;

equals方法主要用于两个对象之间,检测一个对象是否等于另一个对象;

看一看Object类中equals方法的源码:

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

它的作用也是判断两个对象是否相等,般有两种使用情况:

  • 情况1,类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。

  • 情况2,类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。

Java语言规范要求equals方法具有以下特性:

  • 自反性。对于任意不为null的引用值x,x.equals(x)一定是true。
  • 对称性)。对于任意不为null的引用值x和y,当且仅当x.equals(y)是true时,y.equals(x)也是true。
  • 传递性。对于任意不为null的引用值x、y和z,如果x.equals(y)是true,同时y.equals(z)是true,那么x.equals(z)一定是true。
  • 一致性。对于任意不为null的引用值x和y,如果用于equals比较的对象信息没有被修改的话,多次调用时x.equals(y)要么一致地返回true要么一致地返回false。
  • 对于任意不为null的引用值x,x.equals(null)返回false。

介绍下hashCode()?

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。

散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

为什么要有 hashCode?

以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:

当把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。

但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

equals方法和hashcode的关系?

  1. 如果两个对象equals相等,那么这两个对象的HashCode一定也相同;

  2. 如果两个对象的HashCode相同,不代表两个对象就相同,只能说明这两个对象在散列存储结构中,存放于同一个位置。hashCode()只表示对象的哈希码,哈希码相同的对象不一定相等,反之,没有重写equals方法的前提下,两个对象相等,则hashCode一定相同。

  3. 两个对象相等,对两个对象分别调用equals方法都返回true;

为什么重写 equals 方法必须重写 hashcode 方法 ?

判断的时候先根据hashcode进行的判断,相同的情况下再根据equals()方法进行判断。如果只重写了equals方法,而不重写hashcode的方法,会造成hashcode的值不同,而equals()方法判断出来的结果为true。

在Java中的一些容器中,不允许有两个完全相同的对象,插入的时候,如果判断相同则会进行覆盖。这时候如果只重写了equals()的方法,而不重写hashcode的方法,Object中hashcode是根据对象的存储地址转换而形成的一个哈希值。这时候就有可能因为没有重写hashcode方法,造成相同的对象散列到不同的位置而造成对象的不能覆盖的问题。

如果想要详细了解这个问题,可以参考这篇文章——HashCode详解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337795.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何做迭代规划

敏捷开发中的迭代规划如同使用需求漏斗,对各方需求定期进行优先级排序并层层拆解或合并,最终把高优先级且细粒度的需求从漏斗进入到研发团队,确保研发团队做对的事(Do Right Things),避免团队跑偏方向或进度…

Netty之EventLoopGroup详解

目录 目标 Netty版本 Netty官方API NioEventLoopGroup和DefaultEventLoop的区别 EventLoopGroup实现对内部EventLoop的轮询 EventLoop对普通任务和定时任务的实现 执行普通任务 执行定时任务 划分EventLoopGroup职责 简言 实现 指定EventLoopGroup操作ChannelHandl…

手机上怎么在线生成gif?1分钟教你手机图片合成gif

怎样通过手机实现在线制作GIF图片的操作呢?接下来,给大家分享两招gif制作(https://www.gif.cn/)小窍门-【GIF中文网】不需要下载任何软件,小白也能轻松上手。支持原画质导出,图片无损处理。一起来看看具体步…

前端教学视频分享(视频内容与市场时刻保持紧密相连,火热更新中。。。)

⚠️获取公众号 本次要想大家推荐一下本人的公众号,在微信中搜索公众号 李帅豪在对话框中输入前端视频四个字即可立即获取所有视频,不收费无广告!!! 本公众号收集了近两年来前端最新最优秀的学习视频,涵盖…

大数据技术架构(组件)30——Spark:Optimize--->Submit

2.1.9、Optimize--->Submit调优工作主要从CPU、内存、网络开销和IO四方面入手2.1.9.0、Spark On Yarn2.1.9.0.1、Jar包管理及本地性调优spark.yarn.jars :将jar包放到hdfs上,避免每次driver启动的时候都要进行jar包的分发。yarn.nodemanager.localizer.cache.cle…

ChatGPT告诉你智能制造

ChatGPT自上线以来,几乎得到了外界的一致好评,上线两个月,获得1亿月活跃用户,成为增长最快的面向消费者的应用。 面对ChatGPT拟人一般的问答能力,很多人认为它代表着AlphaGo之后,人工智能应用的第二次浪潮…

电子技术——MOS差分输入对

电子技术——MOS差分输入对 差分输入系统因其极高的共模抑制能力,差分输入几乎是是构建所有通用模拟IC的基本前级输入,也是现代信号传输理论的基础。本节我们讲解MOS差分输入对。 MOS差分输入对 下图展示了MOS差分输入对的基本原理图: 一个…

数据采集协同架构,集成马扎克、西门子、海德汉、广数、凯恩帝、三菱、海德汉、兄弟、哈斯、宝元、新代、发那科、华中各类数控以及各类PLC数据采集软件

文章目录 前言一、采集协同架构是什么?可以做什么(数控、PLC配置采集)?二、使用步骤 1.打开软件,配置MQTT或者数据库(支持sqlserver、mysql等)存储转发消息规则2.配置数控系统所采集的参数、转…

项目(今日指数)

一 项目架构1.1 今日指数技术选型【1】前端技术【2】后端技术栈【3】整体概览3.2 核心业务介绍1】业务结构预览【2】业务功能简介1.定时任务调度服务XXL-JOB通过RestTemplate多线程动态拉去股票接口数据,刷入数据库; 2.国内指数服务 3.板块指数服务 4.涨…

使用Harbor构建docker私有仓库

一、概述1、什么是HarborHarbor 是VMware公司开源的云本地 registry 仓库,有可视化的Web管理界面,可以方便的管理和储存 Docker 镜像。Harbor 支持在多个仓库直接进行复制镜像,提供用户管理和访问控制和活动审计。2、Harbor的优势基于角色控制…

mysql高级(事务、存储引擎、索引、锁、sql优化、MVCC)

文章目录1.事务1.1 四大特性ACID1.2 并发事务2.存储引擎2.1 InnoDB2.2 MyISAM2.3 Memory2.4 存储引擎特点2.5 存储引擎的选择3.性能分析3.1 查看执行频次3.2 慢查询日志3.3 profile3.4 explain4.索引4.1 索引结构B-TreeBTreeHash面试题4.2 索引分类思考题4.3 语法4.4 使用规则最…

抖音电商-安全带为例分析

为什么来抖音抖音对好货的扶持力度很大好商品对抖音商城至关

Python-项目实战--飞机大战-英雄登场(7)

目标设计英雄和子弹类使用pygame.key.get_pressed()移动英雄发射子弹1.设计英雄和子弹类1.1英雄需求游戏启动后,英雄出现在屏幕的水平中间位置,距离屏幕底部120像素英雄每隔0.5秒发射一次子弹,每次连发三枚子弹英雄默认不会移动,需…

vulnhub之CLOVER: 1

1.信息收集 输入arp-scan 192.168.239.0/24进行主机存活探测,可以看到192.168.239.171主机存活。 对192.168.239.171主机进行端口扫描,可以看到20、21、22、82、110、443、5781、8080。 发现21端口可以匿名登录,输入:anonymous…

牛客网Python篇数据分析习题(一)

1.现有一个Nowcoder.csv文件,它记录了牛客网的部分用户数据,包含如下字段(字段与字段之间以逗号间隔): Nowcoder_ID:用户ID Level:等级 Achievement_value:成就值 Num_of_exercise&a…

春招快来了,杭电研究生学长聊聊踩过的坑,助你成功上岸

引言 大家好,我是James,由于之前文章内容浏览量太少以及这几个月的繁忙,一直没有静下心输出一些内容,随着疫情放开,新春来临,年后百业待兴,马上又是一年春季招聘。作为一个参加过2022年春&…

golang 通道类型

文章目录一、什么是通道类型二、通道产生的原因三、声明channel四、创建channel五、channel相关操作1、发送值2、接收值3、关闭通道3.1 注意3.2 特点四、通道类型1、无缓冲通道2、有缓冲通道五、单向通道一、什么是通道类型 Go 语言中的通道(channel)是一…

【ChatGpt】使用感受分享

作者:狮子也疯狂 专栏:《基础知识查漏》 坚持做好每一步,幸运之神自然会降临在你的身上 目录一. 🦁 前言二. 🦁 使用详情Ⅰ. 🐇 使用过程Ⅱ. 🐇 使用感受Ⅲ. 🐇 遇到的问题3.1 我遇…

Allegro172版本如何用自带的功能实现快速在1MMBGA下方等距放置电容

Allegro172版本如何用自带的功能实现快速在1MMBGA下方等距放置电容 在做PCB设计的时候,在1MM中心间距的BGA背面放置电容,是非常常见的设计,如何快速把电容等距放在BGA下方,除了借助辅助工具外,在Allegro升级到了172版本的时候,可以借助本身自带的功能实现快速放置,以下图…

【云原生】解读Kubernetes三层网络方案

在上一篇文章中,我以网桥类型的 Flannel 插件为例,为你讲解了 Kubernetes 里容器网络和 CNI 插件的主要工作原理。不过,除了这种模式之外,还有一种纯三层(Pure Layer 3)网络方案非常值得你注意。其中的典型…