2023年Java核心技术面试第八篇(篇篇万字精讲)

这篇具有很好参考价值的文章主要介绍了2023年Java核心技术面试第八篇(篇篇万字精讲)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

十五 . 面向对象的基本要素:封装,继承,多态

 15.1 封装:

15.1.1 例子:

15.2 继承

15.2.1 例子

15.3 多态

15.3.1 例子

15.3.2 小结:谈谈多态的继承的联系

十六 . synchronized 和 ReentrantLock 的区别?

16.1 典型回答

16.2 深入理解底层锁的概念

16.2.1 synchronized

16.2.2 ReentrantLock

16.2.2.1 例子:

16.2.2.1.1 公平性(Fairness)控制:

16.2.2.1.2 可中断性(Interruptibility):

16.2.2.1.3 条件变量(Condition)支持:

16.2.2.1.4 超时控制(Timeout):


十五 . 面向对象的基本要素:封装,继承,多态

 15.1 封装:

封装:封装是将数据和功能包装在一个类中,通过对外提供公共接口来隐藏内部实现细节。这样可以保护数据免受外部直接访问和修改,只能通过类提供的方法进行操作,封装提供了数据的安全性和代码的可维护性。

15.1.1 例子:

我们可以创建一个名为"Person"的类来封装一个人的相关信息,如姓名、年龄和性别。通过定义公共方法如"setName"、"setAge"和"setGender"来设置这些属性值,而不直接暴露给外部代码。这样可以确保属性值的正确性和一致性。

public class Person {
    private String name;
    private int age;
    private String gender;

    public Person(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public static void main(String[] args) {
        Person person = new Person("John", 25, "Male");
        System.out.println("Person Name: " + person.getName());
        System.out.println("Person Age: " + person.getAge());
        System.out.println("Person Gender: " + person.getGender());

        // 修改属性值
        person.setName("Alice");
        person.setAge(30);
        person.setGender("Female");

        System.out.println("Updated Person Name: " + person.getName());
        System.out.println("Updated Person Age: " + person.getAge());
        System.out.println("Updated Person Gender: " + person.getGender());
    }
}

15.2 继承

继承:继承是指一个类(称为子类或派生类)可以继承另一个类(称为父类或基类)的属性和方法。

子类继承了父类的特性,并且可以在此基础上进行扩展或重写。继承实现了代码的重用和扩展性。

15.2.1 例子

我们可以定义一个"Animal"类作为父类,其中包含通用的属性和方法,如"eat"和"sleep"。然后可以创建子类如"Cat"和"Dog"来继承"Animal"类,并在子类中添加特定的属性和方法,如"meow"方法和"bark"方法。

// 定义父类 Animal
class Animal {
    // 父类的属性
    protected String name;
  
    // 父类的方法
    public Animal(String name) {
        this.name = name;
    }
  
    public void eat() {
        System.out.println(name + " is eating.");
    }
  
    public void sleep() {
        System.out.println(name + " is sleeping.");
    }
}

// 定义子类 Cat
class Cat extends Animal {
    // 子类的属性
    private String breed;
  
    // 子类的方法,并调用父类的构造方法
    public Cat(String name, String breed) {
        super(name); // 调用父类的构造方法
        this.breed = breed;
    }
  
    // 子类的自定义方法
    public void meow() {
        System.out.println(name + " is meowing.");
    }
}

// 定义子类 Dog
class Dog extends Animal {
    // 子类的属性
    private String breed;
  
    // 子类的方法,并调用父类的构造方法
    public Dog(String name, String breed) {
        super(name); // 调用父类的构造方法
        this.breed = breed;
    }
  
    // 子类的自定义方法
    public void bark() {
        System.out.println(name + " is barking.");
    }
}

// 测试代码
public class Main {
    public static void main(String[] args) {
        Cat cat = new Cat("Kitty", "Persian");
        cat.eat(); // 调用继承自父类的方法
        cat.sleep();
        cat.meow(); // 调用子类自定义的方法

        Dog dog = new Dog("Buddy", "Labrador");
        dog.eat(); // 调用继承自父类的方法
        dog.sleep();
        dog.bark(); // 调用子类自定义的方法
    }
}

输出:

Kitty is eating.
Kitty is sleeping.
Kitty is meowing.
Buddy is eating.
Buddy is sleeping.
Buddy is barking.

15.3 多态

多态:多态是指同一种操作可以作用于不同的对象,并根据对象的实际类型执行不同的行为。通过多态,可以提高代码的灵活性和可扩展性。

15.3.1 例子

定义了一个抽象类 Animal,并具有一个抽象方法 sound。然后,定义了两个子类 CatDog,它们分别继承自 Animal 并实现了 sound 方法。

在测试类中,创建了一个 Animal 类型的对象数组,并分别用 CatDog 的实例来初始化数组的元素。然后通过循环遍历数组,并调用 sound 方法,可以看到根据对象的实际类型,程序会执行不同的行为。这就是多态的体现,相同的方法名 sound 可以作用于不同的对象,并根据对象的实际类型执行不同的行为。

// 定义父类 Animal
abstract class Animal {
    abstract void sound();
}

// 定义子类 Cat
class Cat extends Animal {
    void sound() {
        System.out.println("喵喵喵");
    }
}

// 定义子类 Dog
class Dog extends Animal {
    void sound() {
        System.out.println("汪汪汪");
    }
}

// 测试类
public class PolymorphismExample {
    public static void main(String[] args) {
        // 创建 Animal 对象数组
        Animal[] animals = new Animal[2];
        animals[0] = new Cat();
        animals[1] = new Dog();

        // 循环遍历数组并调用 sound 方法
        for (Animal animal : animals) {
            animal.sound();
        }
    }
}

15.3.2 小结:谈谈多态的继承的联系

继承是建立类之间的一种层次关系,子类可以继承父类的属性和方法,并且可以增加自己的特定实现;而多态是在继承关系中,通过父类的类型引用来指向子类的对象,并且根据对象的实际类型执行不同的行为。继承是一种静态的关系,而多态是一种动态的行为。继承和多态通常是一起使用,多态是继承的一种体现。

十六 . synchronized 和 ReentrantLock 的区别?

 Java精心设计的高效并发机制,构建大规模应用的基础之一。

16.1 典型回答

synchronized 是Java内建的同步机制,也被人称作Intrinsic Locking,提供互斥的语义和可见性,当一个线程已经获取当前锁时,其他试图获取的线程只能等待或者阻塞在哪里。

Java 5 以前,synchronized 是仅有的同步手段,在代码中,synchronized可以用来修饰方法,可以在特定的代码快上,本质上synchronized方法,等同于把方法全部语句用synchronized块包起来。

ReentrantLock ,通常称为再入锁,Java提供锁的实现,语义和synchronized差不多,再入锁可以直接通过代码,直接调用Lock()方法获取,代码书写更加灵活,ReentrantLock提供了很多实用的方法,实现了很多synchronized无法做到的细节控制,可以控制fairness,也就是公平性,或者利用定义条件等,明确调用unlock()方法释放,不然就会一直持有这个锁。

synchronized和ReentrantLock的性能比较,早期synchronized再很多场景下性能相差比较大,后续进行改进后,再低竞争的场景表现可能优于ReentrantLock。

16.2 深入理解底层锁的概念

16.2.1 synchronized

16.2.2 ReentrantLock

ReentrantLock是Java提供的可重入锁实现,它具有更细粒度的控制和更多的功能。相较于synchronizedReentrantLock提供了以下优势:

  1. 公平性(Fairness)控制:ReentrantLock可以通过构造方法的参数来指定是否按照线程请求锁的顺序获取锁(公平性),以避免某些线程长时间等待锁而产生饥饿现象。
  2. 可中断性(Interruptibility):ReentrantLock提供了可中断的获取锁的方法,即线程在等待锁的过程中可以被其他线程中断,并通过捕获InterruptedException来处理中断事件。
  3. 条件变量(Condition)支持:ReentrantLock内置了Condition接口,可以创建多个条件变量,使线程能够在特定条件满足时等待或被唤醒,从而实现更灵活的线程协作。
  4. 超时控制(Timeout):ReentrantLock提供了尝试获取锁的方法,可以指定一个超时时间,在超过指定时间后如果无法获得锁,则继续执行其他操作,避免线程长时间等待。

在高竞争的多线程场景下,ReentrantLock通常表现更好,因为它提供了对锁的更细粒度的控制,并且支持更多的高级功能。

16.2.2.1 例子:
16.2.2.1.1 公平性(Fairness)控制:

ReentrantLock提供了公平性控制的功能。通过在构造方法中指定fair参数为true,可以使得锁的获取按照线程请求的顺序进行,即先到先得的原则。这样可以避免某些线程一直获取不到锁而产生饥饿现象。

相比之下,synchronized关键字并没有提供公平性控制的选项,它的锁获取是非公平的。在多个线程同时竞争同一个锁时,synchronized无法保证等待时间最长的线程优先获得锁,可能会导致一些线程长时间等待锁而无法执行。

因此,如果对公平性有较高的要求,可以使用ReentrantLock来实现可重入锁,并通过设置fair参数为true来保证线程的公平竞争。

16.2.2.1.2 可中断性(Interruptibility):

假设有两个线程,线程A和线程B,它们竞争一个ReentrantLock锁。

import java.util.concurrent.locks.ReentrantLock;

public class InterruptExample {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            try {
                lock.lockInterruptibly(); // 可中断地获取锁
                System.out.println("线程A获得了锁");
                Thread.sleep(5000); // 模拟线程A执行一些操作
            } catch (InterruptedException e) {
                System.out.println("线程A被中断");
            } finally {
                if (lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        });

        Thread threadB = new Thread(() -> {
            try {
                Thread.sleep(2000); // 等待2秒
                threadA.interrupt(); // 中断线程A
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        threadA.start();
        threadB.start();
    }
}

线程A通过调用lock.lockInterruptibly()方法来可中断地获取锁。而线程B在等待2秒后,调用threadA.interrupt()方法来中断线程A。

如果线程A在等待锁的过程中被中断,会触发InterruptedException异常,然后线程A可以根据自己的需求进行相应的处理。在上述代码中,线程A会打印"线程A被中断"。

这个例子展示了ReentrantLock的可中断性,通过中断一个等待锁的线程,可以让它在等待过程中响应中断并进行相应的处理。而synchronized关键字并没有提供直接的中断支持,无法中断正在等待锁的线程。

 文章来源地址https://www.toymoban.com/news/detail-673340.html

16.2.2.1.3 条件变量(Condition)支持:

ReentrantLock内置了Condition接口,通过它可以创建多个条件变量,实现更灵活的线程协作。

Condition接口提供了以下几个方法:

  • await():使当前线程等待,并释放锁,直到被其他线程显式地唤醒或被中断。
  • awaitUninterruptibly():与await()类似,但不响应中断。
  • signal():唤醒一个等待该条件的线程。
  • signalAll():唤醒所有等待该条件的线程。

例子:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionExample {
    private static ReentrantLock lock = new ReentrantLock();
    private static Condition condition = lock.newCondition();

    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            try {
                lock.lock();
                System.out.println("线程A开始等待");
                condition.await(); // 等待条件满足
                System.out.println("线程A被唤醒");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        Thread threadB = new Thread(() -> {
            try {
                Thread.sleep(2000); // 等待2秒
                lock.lock();
                System.out.println("线程B发出唤醒信号");
                condition.signal(); // 发出唤醒信号
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        });

        threadA.start();
        threadB.start();
    }
}

线程A通过调用condition.await()方法使自己等待条件满足,然后线程B在等待2秒后,通过调用condition.signal()方法唤醒线程A。

使用条件变量,我们可以实现更加灵活的线程协作,线程可以根据特定的条件进行等待或唤醒。这在一些生产者消费者模型、线程池等场景中非常有用。而synchronized关键字并没有直接提供这种条件变量的支持。

16.2.2.1.4 超时控制(Timeout):

,ReentrantLock提供了尝试获取锁的方法,并且可以指定一个超时时间。如果在指定时间内无法获取到锁,则可以继续执行其他操作,避免线程长时间等待。

ReentrantLock提供了以下几个尝试获取锁的方法:

  • tryLock():尝试获取锁,如果成功获取到锁则返回true,否则立即返回false
  • tryLock(long timeout, TimeUnit unit):尝试在指定的超时时间内获取锁,如果在指定时间内成功获取到锁则返回true,否则在超时后返回false

例子:

线程A调用lock.tryLock(3, TimeUnit.SECONDS)方法,在3秒内尝试获取锁。如果在3秒内成功获取到锁,则执行相应的操作,否则在超时后输出"线程A尝试获取锁超时"。

通过使用tryLock()方法并指定超时时间,我们可以避免线程长时间等待,并在超时后执行其他操作。这在一些需要控制等待时间的场景中非常有用。

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TimeoutExample {
    private static ReentrantLock lock = new ReentrantLock();

    public static void main(String[] args) {
        Thread threadA = new Thread(() -> {
            try {
                if (lock.tryLock(3, TimeUnit.SECONDS)) { // 在3秒内尝试获取锁
                    try {
                        System.out.println("线程A获得了锁");
                        Thread.sleep(5000); // 模拟线程A执行一些操作
                    } finally {
                        lock.unlock();
                        System.out.println("线程A释放了锁");
                    }
                } else {
                    System.out.println("线程A尝试获取锁超时");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread threadB = new Thread(() -> {
            try {
                Thread.sleep(2000); // 等待2秒
                lock.lock(); // 线程B获得锁
                System.out.println("线程B获得了锁");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
                System.out.println("线程B释放了锁");
            }
        });

        threadA.start();
        threadB.start();
    }
}

tips:

TimeUnit.SECONDS 是 Java 中的一个枚举常量,它表示时间单位为秒。

lock.tryLock(3, TimeUnit.SECONDS) 表示在 3 秒内尝试获取锁。这里的 3 就是指定的时间,而 TimeUnit.SECONDS 则表示时间单位为秒。

  • TimeUnit.NANOSECONDS:纳秒
  • TimeUnit.MICROSECONDS:微秒
  • TimeUnit.MILLISECONDS:毫秒
  • TimeUnit.MINUTES:分钟
  • TimeUnit.HOURS:小时
  • TimeUnit.DAYS:天

 

到了这里,关于2023年Java核心技术面试第八篇(篇篇万字精讲)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【从零开始学习JAVA | 第八篇】String类

    目录 前言: String类: 常见的认识误区: 创建String类:  注意点: 总结:         String类是Java中最常见的一个类,本篇将对Stirng类的各种功能进行详细的介绍,各位小伙伴如果感兴趣可以点击进来观看。 Java中的String类是一个非常常用的类, 它表示一串字符序列 。Java的字

    2024年02月10日
    浏览(50)
  • 2023年MySQL核心技术面试第一篇

    目录 前言: MySQL开篇前言补充含有前三点,先认识大概的MySQL,从下一篇开始进入MySQL的核心技术讲解。 一 . MySQL开篇前言补充 存储:一个完整的数据存储过程是怎样的? 1.1 数据存储过程  1.1.1 创建MySQl 数据库 1.1.1.1 为什么我们要先创建一个数据库,而不是直接创建数据表

    2024年02月11日
    浏览(37)
  • 第八篇【传奇开心果系列】Python自动化办公库技术点案例示例:深度解读使用Python库清洗处理从PDF文件提取的文本

    在使用pyPDF4或任何其他Python的PDF解析库提取PDF文件的文本后,进行清洗处理是非常重要的。这是因为PDF文件通常包含了各种格式化元素,如页眉、页脚、页码、图表、图片等,这些元素可能会干扰到你提取的文本内容。清洗处理的目标是去除这些干扰元素,仅提取出你真正需

    2024年03月22日
    浏览(60)
  • 「Java核心技术大会 2023」——小解送书第三期

    目录 共同深入探讨 Java 生态!直播预约:视频号“IT阅读排行榜” 抽奖 大会简介 人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近几年里,Java阵营的

    2024年02月09日
    浏览(51)
  • 《Java核心技术大会2023》——AIC松鼠活动第一期

    大会简介 人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近几年里,Java阵营的确受到了前所未有的挑战,出现了更多更强大的竞争者。 但是,迄今Ja

    2024年02月16日
    浏览(41)
  • 「Java核心技术大会 2023」6月启动,邀你共同探讨Java生态

    🤵‍♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+         人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家;云原生的持

    2024年02月10日
    浏览(61)
  • 「Java核心技术大会 2023」6月重磅启动,邀你共同探讨Java生态

    前言 📕作者简介: 热爱跑步的恒川 ,致力于C/C++、Java、Python等多编程语言,热爱跑步,喜爱音乐的一位博主。 📗本文收录于恒川的日常汇报系列,大家有兴趣的可以看一看 📘相关专栏C语言初阶、C语言进阶系列等,大家有兴趣的可以看一看 📙Python零基础入门系列,Jav

    2024年02月09日
    浏览(53)
  • 「Java核心技术大会 2023」6月重磅启动,邀你共同探讨Java生态 ~文末福利

    人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近几年里,Java阵营的确受到了前所未有的挑战,出现了更多更强大的竞争者。 但是,迄今Java仍然有着非

    2024年02月11日
    浏览(57)
  • 「Java核心技术大会 2023」6月重磅启动,邀你共同探讨Java生态【文末送书】

    大会简介 人工智能在22年、23年的再次爆发让Python成为编程语言里最大的赢家;云原生的持续普及令Go、Rust等新生的语言有了进一步叫板传统技术体系的资本与底气。我们必须承认在近几年里,Java阵营的确受到了前所未有的挑战,出现了更多更强大的竞争者。 但是,迄今Ja

    2024年02月11日
    浏览(81)
  • 第八篇——Kafka Streams源码解读

    作者:禅与计算机程序设计艺术 Kafka Streams是一个开源分布式流处理平台,它可以让你轻松处理实时数据流。通过Kafka Streams API可以轻松创建、部署和运行复杂的实时流处理应用程序。虽然Kafka Stream提供了许多高级功能,但其底层原理却十分简单易懂,在学习之余,我们还是需

    2024年02月07日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包