Android App开发语音处理之系统自带的语音引擎、文字转语音、语音识别的讲解及实战(超详细 附源码)

news2025/2/25 21:33:23

需要源码请点赞关注收藏后评论区留下QQ~~~

一、系统自带的语音引擎

语音播报的本质是将书面文字转换成自然语言的音频流,这个转换操作被称作语音合成,又称TTS(从文本到语音)在转换过程中,为了避免机械合成的呆板和停顿感,语音合成技术还得对语音流进行平滑处理,以确保输出得语音音律流畅自然。

不管是Android原生的西文引擎还是手机厂商集成的中文引擎,都支持通过系统提供的API处理语音,其中的语音合成工具是TextToSpeech 常用方法如下

构造方法:第二个输入参数为语音监听器

setLanguage:设置引擎语言

setSpeechRate 设置语速

setPitch 设置音调

synthesizeToFile 把指定文本的朗读语言输出到文件

实战效果如下

 代码如下

Java类

package com.example.voice;

import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Spinner;

import androidx.appcompat.app.AppCompatActivity;

import com.example.voice.adapter.LanguageListAdapter;
import com.example.voice.bean.Language;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class SpeechEngineActivity extends AppCompatActivity {
    private final static String TAG = "SpeechEngineActivity";
    private TextToSpeech mSpeech; // 声明一个文字转语音对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_speech_engine);
        findViewById(R.id.btn_jump_setting).setOnClickListener(v -> {
            Intent intent = new Intent();
            intent.setAction("com.android.settings.TTS_SETTINGS");
            startActivity(intent);
        });
        // 创建一个文字转语音对象,初始化结果在监听器TTSListener中返回
        mSpeech = new TextToSpeech(this, new TTSListener());
    }

    private List<TextToSpeech.EngineInfo> mEngineList; // 语音引擎列表
    // 定义一个文字转语音的初始化监听器
    private class TTSListener implements TextToSpeech.OnInitListener {
        // 在初始化完成时触发
        @Override
        public void onInit(int status) {
            if (status == TextToSpeech.SUCCESS) { // 初始化成功
                if (mEngineList == null) { // 首次初始化
                    // 获取系统支持的所有语音引擎
                    mEngineList = mSpeech.getEngines();
                    initEngineSpinner(); // 初始化语音引擎下拉框
                }
                initLanguageList(); // 初始化语言列表
            }
        }
    }

    // 初始化语音引擎下拉框
    private void initEngineSpinner() {
        String[] engineArray = new String[mEngineList.size()];
        for(int i=0; i<mEngineList.size(); i++) {
            engineArray[i] = mEngineList.get(i).label;
        }
        ArrayAdapter<String> engineAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, engineArray);
        Spinner sp_engine = findViewById(R.id.sp_engine);
        sp_engine.setPrompt("请选择语音引擎");
        sp_engine.setAdapter(engineAdapter);
        sp_engine.setOnItemSelectedListener(new EngineSelectedListener());
        sp_engine.setSelection(0);
    }

    private class EngineSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            //recycleSpeech(); // 回收文字转语音对象
            // 创建指定语音引擎的文字转语音对象
            mSpeech = new TextToSpeech(SpeechEngineActivity.this, new TTSListener(),
                    mEngineList.get(arg2).name);
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

    private String[] mLanguageArray = {"中文普通话", "英语", "法语", "德语", "意大利语",  };
    private Locale[] mLocaleArray = { Locale.CHINA, Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN };

    // 初始化语言列表
    private void initLanguageList() {
        List<Language> languageList = new ArrayList<>();
        // 下面遍历语言数组,从中挑选出当前引擎所支持的语言列表
        for (int i=0; i<mLanguageArray.length; i++) {
            String desc = "正常使用";
            // 设置朗读语言
            int result = mSpeech.setLanguage(mLocaleArray[i]);
            if (result == TextToSpeech.LANG_MISSING_DATA) {
                desc = "缺少数据";
            } else if (result == TextToSpeech.LANG_NOT_SUPPORTED) {
                desc = "暂不支持";
            }
            languageList.add(new Language(mLanguageArray[i], desc));
        }
        // 下面把该引擎对各语言的支持情况展示到列表视图上
        ListView lv_language = findViewById(R.id.lv_language);
        LanguageListAdapter adapter = new LanguageListAdapter(this, languageList);
        lv_language.setAdapter(adapter);
    }

}

二、文字转语音

既然明确了一个引擎能够支持哪些语言,接下来就可以大胆设置朗读的语言了,并且设置好语言后,还得提供对应的文字才可以,下面是一个语音播报页面的实例

中文普通话播报

英文版播报 

可以在下拉框中选择自己想要朗读的语言 

 代码如下

Java类

package com.example.voice;

import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.example.voice.bean.Language;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public class SpeechComposeActivity extends AppCompatActivity {
    private final static String TAG = "SpeechComposeActivity";
    private TextToSpeech mSpeech; // 声明一个文字转语音对象
    private EditText et_tts; // 声明一个编辑框对象
    private List<TextToSpeech.EngineInfo> mEngineList; // 语音引擎列表

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_speech_compose);
        et_tts = findViewById(R.id.et_tts);
        findViewById(R.id.btn_read).setOnClickListener(v -> {
            String content = et_tts.getText().toString();
            // 开始朗读指定文本
            int result = mSpeech.speak(content, TextToSpeech.QUEUE_FLUSH, null, null);
            String desc = String.format("朗读%s", result==TextToSpeech.SUCCESS?"成功":"失败");
            Toast.makeText(this, desc, Toast.LENGTH_SHORT).show();
        });
        // 创建一个文字转语音对象,初始化结果在监听器的onInit方法中返回
        mSpeech = new TextToSpeech(this, mListener);
    }

    // 创建一个文字转语音的初始化监听器实例
    private TextToSpeech.OnInitListener mListener = status -> {
        if (status == TextToSpeech.SUCCESS) { // 初始化成功
            if (mEngineList == null) { // 首次初始化
                mEngineList = mSpeech.getEngines(); // 获取系统支持的所有语音引擎
                initEngineSpinner(); // 初始化语音引擎下拉框
            }
            initLanguageSpinner(); // 初始化语言下拉框
        }
    };

    // 初始化语音引擎下拉框
    private void initEngineSpinner() {
        String[] engineArray = new String[mEngineList.size()];
        for(int i=0; i<mEngineList.size(); i++) {
            engineArray[i] = mEngineList.get(i).label;
        }
        ArrayAdapter<String> engineAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, engineArray);
        Spinner sp_engine = findViewById(R.id.sp_engine);
        sp_engine.setPrompt("请选择语音引擎");
        sp_engine.setAdapter(engineAdapter);
        sp_engine.setOnItemSelectedListener(new EngineSelectedListener());
        sp_engine.setSelection(0);
    }

    private class EngineSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            recycleSpeech(); // 回收文字转语音对象
            // 创建指定语音引擎的文字转语音对象
            mSpeech = new TextToSpeech(SpeechComposeActivity.this, mListener,
                    mEngineList.get(arg2).name);
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

    // 回收文字转语音对象
    private void recycleSpeech() {
        if (mSpeech != null) {
            mSpeech.stop(); // 停止文字转语音
            mSpeech.shutdown(); // 关闭文字转语音
            mSpeech = null;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        recycleSpeech(); // 回收文字转语音对象
    }

    private String[] mLanguageArray = {"中文普通话", "英语", "法语", "德语", "意大利语"};
    private Locale[] mLocaleArray = { Locale.CHINA, Locale.ENGLISH, Locale.FRENCH, Locale.GERMAN, Locale.ITALIAN };
    private String[] mValidLanguageArray; // 当前引擎支持的语言名称数组
    private Locale[] mValidLocaleArray; // 当前引擎支持的语言类型数组
    private String mTextCN = "离离原上草,一岁一枯荣。野火烧不尽,春风吹又生。";
    private String mTextEN = "Hello World. Nice to meet you. This is a TTS demo.";

    // 初始化语言下拉框
    private void initLanguageSpinner() {
        List<Language> languageList = new ArrayList<>();
        // 下面遍历语言数组,从中挑选出当前引擎所支持的语言列表
        for (int i=0; i<mLanguageArray.length; i++) {
            // 设置朗读语言。通过检查方法的返回值,判断引擎是否支持该语言
            int result = mSpeech.setLanguage(mLocaleArray[i]);
            Log.d(TAG, "language="+mLanguageArray[i]+",result="+result);
            if (result != TextToSpeech.LANG_MISSING_DATA
                    && result != TextToSpeech.LANG_NOT_SUPPORTED) { // 语言可用
                languageList.add(new Language(mLanguageArray[i], mLocaleArray[i]));
            }
        }
        mValidLanguageArray = new String[languageList.size()];
        mValidLocaleArray = new Locale[languageList.size()];
        for(int i=0; i<languageList.size(); i++) {
            mValidLanguageArray[i] = languageList.get(i).name;
            mValidLocaleArray[i] = languageList.get(i).locale;
        }
        // 下面初始化语言下拉框
        ArrayAdapter<String> languageAdapter = new ArrayAdapter<>(this,
                R.layout.item_select, mValidLanguageArray);
        Spinner sp_language = findViewById(R.id.sp_language);
        sp_language.setPrompt("请选择朗读语言");
        sp_language.setAdapter(languageAdapter);
        sp_language.setOnItemSelectedListener(new LanguageSelectedListener());
        sp_language.setSelection(0);
    }

    private class LanguageSelectedListener implements AdapterView.OnItemSelectedListener {
        public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
            if (mValidLocaleArray[arg2]==Locale.CHINA) { // 汉语
                et_tts.setText(mTextCN);
            } else { // 其他语言
                et_tts.setText(mTextEN);
            }
            mSpeech.setLanguage(mValidLocaleArray[arg2]); // 设置选中的朗读语言
        }

        public void onNothingSelected(AdapterView<?> arg0) {}
    }

}

三、原生的语音识别

Android提供了语音识别器SpeechRecognizer 该工具常用方法如下

isRecognitionAvailable  检查系统是否支持原生的语音识别

createSpeechRecognizer 创建原生的语音识别器对象

setRecognitionListener 设置语音识别监听器

startListening 开始语音识别

stopListening 停止语音识别

cancel 取消语音识别

destroy 销毁语音识别器

识别结果监听器提供了许多回调方法,其中onResults方法可获得识别后的文本信息,然而每个引擎对文本结果的包装结构不尽相同,比如百度语音返回JSON格式的字符串,而讯飞语音返回字符串列表,为此要分别尝试几种格式的文本识别  效果如下

 

 结果如下 点击开始识别后对着麦克风说话 停止识别后则会自动输出识别内容

此处连接真机测试更佳 模拟机可能没有麦克风~~~

 代码如下

java类

package com.example.voice;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.provider.Settings;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.util.Log;
import android.widget.Button;
import android.widget.TextView;

import org.json.JSONArray;
import org.json.JSONObject;

import java.util.List;
import java.util.Locale;

@SuppressLint("SetTextI18n")
public class SpeechRecognizeActivity extends AppCompatActivity implements RecognitionListener {
    private final static String TAG = "SpeechRecognizeActivity";
    private TextView tv_result; // 声明一个文本视图对象
    private Button btn_recognize; // 声明一个按钮对象
    private SpeechRecognizer mRecognizer; // 声明一个语音识别对象
    private boolean isRecognizing = false; // 是否正在识别

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_speech_recognize);
        tv_result = findViewById(R.id.tv_result);
        btn_recognize = findViewById(R.id.btn_recognize);
        // 检查系统是否支持原生的语音识别
        boolean enable = SpeechRecognizer.isRecognitionAvailable(this);
        if (enable) {
            initRecognize(); // 初始化语音识别
        } else {
            tv_result.setText("原生的语音识别服务不可用");
            btn_recognize.setEnabled(false);
            btn_recognize.setTextColor(Color.GRAY);
        }
    }

    // 初始化语音识别
    private void initRecognize() {
        String serviceComponent = Settings.Secure.getString(
                getContentResolver(), "voice_recognition_service");
        // 获得系统内置的语音识别服务
        ComponentName component = ComponentName.unflattenFromString(serviceComponent);
        Log.d(TAG, "getPackageName="+component.getPackageName()+",getClassName="+component.getClassName());
        tv_result.setText("原生的语音识别服务采用"+component.getPackageName()
                +"里的服务"+component.getClassName());
        // 创建原生的语音识别器对象
        mRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
        mRecognizer.setRecognitionListener(this); // 设置语音识别监听器
        btn_recognize.setOnClickListener(v -> {
            if (!isRecognizing) { // 未在识别
                Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
                intent.putExtra(RecognizerIntent.EXTRA_PARTIAL_RESULTS, true);
                intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.CHINA);
                intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                        RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
                intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);
                mRecognizer.startListening(intent); // 开始语音识别
            } else { // 正在识别
                mRecognizer.stopListening(); // 停止语音识别
                //mRecognizer.cancel(); // 取消语音识别
            }
            isRecognizing = !isRecognizing;
            btn_recognize.setText(isRecognizing?"停止识别":"开始识别");
        });
    }

    @Override
    public void onReadyForSpeech(Bundle params) {}

    @Override
    public void onBeginningOfSpeech() {}

    @Override
    public void onRmsChanged(float rmsdB) {}

    @Override
    public void onBufferReceived(byte[] buffer) {}

    @Override
    public void onEndOfSpeech() {}

    @Override
    public void onError(int error) {
        Log.d(TAG, "Recognize error:"+error);
    }

    @Override
    public void onResults(Bundle results) {
        Log.d(TAG, "onResults Start");
        String desc = "";
        String key = SpeechRecognizer.RESULTS_RECOGNITION;
        try { // 百度语音分支
            String result = results.getString(key);
            Log.d(TAG, "result="+result);
            JSONObject object = new JSONObject(result);
            String recognizeResult = object.getString("recognizeResult");
            JSONArray recognizeArray = new JSONArray(recognizeResult);
            for (int i=0; i<recognizeArray.length(); i++) {
                JSONObject item = (JSONObject) recognizeArray.get(i);
                String se_query = item.getString("se_query");
                desc = desc + "\n" + se_query;
                Log.d(TAG, "desc="+desc);
            }
        } catch (Exception e) { // 讯飞语音分支
            e.printStackTrace();
            List<String> resultList = results.getStringArrayList(key);
            for (String str : resultList) {
                desc = desc + "\n" + str;
                Log.d(TAG, "desc="+desc);
            }
        }
        tv_result.setText("识别到的文字为:"+desc);
        Log.d(TAG, "onResults End");
    }

    @Override
    public void onPartialResults(Bundle partialResults) {
        Log.d(TAG, "onPartialResults");
    }

    @Override
    public void onEvent(int eventType, Bundle params) {}

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mRecognizer != null) {
            mRecognizer.destroy(); // 销毁语音识别器
        }
    }

}

创作不易 觉得有帮助请点赞关注收藏~~~

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

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

相关文章

一款客服系统有哪些必备的功能模块?

为了提升客户服务质量&#xff0c;和客户更好地进行沟通&#xff0c;越来越多的企业配置了客服系统。那一款优秀的客服系统需要配置哪些功能模块呢&#xff1f; 1、支持多渠道接入 新媒体的快速发展使得企业有机会通过更多的渠道和客户进行联系&#xff0c;比如公众号、微博、…

java环境安装与配置

这篇文章只是为了以后我配置环境方便而写 1&#xff0c;点击网址&#xff0c;进入Oracle官网 然后参照Java JDK下载安装及环境配置超详细图文教程 2&#xff0c;安装之后如果目录里没有jre文件夹 参考Jdk中没有jre文件夹怎么办&#xff1f; ①简单点就是&#xff0c;管理员模式…

京东零售大数据云原生平台化实践

分享嘉宾&#xff1a;吴维伟 京东 架构工程师 编辑整理&#xff1a;陈妃君 深圳大学 出品社区&#xff1a;DataFun 导读&#xff1a;随着业务调整和集群资源整合需求&#xff0c;大数据系统中集群数据迁移复杂混乱。本文将以京东大数据平台为例&#xff0c;介绍京东近一年在数…

HTML+CSS+JS制作一个迅雷看看电影网页设计实例 ,排版整洁,内容丰富,主题鲜明,简单的网页制作期末作业

HTML实例网页代码, 本实例适合于初学HTML的同学。该实例里面有设置了css的样式设置&#xff0c;有div的样式格局&#xff0c;这个实例比较全面&#xff0c;有助于同学的学习,本文将介绍如何通过从头开始设计个人网站并将其转换为代码的过程来实践设计。 文章目录一、网页介绍一…

FreeCAD二次开发-基于PyQT对话框与FC交互的开发

版本 FreeCAD0.18.2+PyCharm Community 2020.3.3 演示效果 环境搭建步骤 1.先安装好FreeCAD和PyCharm 2.添加环境变量 点击确定,全部关掉。 3.测试变量是否生效(CMD打开控制台,输入python回车) 弹出如下,说明可以进入FreeCAD自带的python解释器 4.创建工作台Workbench(…

Bridge Champ:Jelurida实践PlaytoOwn的Web 3社交游戏

Play-to-Own 为什么能引领Web3游戏 Web 3游戏将进入“Play-to-Own”的游戏新时代。解锁游戏中的经济活动将极大地扩大游戏产业的TAM&#xff0c;并加速价值创造。 以Axie Infinity为例&#xff0c;Axie普及了P2E模式&#xff0c;其DAU从2021年初的1万增长到峰值的300万&#…

基于遗传算法的微电网经济运行优化matlab程序

基于遗传算法的微电网经济运行优化matlab程序 摘 要: 微电网作为智能电网的一部分&#xff0c;是分布式电源接入电网的一种有效手段&#xff0c;微电网经济运行是其中一个重要研究方面。考察微电网经济性&#xff0c;通常是从最小运行成本和最小环境污染物排放成本两方面入手进…

Git clone时报错: OpenSSL SSL_read: Connection was reset, errno 10054

有段时间没有在GitHub上clone代码了&#xff0c;今天git clone&#xff1a; https://github.com/xxxxxx 居然直接给我抛出了错误&#xff1a; GitHub clone时,报错:Connection was reset, errno 10054 咦&#xff1f;这是什么鬼&#xff1f;然后想起以前clone时用的git地址…

[附源码]Python计算机毕业设计高校党建信息平台

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

秒杀微服务实现抢购代金券功能

文章目录需求分析秒杀场景的解决方案数据库表设计代金券表抢购活动表订单表创建秒杀服务pom依赖配置文件关系型数据库实现代金券秒杀相关实体引入抢购代金券活动信息代金券订单信息Rest配置类全局异常处理添加代金券秒杀活动代金券活动实体代金券活动Mapper->SeckillVoucher…

【技术分享】Python脚本实现BJTU校园网自动登录

文章目录1.背景介绍2.登录分析3.代码分析4.源代码1.背景介绍 BJTU的校园网连接好以后需要输入账号和密码才能正确登录&#xff0c;如下图所示。整个流程比较繁琐&#xff0c;尤其是很多服务器、工作站是无图形化的系统&#xff0c;大部分时间需要SSH连接&#xff0c;所以通过界…

【Rust 日报】2022-11-25 Rust 真的要上天了!

Rust 真的要上天了&#xff01;Gama 将发射太阳帆宇宙飞船&#xff0c;并且是公开将 Rust 送入太空的公司之一。是的&#xff0c;我们在太空中&#xff01;详情&#xff1a;https://twitter.com/AeroRust/status/1596052251650686976Redox OS 0.8.0 现已发布&#xff01;自从 0…

【POJ No. 2352】数星星 Stars

【POJ No. 2352】数星星 Stars 北大OJ 题目地址 【题意】 星星由平面上的点表示&#xff0c;星星的等级为纵横坐标均不超过自己的星星数量&#xff08;不包括自己&#xff09;。下图中&#xff0c; 5号星的等级为3&#xff08;纵横坐标均不超过5号星的星星有3颗&#xff1a;1…

Java(一)--- DOS,文档注释,代码规范

目录 一、开发注意事项 二、文档注释 1、基本格式 2、如何生成对应文档注释 三、Java代码规范 四、DOS 一、开发注意事项 Java应用程序的执行入口是main0方法。它有固定的书写格式:public static void main(Stringl] args){...}一个源文件中最多只能有一个public类。其它类…

ALU,半加器,全加器,减法电路

目录 &#xff08;1&#xff09;ALU(Arithmetic Logical Unit) &#xff08;2&#xff09;半加器(Half adder) &#xff08;3&#xff09;全加器(Full Adder) &#xff08;5&#xff09;二进制数的加法电路 &#xff08;6&#xff09;二进制数的减法电路 &#xff08;7&…

绿色信贷数据合集(更新至2021年)

1. 2007-2021年国有大型商业银行和全国股份制商业银行绿色信贷数据 1、数据来源&#xff1a;公司年报和可持续发展报告以及社会责任报告 2、时间跨度&#xff1a;2007-2021年 3、区域范围&#xff1a;36家国有大型商业银行和全国股份制商业银行 4、指标说明&#xff1a; 包…

Linux线程安全

目录 一.Linux线程互斥 1.1互斥相关概念 1.2互斥量mutex 1.3互斥量接口 1.4互斥量原理 二.可重入与线程安全 三.常见锁的概念 四. Linux线程同步 4.1同步概念与竞态条件 4.2条件变量 一.Linux线程互斥 1.1互斥相关概念 临界资源&#xff1a;多线程执行流共享的资源就…

Head First设计模式(阅读笔记)-05.单例模式

巧克力工厂 巧克力工厂需要将牛奶和巧克力混合&#xff0c;因此需要一个巧克力锅炉&#xff0c;具体代码如下&#xff1a; public class ChocolateBoiler{private boolean empty; // 判断是否为空private boolean boiled; // 判断是否煮沸public ChocolateBoiler(){ // 刚开…

这样的萌妹,谁不爱呢?

今日主线任务夺回 秋雅 学妹黑马萌妹来喽&#xff01;黑马教室环境如何&#xff1f;宿舍是否舒适&#xff1f;食堂有啥菜系&#xff1f;这个视频里统统有~学妹上线不靠套路&#xff0c;全凭走心带你在线云游黑马校园↓↓↓之前有很多粉丝来私聊播妞&#xff0c;想详细了解黑马校…

某大厂领导发邮件,怒斥员工“21点没人加班”,要求员工反思!

注意&#xff0c;又有奇葩领导出没。近日&#xff0c;有网友爆出恒生电子某领导发邮件“反思”21&#xff1a;00后没人上班&#xff0c;该领导说&#xff0c;当时自己脑子里冒出了几个念头&#xff1a;1.这些小组的工作任务都已经按时保质保量完成了吗&#xff1f;各项研发指标…