Java笔试面试题AI答之面向对象(8)

news2024/11/15 17:47:00

文章目录

  • 43. 解释Java接口隔离原则和单一原则如何理解 ?
      • 单一职责原则(Single Responsibility Principle, SRP)
      • 接口隔离原则(Interface Segregation Principle, ISP)
  • 44. Java 有没有 goto? 如果有,一般用在什么地方?如果没有,如何跳出当前的多重嵌套循环?
      • 跳出当前的多重嵌套循环
  • 45. 简述Java 创建对象的方式有哪些?
  • 46. 简述Java 浅拷贝和深拷贝 ?
      • 浅拷贝(Shallow Copy)
      • 深拷贝(Deep Copy)
      • 总结
  • 47. Java简述super()与this()的区别?
      • super()
      • this()
      • 总结
  • 48. Java Final类有什么特点?

43. 解释Java接口隔离原则和单一原则如何理解 ?

在Java中,接口隔离原则和单一职责原则是面向对象设计中的重要原则,它们有助于构建更加灵活、可维护和可扩展的软件系统。下面分别解释这两个原则:

单一职责原则(Single Responsibility Principle, SRP)

单一职责原则是指一个类应该仅有一个引起它变化的原因。换句话说,一个类应该负责一组相对独立且紧密相关的职责,并且当这个类需要变动时,应该只有一项职责的变动会导致类的变动。

这个原则强调类的职责应该尽量单一,以便于理解和维护。如果一个类承担了过多的职责,那么当其中一个职责发生变更时,可能会影响到其他的职责,从而增加维护的复杂性和风险。

例如,考虑一个Employee类,如果它同时负责员工信息的存储、员工薪资的计算以及员工考勤的管理,那么这个类就违反了单一职责原则。更好的做法是将这些职责分别划分到EmployeeInfoSalaryCalculatorAttendanceManager等不同的类中。

接口隔离原则(Interface Segregation Principle, ISP)

接口隔离原则指的是使用多个专门的接口,比使用单一的总接口(胖接口)要好。换句话说,一个类不应该被迫依赖于它不使用的方法。客户端不应该被迫依赖于它不使用的接口方法。

这个原则强调接口的职责应该尽量单一,只包含客户端需要的方法,从而减少接口之间的耦合。如果一个接口包含了多个职责,那么当其中一个职责发生变更时,可能会影响到依赖于该接口的多个类,从而增加维护的复杂性和风险。

例如,考虑一个Animal接口,它包含了fly()walk()swim()等方法。但是,并不是所有的动物都能飞行或游泳。如果有一个Dog类实现了这个Animal接口,那么它就必须实现fly()swim()方法,即使这些方法对于狗来说是没有意义的。这明显违反了接口隔离原则。更好的做法是将飞行、行走和游泳等职责分别定义在FlyableWalkableSwimmable等接口中,然后让不同的动物类根据需要实现相应的接口。

综上所述,单一职责原则和接口隔离原则都是为了提高软件系统的可维护性、可扩展性和灵活性。它们鼓励我们将系统的职责进行细分,并使用专门的类或接口来承担这些职责,从而避免因为职责的耦合而导致的复杂性和风险。

44. Java 有没有 goto? 如果有,一般用在什么地方?如果没有,如何跳出当前的多重嵌套循环?

Java 语言中确实存在 goto 关键字,但它是作为保留关键字存在的,并未在 Java 语言的规范中实际使用或实现。这意味着你不能在 Java 程序中使用 goto 语句来跳转控制流。Java 语言的这种设计决策是出于提高代码可读性和可维护性的考虑,因为 goto 语句可能会导致代码难以理解和维护,尤其是在复杂的控制流中。

跳出当前的多重嵌套循环

由于 Java 不支持 goto 语句,你需要使用其他方式来跳出多重嵌套循环。以下是一些常用的方法:

  1. 使用标签(Label)和 break 语句
    在 Java 中,你可以给循环(或任何块)添加一个标签,然后使用带有该标签的 break 语句来跳出多重嵌套循环。这是一种模拟 goto 跳出到特定标签位置的方式。

    outerLoop:
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
            if (i * j > 20) {
                break outerLoop; // 跳出最外层的循环
            }
            System.out.println(i * j);
        }
    }
    
  2. 使用异常
    虽然这不是一个推荐的做法(因为异常处理应该用于处理异常情况,而不是控制程序流程),但在某些特殊情况下,你可以抛出一个自定义的异常,并在外层捕获它,以此来跳出多重循环。

    try {
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                if (i * j > 20) {
                    throw new Exception("Break from loops");
                }
                System.out.println(i * j);
            }
        }
    } catch (Exception e) {
        // 处理异常或简单地忽略它
    }
    
  3. 重构代码
    通常,如果你发现自己需要频繁地跳出多重嵌套循环,这可能是你的代码设计需要改进的信号。考虑将循环体或循环条件重构为单独的函数或方法,这样你就可以使用普通的 return 语句来退出函数,而不是尝试跳出多层循环。

    public void process() {
        for (int i = 0; i < 10; i++) {
            if (!processInner(i)) {
                break;
            }
        }
    }
    
    private boolean processInner(int i) {
        for (int j = 0; j < 10; j++) {
            if (i * j > 20) {
                return false; // 相当于跳出外层循环
            }
            System.out.println(i * j);
        }
        return true;
    }
    

    这种方法通常会使代码更加清晰和易于维护。

45. 简述Java 创建对象的方式有哪些?

在Java中,创建对象的方式主要有以下几种:

  1. 使用new关键字
    这是创建对象最常用和直接的方式。通过new关键字调用类的构造方法(Constructor)来创建对象。如果类中没有显式定义构造方法,Java编译器会提供一个默认的无参构造方法;如果类中定义了构造方法,则必须使用这些构造方法之一来创建对象。

    MyClass obj = new MyClass(); // 使用无参构造方法
    MyClass objWithArgs = new MyClass(arg1, arg2); // 使用有参构造方法
    
  2. 使用Class类的newInstance()方法(已过时,不推荐使用):
    在Java 9之前,Class类提供了一个newInstance()方法,它使用无参构造方法来创建类的实例。但是,从Java 9开始,这个方法被标记为过时(deprecated),因为它不能传递任何构造参数,且不如Constructor类的newInstance()方法灵活。不过,在了解旧代码时仍然可能会遇到它。

    // 注意:此方法已过时,不推荐使用
    MyClass obj = MyClass.class.newInstance();
    
  3. 使用反射(Reflection)的Constructor类的newInstance()方法
    通过反射,可以在运行时动态地创建对象,包括使用有参构造方法。这涉及到java.lang.reflect.Constructor类。这种方式比Class.newInstance()更灵活,因为它允许传递构造参数。

    Class<?> clazz = Class.forName("com.example.MyClass");
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class);
    MyClass obj = (MyClass) constructor.newInstance("arg1", 123);
    
  4. 使用克隆(Cloning)
    如果类实现了Cloneable接口,并覆盖了Object类的clone()方法,那么可以通过调用已存在对象的clone()方法来创建该对象的一个副本。注意,这里创建的是浅拷贝(shallow copy),如果对象包含对可变对象的引用,则这些引用也会被拷贝,但引用的对象本身不会被拷贝。

    MyClass original = new MyClass();
    MyClass clone = (MyClass) original.clone();
    
  5. 使用反序列化(Serialization/Deserialization)
    如果一个类的对象可以被序列化,那么可以通过序列化该对象到一个流中,然后再从流中反序列化出该对象的一个新实例来创建对象。这通常用于对象状态的持久化或网络传输。

    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("obj.ser"));
    out.writeObject(originalObj);
    out.close();
    
    ObjectInputStream in = new ObjectInputStream(new FileInputStream("obj.ser"));
    MyClass newObj = (MyClass) in.readObject();
    in.close();
    

这些是在Java中创建对象的一些主要方式。每种方式都有其特定的使用场景和限制。

46. 简述Java 浅拷贝和深拷贝 ?

在Java中,拷贝(Copy)对象时,有两种主要的拷贝方式:浅拷贝(Shallow Copy)和深拷贝(Deep Copy)。这两种拷贝方式的主要区别在于它们如何处理对象中的引用类型字段。

浅拷贝(Shallow Copy)

浅拷贝是指创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行逐位复制;如果字段是引用类型,则复制引用但不复制引用的对象。因此,原始对象及其副本会引用同一个对象。

这意味着,如果在原始对象或其副本中修改了引用类型的字段,那么这些修改将反映在两个对象上,因为它们实际上指向的是内存中的同一个对象。

浅拷贝的实现方式之一是使用Object类的clone()方法(注意,并不是所有的类都继承自Cloneable接口,只有实现了Cloneable接口的类才能调用clone()方法,否则会抛出CloneNotSupportedException)。另外,也可以使用拷贝构造函数或拷贝工厂方法来实现浅拷贝。

深拷贝(Deep Copy)

深拷贝是指创建一个新对象,然后将当前对象的非静态字段复制到该新对象,无论字段是值类型的还是引用类型。对于引用类型的字段,深拷贝会创建一个全新的对象,并将这个新对象的引用赋值给副本的字段。因此,原始对象和副本对象在内存中是完全独立的。

这意味着,对原始对象或其副本中的引用类型字段所做的任何修改都不会影响到另一个对象。

实现深拷贝通常需要程序员自己编写代码来复制所有字段,包括引用类型的字段。这可以通过递归地调用clone()方法(如果适用)或使用序列化(Serialization)和反序列化(Deserialization)技术来实现。序列化是将对象状态转换为可以保存或传输的格式的过程,反序列化则是将已保存的序列化对象状态重新构造为对象的过程。通过序列化和反序列化,可以实现对象的深拷贝,因为序列化时会保存对象的状态以及对象引用的所有对象的状态,反序列化时会创建所有对象的全新实例。

总结

  • 浅拷贝:只复制对象本身和基本数据类型字段,对于引用类型字段,只复制引用而不复制引用的对象。
  • 深拷贝:不仅复制对象本身和基本数据类型字段,还复制引用类型字段指向的对象,并创建全新的对象实例。

47. Java简述super()与this()的区别?

在Java中,super()this() 都是构造方法中的特殊用法,但它们有着明显的区别和用途。

super()

  • 用途super() 用于在子类的构造方法中调用父类的构造方法。这是确保父类被正确初始化的一种方式。
  • 调用时机super() 必须是子类构造方法中的第一条语句(除了注释之外)。如果子类构造方法中没有显式地调用父类的构造方法,那么编译器会自动插入一个调用父类无参构造方法的 super()。但是,如果父类没有无参构造方法且子类构造方法中没有显式调用其他父类构造方法,则编译时会报错。
  • 限制:在子类构造方法中,super() 调用只能出现一次,且必须作为第一条语句(除非父类没有无参构造方法且你显式调用了其他父类构造方法)。

this()

  • 用途this() 用于在当前类的构造方法中调用当前类的另一个构造方法。这通常用于代码复用,避免重复初始化代码。
  • 调用时机:与 super() 类似,this() 也必须是构造方法中的第一条语句(除了注释和 super() 调用之外,如果有的话)。
  • 限制this() 调用在构造方法中也只能出现一次,且同样必须是第一条语句(如果存在 super() 调用,则 super() 调用必须在 this() 之前)。
  • 注意this()super() 不能同时出现在同一个构造方法中,因为两者都必须是构造方法中的第一条语句,而这个位置只能被其中一个占用。

总结

  • 用途super() 用于调用父类构造方法,确保父类被正确初始化;this() 用于调用当前类的另一个构造方法,实现代码复用。
  • 调用时机和位置:两者都必须是构造方法中的第一条语句(super() 除外,如果它是自动插入的)。this() 调用必须在 super() 调用之后(如果存在 super() 调用)。
  • 限制:两者都只能在构造方法中出现一次,且都是构造方法中的第一条语句(除非存在特殊情况,如父类没有无参构造方法且子类没有显式调用父类构造方法)。
  • 同时使用this()super() 不能同时出现在同一个构造方法中。

48. Java Final类有什么特点?

Java中的final类具有一些独特的特点,这些特点主要围绕其不可变性(在继承方面的)和性能优化方面。以下是final类的一些主要特点:

  1. 不可被继承final类不能被其他类继承。这是final修饰符在类定义中最直接的作用。当你将类声明为final时,你就是在告诉编译器和其他开发者,这个类的设计是完整的,不需要也不应该被扩展或修改。这有助于保持类的封装性和安全性,防止子类破坏父类的设计。

  2. 设计上的稳定性:通过将类声明为final,开发者可以明确表示这个类的设计是稳定的,不需要通过继承来扩展其功能。这有助于其他开发者理解类的用途和限制,并避免不必要的继承尝试。

  3. 性能优化:在某些情况下,将类声明为final可以提高性能。这是因为编译器和JVM可以对final类进行更深入的优化,因为它们知道这些类不会被继承。例如,JVM可以缓存final类的布局信息,从而加快类加载和实例化的速度。

  4. 简化调试:由于final类不能被继承,因此当在调试过程中遇到问题时,你可以更容易地确定问题的来源,因为不需要考虑子类可能引入的复杂性。

  5. 鼓励组合而非继承:在面向对象编程中,继承是一种强大的特性,但它也可能导致设计上的复杂性。通过将类声明为final,开发者可以鼓励其他开发者使用组合(composition)而不是继承(inheritance)来扩展类的功能。组合通常被认为是一种更灵活、更易于维护的设计方法。

  6. 与final方法和final变量的关系:虽然final类、final方法和final变量在Java中都扮演着不同的角色,但它们都体现了不可变性的概念。final方法不能被覆盖,final变量一旦被初始化就不能被重新赋值,而final类则不能被继承。这些特性共同构成了Java中不可变性的一部分。

总之,final类在Java中是一种有用的特性,它可以帮助开发者创建稳定、高效且易于维护的类。然而,它也应该谨慎使用,以确保不会不必要地限制类的灵活性和可扩展性。

答案来自文心一言,仅供参考

在这里插入图片描述

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

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

相关文章

004.Python爬虫系列_web请求全过程剖析(重点)

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

2024年8月31日历史上的今天大事件早读

1449年8月31日 明朝“土木之变” 1907年8月31日 英、法、俄三国协约形成 1914年8月31日 “骆派”京韵大鼓的创建者骆玉笙诞生 1916年8月31日 蔡锷东渡日本养病 1935年8月31日 美国通过《中立法案》 1937年8月31日 日本华北方面军成立 1941年8月31日 晋察冀边区完成民主大…

2024最新最全:国内外人工智能AI工具网站大全!

国内外人工智能AI工具网站大全&#xff08;一键收藏&#xff0c;应有尽有&#xff09; 摘要一、AI写作工具二、AI图像工具 2.1、常用AI图像工具2.2、AI图片插画生成2.3、AI图片背景移除2.4、AI图片无损调整2.5、AI图片优化修复2.6、AI图片物体抹除 三、AI音频工具四、AI视频工…

南京观海微电子----CMOS门电路(OD门、传输门、双向模拟开关、三态门)

【 1. MOS管】 MOS管&#xff1a;绝缘栅型场效应管。 【 2. CMOS电路】 当NMOS管和PMOS管成对出现在电路中&#xff0c;且二者在工作中互补&#xff0c;称为CMOS管(Complementary Metal-Oxide-Semiconductor)。 电路结构 拉电流 如下图所示&#xff0c;输入低电平&#xff…

王者荣耀 设置游戏头像 不用微信头像

我们在微信 我 选择 设置 在里面找到 个人信息与权限 如果找不到看看有木有一个叫隐私的选项 点击 进入之后 选择授权管理 找到王者荣耀 然后点击右侧的小箭头进入 点击下面的 解除授权 确认一下 解除授权 然后重新打开王者 选择微信登录 我们这里 选择新建昵称头像 选…

线性代数之线性方程组

目录 线性方程组 1. 解的个数 齐次线性方程组&#xff1a; 非齐次线性方程组&#xff1a; 2. 齐次线性方程组的解 3. 非齐次线性方程组的解 4. 使用 Python 和 NumPy 求解线性方程组 示例代码 齐次线性方程组 非齐次线性方程组 示例结果 齐次线性方程组 非齐次线性…

Unity获取SceneView尺寸

获取SceneView尺寸 var sceneView SceneView.lastActiveSceneView; var size new Vector2(sceneView.position.width,sceneView.position.height);

Elasticsearch学习(1)-mac系统安装elasticsearch基础

Elasticsearch基础 1. 传统数据库与elasticsarch2. 下载Elasticsearch7. 经过上述所有操作&#xff0c;就可以得到一个具体的连接可视化页面3. 安装kibana4. 其余知识点 elasticsearch是什么&#xff1f; Elasticsearch 是一个分布式、高扩展、高实时的搜索与数据分析引擎。它能…

sql-labs靶场(41-50)

四十一 1.查看数据库名 ?id-1 union select 1,2,database()-- 2.查看表名 ?id-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schemadatabase()-- 3.查看user表列名 ?id-1 union select 1,group_concat(column_name),3 from…

SpringMVC处理流程介绍

SpringMVC请求处理流程 发起请求到前端控制器(DispatcherServlet)前端控制器请求HandlerMapping查找Handler(可以根据xml配置,注解进行查找) 对应Spring源码 //在类DispatcherServlet里面 protected void doDispatch(HttpServletRequest request, HttpServletResponse respon…

Leetcode102二叉树的层序遍历(java实现)

今天分享的题目是lee102题&#xff0c;题目的描述如下&#xff1a; 可能做到这道题的小伙伴写过其他关于二叉树的题目&#xff0c;但是一般是使用递归的方式做一个深度遍历&#xff0c;而层序遍历我们该如何做呢&#xff1f; 解题思路&#xff1a;使用一个队列来记录本层节点&a…

浅谈新能源汽车充电桩安装以及防范

摘要&#xff1a;随着国家对绿色环保的倡导&#xff0c;新能源电动汽车应运而生&#xff0c;它们采用清洁能源替代传统能源&#xff0c;有效避免了对自然环境的污染&#xff0c;并减少了资源消耗&#xff0c;实现了资源的高效利用。新能源电动汽车的普及降低了使用成本&#xf…

Rust Linux开发人员自比道路建设者和寻路者的区别

红帽公司&#xff08;Red Hat&#xff09;的长期直接渲染管理器&#xff08;Direct Rendering Manager&#xff0c;DRM&#xff09;子系统维护者大卫-艾尔里&#xff08;David Airlie&#xff09;撰写了一篇有趣的博文&#xff0c;将开发人员的类型与筑路工人、寻路者与酒店进行…

800G OSFP光模块发展概述

在快速发展的高速网络领域&#xff0c;800G OSFP光模块的演变象征着创新与进步。自诞生以来&#xff0c;800G OSFP光模块凭借哪些独特优势脱颖而出&#xff1f;本文将重点介绍800G OSFP光模块的发展路径。 800G OSFP光模块发展路径 路径一&#xff1a;EML 路由 800G DR8 OSF…

Python进阶07-高级语法

零、文章目录 Python进阶07-高级语法 1、with语句 &#xff08;1&#xff09;文件操作 文件使用完后必须关闭&#xff0c;因为文件对象会占用操作系统的资源&#xff0c;并且操作系统同一时间能打开的文件数量也是有限的 # 第一步&#xff1a;打开文件 f open(python.txt…

另一种关于类的小例

前言 我们还是以一段关于构造函数的代码作为开端&#xff0c;我们以之前银行家的小项目为背景 class Account {constructor(owner, currency, pin) {this.owner owner;this.currency currency;this.pin pin;} }const ITshare new Account(ITshare, EUR, 21211); console.…

堆垛机及AGV能力计算

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》人俱乐部 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载。 这份文件是关于堆垛机和AGV&#xff08;…

第六课,模运算进阶,计算机存储单位

一&#xff0c;模运算的进阶知识 先复习一下已知的模运算知识&#xff1a; ①符号是%&#xff0c;但作为模运算符号时应念作“模”而非“百分之”或“百分号” ②参与模运算的数必须是两个整数&#xff0c;其作用是计算余数 然后新学几个模运算知识&#xff1a; ③当被除数是…

IPv4和子网掩码

目录 IP地址&#xff1a; IP概念&#xff1a; 网络号与主机号&#xff1a; 网关与跨网通信&#xff1a; IP地址的分类&#xff1a; 子网掩码&#xff1a; 如何确定两个IP地址是否在同一网段; 练习&#xff1a; 补充&#xff1a; IP地址&#xff1a; IP概念&#xff1…

哪家宠物空气净化器能吸毛除臭?希喂、352真实测评分享

自从家里同时迎来了猫咪与狗狗&#xff0c;生活的色彩确实丰富了许多&#xff0c;但这份喜悦的背后&#xff0c;也有每天理都理不断的“盛况”。每当结束了一天的忙碌&#xff0c;满心期待着家的温馨与安宁&#xff0c;推开家门的那一刻&#xff0c;猫和狗先迎接我的反而是它们…