精华内容
下载资源
问答
  • 常见的二十种软件测试方法详解(史上最全)

    千次阅读 多人点赞 2021-01-27 22:15:57
    一.单元测试(模块测试) 单元测试是对软件组成单元...测试内容:模块接口测试(测试模块里面的参数传递是否正确)、局部数据结构测试(测试变量的作用域范围)、路径测试(if-else 判断必须覆盖所有分支)、错误处理

    一.单元测试(模块测试)

    单元测试是对软件组成单元进行测试。其目的是检验软件组成单位的正确性。测试对象是:模块。

    对模块进行测试,单独的一个模块测试,属于静态测试的一类

    • 测试阶段:编码后或者编码前(TDD)
    • 测试对象:最小模块
    • 测试人员:白盒测试工程师或开发工程师(测源码)
    • 测试依据:代码和注释+详细设计文档
    • 测试方法:白盒测试(因为要测源码)
    • 测试内容:模块接口测试(测试模块里面的参数传递是否正确)、局部数据结构测试(测试变量的作用域范围)、路径测试(if-else 判断必须覆盖所有分支)、错误处理测试、边界测试( for 循环)

    二.集成测试

    集成测试也称联合测试,将程序模块采用适当的集成策略组装起来,对系统的接口(白盒测试)以及集成后的功能(黑盒测试进行正确性检测的一种测试。集成主要目的是检查软件单位之间的接口是否正确。

    • 测试阶段:一般单元测试之后进行
    • 测试对象:模块间的接口
    • 测试人员:白盒测试工程师或开发工程师
    • 测试依据:单元测试的模块+概要设计文档
    • 测试方法:黑盒测试与白盒测试相结合
    • 测试内容:模块之间数据传输、模块之间功能冲突、模块组装功能正确性、全局数据结构、单模块缺陷对系统的影响

    三.系统测试

    将软件系统看成是一个系统的测试。包括对功能、性能以及软件所运行的软硬件环境进行测试。时间大部分在系统测试执行阶段,包括回归测试和冒烟测试。

    • 测试阶段:集成测试通过之后
    • 测试对象:整个系统(软、硬件)
    • 测试人员:黑盒测试工程师(对功能测试)
    • 测试依据:需求规格说明文档
    • 测试方法:黑盒测试
    • 测试内容:功能、界面、可靠性、易用性、性能、兼容性、安全性等
    • 回归测试(Regression Testing)

    四.回归测试

    回归测试是指修改了旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。

    有了代码修改后就进行回归测试,根据测试阶段确定回归范围。

    在整个软件测试过程中占有很大的工作量比重,软件开发的各个阶段都会进行多次回归测试。随着系统的庞大,回归测试的成本越来越大,通过选择正确的回归测试策略来改进回归测试的效率和有效性是很有意义的。

    五.冒烟测试

    这一术语源自硬件行业。
    对一个硬件或硬件组件进行更改或修复后,直接给设备加电。如果没有冒烟,则该组件就通过了测试。也可以理解为该种测试耗时短,仅用一袋烟功夫足够了。

    冒烟测试的对象是每一个新编译的需要正式测试的软件版本,目的是确认软件基本功能正常,可以进行后续的正式测试工作。冒烟测试的执行者是版本编译人员。

    概念:对核心主干流程进行测试,如果成功,就认为成功
    作用:判断是否接受测试的标准,若核心主干都走不通,那么直接打下去

    六.验收测试

    买到新手机,一般会有7天包退,一个月包换,我们会尽量在7天内把手机的所有功能都试一遍。

    验收测试是部署软件之前的最后一个测试操作。它是技术测试的最后一个阶段,也称为交付测试。验收测试的目的是确保软件准备就绪,按照项目合同、任务书、双方约定的验收依据文档,向软件购买都展示该软件系统满足原始需求。

    • 测试阶段:系统测试通过之后
    • 测试对象:整个系统(包括软硬件)。
    • 测试人员:主要是最终用户或者需求方。
    • 测试依据:用户需求、验收标准
    • 测试方法:黑盒测试(对功能进行测试)
    • 测试内容:同系统测试(功能…各类文档等)

    七.静态测试(不运行程序本身,测试文档)

    静态测试是指不运行被测程序本身,仅通过分析或检查源程序的语法、结构、过程、接口等来检查程序的正确性。‘对需求规格说明书、软件设计说明书、源程序做结构分析、流程图分析、符号执行来找错。

    八.动态测试

    动态测试方法是指通过运行被测程序,检查运行结果与预期结果的差异,并分析运行效率、正确性和健壮性等性能。大多数软件测试工作都属于动态测试。

    九.手工测试

    就是由人去一个一个的输入测试用例,然后观察结果,和机器测试相对应,属于比较原始但是不可缺少的一个步骤。

    总结优缺点:
    (1)优点:自动化无法替代探索性测试、发散思维结果的测试。
    (2)缺点:执行效率慢,量大易错。

    十.自动化测试

    就是在预设条件下运行系统或应用程序,评估运行结果,预先条件应包括正常条件和异常条件。

    简单说自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。

    自动化实施步骤:
    1.完成功能测试,版本基本稳定
    2.根据项目特性,选择适合项目的自动化工具,并搭建环境
    3.提取手工测试的测试用例转化为自动化测试的用例
    4.通过工具、代码实现自动化的构造输入,自动检测输出结果是否符合预期
    5.生成自动测试报告
    6.持续改进,脚本优化。

    十一.业务测试

    业务测试是测试人员把系统各个模块串接起来运行、模拟真实用户实际的工作流程,满足用户需求定义的功能来进行测试的过程。

    例如查看邮件:
    登录网站-输入用户名、密码登录-进入收件箱-查到邮件-点击打开-查阅-关闭邮件-退出邮箱-关闭网站
    业务测试关注需求和用户
    所有业务流程进行测试,包过主干流程,分支流程,甚至更小的流程
    测不同的业务,必须对项目的需求特别了解

    十二.界面测试

    界面测试(简称UI测试),测试用户界面的功能模块的布局是否合理、整体风格是否一致、各个控件的放置位置是否符合客户使用习惯,此外还要测试界面操作便捷性、导航简单易懂性,页面元素的可用性,界面中文字是否正确,命名是否统一,页面是否美观,文字、图片组合是否完美等。

    十三.文档测试

    在这里插入图片描述

    十四.兼容性测试

    大家经常上网,同一网站在不同的浏览器上表现不一样

    WEB测试 ;APP测试

    兼容性主要是指软件之间能否很好的运做,会不会有影响、软件和硬件之间能否发挥很好的效率工作,会不会影响导致系统的崩溃。

    • 平台测试
    • 浏览器测试
    • 软件本身能否向前或者向后兼容
    • 测试软件能否与其它相关的软件兼容
    • 数据兼容性测试

    最常见的就是浏览器的兼容性测试,不同浏览器在css,js解析上的不同会导致页面的显示不同。

    十五.易用性测试

    易用性(Useability)是交互的适应性、功能性和有效性的集中体现。

    手机拔打电话功能不放在首页,放在一个目录下边,点击三四次才可以找到拔打电话功能,这个功能好用吗?

    十六.性能测试

    检查系统是否满足需求规格说明书中规定的性能。

    通常表现在以下几个方面:

    • 对资源利用(如内存、处理机周期等)进行的精确度量
    • 对执行间隔
    • 日志事件(如中断,报错)
    • 响应时间
    • 吞吐量(TPS)
    • 辅助存储区(例如缓冲区、工作区的大小等)
    • 处理精度等进行的监测

    十七.易用性测试

    易用性(Useability)是交互的适应性、功能性和有效性的集中体现。易用性属于人体工程学的范畴,人体工程学(ergonomics)是一门将日常使用的东西设计为易于使用和实用性强的学科。

    手机拔打电话功能不放在首页,放在一个目录下边,点击三四次才可以找到拔打电话功能,这个功能好用吗?

    在某些大厂会有专门的部门来进行易用性测试,又叫用户体验测试。

    十八. 安装测试

    测试程序的安装、卸载
    典型的是app的安装、卸载

    十九.安全测试

    安全测试是一个相对独立的领域,需要更多的专业知识。例如web的安全测试,需要熟悉各种网络协议
    TCP\HTTP,防火墙,CDN,熟悉各种操作系统的漏洞,熟悉路由器等。从软件来说,熟悉各种攻击手段,例如
    SQL注入、Xss等。
    作为web入门测试,可以IBM的appscan。

    二十.内存泄漏测试

    电脑打开的东西太多,机器反应慢甚至死机,重启之后就好了,过会同样的问题出现

    很多软件系统都存在内存泄露的问题,尤其是缺乏自动垃圾回收机制的“非托管”语言 编写的程序,例如C、CH、Delphi等。从用户使用的角度来看,内存泄露本身不会造成什 么危害,一般用户可能根本不会感觉到内存泄露的存在。但是内存泄露是会累积的,只要执 行的次数足够多,最终会耗尽所有可用内存,使软件的执行越来越慢,最后停止响应。可以 把这种软件的问题比喻成软件的“慢性病”。

    造成内存泄露的原因有很多,最常见的有以下几种。

    1.分配完内存之后忘了回收。
    2.程序写法有问题,造成没办法回收。
    3.某些API函数的使用不正确,造成内存泄露。
    4.没有及时释放。

    内存泄漏的检测:
    1、对于不同的程序可以使用不同的方法来进行内存泄露的检查,还可以使用一些专门的工具来进行内存问题的检查,例如MemProof. AQTime、Purify、BundsChecker等。 有些开发工具本身就带有内存问题检查机制.要确保程序员在编写程序和编译程序的时候打开这些功能。
    2、通过代码扫描分析工具来检查

    展开全文
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    Java和C++的区别 Oracle JDK 和 OpenJDK 的对比 基础语法 数据类型 Java有哪些数据类型 switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上 用最有效率的方法计算 2 乘以 8 Math.round...

    Java面试总结(2021优化版)已发布在个人微信公众号【技术人成长之路】,优化版首先修正了读者反馈的部分答案存在的错误,同时根据最新面试总结,删除了低频问题,添加了一些常见面试题,对文章进行了精简优化,欢迎大家关注!😊😊

    【技术人成长之路】,助力技术人成长!更多精彩文章第一时间在公众号发布哦!

    文章目录

    Java面试总结汇总,整理了包括Java基础知识,集合容器,并发编程,JVM,常用开源框架Spring,MyBatis,数据库,中间件等,包含了作为一个Java工程师在面试中需要用到或者可能用到的绝大部分知识。欢迎大家阅读,本人见识有限,写的博客难免有错误或者疏忽的地方,还望各位大佬指点,在此表示感激不尽。文章持续更新中…

    序号内容链接地址
    1Java基础知识面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390612
    2Java集合容器面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588551
    3Java异常面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390689
    4并发编程面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104863992
    5JVM面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390752
    6Spring面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397516
    7Spring MVC面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397427
    8Spring Boot面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397299
    9Spring Cloud面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397367
    10MyBatis面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/101292950
    11Redis面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/103522351
    12MySQL数据库面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104778621
    13消息中间件MQ与RabbitMQ面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588612
    14Dubbo面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104390006
    15Linux面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104588679
    16Tomcat面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397665
    17ZooKeeper面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104397719
    18Netty面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/104391081
    19架构设计&分布式&数据结构与算法面试题(2020最新版)https://thinkwon.blog.csdn.net/article/details/105870730

    Java概述

    何为编程

    编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程。

    为了使计算机能够理解人的意图,人类就必须要将需解决的问题的思路、方法、和手段通过计算机能够理解的形式告诉计算机,使得计算机能够根据人的指令一步一步去工作,完成某种特定的任务。这种人和计算机之间交流的过程就是编程。

    什么是Java

    Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。

    jdk1.5之后的三大版本

    • Java SE(J2SE,Java 2 Platform Standard Edition,标准版)
      Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。Java SE 包含了支持 Java Web 服务开发的类,并为Java EE和Java ME提供基础。
    • Java EE(J2EE,Java 2 Platform Enterprise Edition,企业版)
      Java EE 以前称为 J2EE。企业版本帮助开发和部署可移植、健壮、可伸缩且安全的服务器端Java 应用程序。Java EE 是在 Java SE 的基础上构建的,它提供 Web 服务、组件模型、管理和通信 API,可以用来实现企业级的面向服务体系结构(service-oriented architecture,SOA)和 Web2.0应用程序。2018年2月,Eclipse 宣布正式将 JavaEE 更名为 JakartaEE
    • Java ME(J2ME,Java 2 Platform Micro Edition,微型版)
      Java ME 以前称为 J2ME。Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境。Java ME 包括灵活的用户界面、健壮的安全模型、许多内置的网络协议以及对可以动态下载的连网和离线应用程序的丰富支持。基于 Java ME 规范的应用程序只需编写一次,就可以用于许多设备,而且可以利用每个设备的本机功能。

    JVM、JRE和JDK的关系

    JVM
    Java Virtual Machine是Java虚拟机,Java程序需要运行在虚拟机上,不同的平台有自己的虚拟机,因此Java语言可以实现跨平台。

    JRE
    Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要是java.lang包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等,系统缺省加载这个包

    如果想要运行一个开发好的Java程序,计算机中只需要安装JRE即可。

    JDK
    Java Development Kit是提供给Java开发人员使用的,其中包含了Java的开发工具,也包括了JRE。所以安装了JDK,就无需再单独安装JRE了。其中的开发工具:编译工具(javac.exe),打包工具(jar.exe)等

    JVM&JRE&JDK关系图

    什么是跨平台性?原理是什么

    所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行。

    实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序。

    Java语言有哪些特点

    简单易学(Java语言的语法与C语言和C++语言很接近)

    面向对象(封装,继承,多态)

    平台无关性(Java虚拟机实现平台无关性)

    支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的)

    支持多线程(多线程机制使应用程序在同一时间并行执行多项任)

    健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等)

    安全性

    什么是字节码?采用字节码的最大好处是什么

    字节码:Java源代码经过虚拟机编译器编译后产生的文件(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。

    采用字节码的好处

    Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

    先看下java中的编译器和解释器

    Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中,这种供虚拟机理解的代码叫做字节码(即扩展为.class的文件),它不面向任何特定的处理器,只面向虚拟机。每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行,这就是上面提到的Java的特点的编译与解释并存的解释。

    Java源代码---->编译器---->jvm可执行的Java字节码(即虚拟指令)---->jvm---->jvm中解释器----->机器可执行的二进制机器码---->程序运行。
    

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

    一个程序中可以有多个类,但只能有一个类是主类。在Java应用程序中,这个主类是指包含main()方法的类。而在Java小程序中,这个主类是一个继承自系统类JApplet或Applet的子类。应用程序的主类不一定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口点。

    Java应用程序与小程序之间有那些差别?

    简单说应用程序是从主线程启动(也就是main()方法)。applet小程序没有main方法,主要是嵌在浏览器页面上运行(调用init()线程或者run()来启动),嵌入浏览器这点跟flash的小游戏类似。

    Java和C++的区别

    我知道很多人没学过C++,但是面试官就是没事喜欢拿咱们Java和C++比呀!没办法!!!就算没学过C++,也要记下来!

    • 都是面向对象的语言,都支持封装、继承和多态
    • Java不提供指针来直接访问内存,程序内存更加安全
    • Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
    • Java有自动内存管理机制,不需要程序员手动释放无用内存

    Oracle JDK 和 OpenJDK 的对比

    1. Oracle JDK版本将每三年发布一次,而OpenJDK版本每三个月发布一次;

    2. OpenJDK 是一个参考模型并且是完全开源的,而Oracle JDK是OpenJDK的一个实现,并不是完全开源的;

    3. Oracle JDK 比 OpenJDK 更稳定。OpenJDK和Oracle JDK的代码几乎相同,但Oracle JDK有更多的类和一些错误修复。因此,如果您想开发企业/商业软件,我建议您选择Oracle JDK,因为它经过了彻底的测试和稳定。某些情况下,有些人提到在使用OpenJDK 可能会遇到了许多应用程序崩溃的问题,但是,只需切换到Oracle JDK就可以解决问题;

    4. 在响应性和JVM性能方面,Oracle JDK与OpenJDK相比提供了更好的性能;

    5. Oracle JDK不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本;

    6. Oracle JDK根据二进制代码许可协议获得许可,而OpenJDK根据GPL v2许可获得许可。

    基础语法

    数据类型

    Java有哪些数据类型

    定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。

    分类

    • 基本数据类型
      • 数值型
        • 整数类型(byte,short,int,long)
        • 浮点类型(float,double)
      • 字符型(char)
      • 布尔型(boolean)
    • 引用数据类型
      • 类(class)
      • 接口(interface)
      • 数组([])

    Java基本数据类型图

    switch 是否能作用在 byte 上,是否能作用在 long 上,是否能作用在 String 上

    在 Java 5 以前,switch(expr)中,expr 只能是 byte、short、char、int。从 Java5 开始,Java 中引入了枚举类型,expr 也可以是 enum 类型,从 Java 7 开始,expr 还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。

    用最有效率的方法计算 2 乘以 8

    2 << 3(左移 3 位相当于乘以 2 的 3 次方,右移 3 位相当于除以 2 的 3 次方)。

    Math.round(11.5) 等于多少?Math.round(-11.5)等于多少

    Math.round(11.5)的返回值是 12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加 0.5 然后进行下取整。

    float f=3.4;是否正确

    不正确。3.4 是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成 float f =3.4F;。

    short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗

    对于 short s1 = 1; s1 = s1 + 1;由于 1 是 int 类型,因此 s1+1 运算结果也是 int型,需要强制转换类型才能赋值给 short 型。

    而 short s1 = 1; s1 += 1;可以正确编译,因为 s1+= 1;相当于 s1 = (short(s1 + 1);其中有隐含的强制类型转换。

    编码

    Java语言采用何种编码方案?有何特点?

    Java语言采用Unicode编码标准,Unicode(标准码),它为每个字符制订了一个唯一的数值,因此在任何的语言,平台,程序都可以放心的使用。

    注释

    什么Java注释

    定义:用于解释说明程序的文字

    分类

    • 单行注释
      格式: // 注释文字
    • 多行注释
      格式: /* 注释文字 */
    • 文档注释
      格式:/** 注释文字 */

    作用

    在程序中,尤其是复杂的程序中,适当地加入注释可以增加程序的可读性,有利于程序的修改、调试和交流。注释的内容在程序编译的时候会被忽视,不会产生目标代码,注释的部分不会对程序的执行结果产生任何影响。

    注意事项:多行和文档注释都不能嵌套使用。

    访问修饰符

    访问修饰符 public,private,protected,以及不写(默认)时的区别

    定义:Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。

    分类

    private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
    default (即缺省,什么也不写,不使用任何关键字): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
    protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
    public : 对所有类可见。使用对象:类、接口、变量、方法

    访问修饰符图

    运算符

    &和&&的区别

    &运算符有两种用法:(1)按位与;(2)逻辑与。

    &&运算符是短路与运算。逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true 整个表达式的值才是 true。&&之所以称为短路运算,是因为如果&&左边的表达式的值是 false,右边的表达式会被直接短路掉,不会进行运算。

    注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。

    关键字

    Java 有没有 goto

    goto 是 Java 中的保留字,在目前版本的 Java 中没有使用。

    final 有什么用?

    用于修饰类、属性和方法;

    • 被final修饰的类不可以被继承
    • 被final修饰的方法不可以被重写
    • 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的

    final finally finalize区别

    • final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表
      示该变量是一个常量不能被重新赋值。
    • finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块
      中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。
    • finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调
      用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的
      最后判断。

    this关键字的用法

    this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。

    this的用法在java中大体可以分为3种:

    1.普通的直接引用,this相当于是指向当前对象本身。

    2.形参与成员名字重名,用this来区分:

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

    3.引用本类的构造函数

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

    super关键字的用法

    super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。

    super也有三种用法:

    1.普通的直接引用

    与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。

    2.子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分

    class Person{
        protected String name;
     
        public Person(String name) {
            this.name = name;
        }
     
    }
     
    class Student extends Person{
        private String name;
     
        public Student(String name, String name1) {
            super(name);
            this.name = name1;
        }
     
        public void getInfo(){
            System.out.println(this.name);      //Child
            System.out.println(super.name);     //Father
        }
     
    }
    
    public class Test {
        public static void main(String[] args) {
           Student s1 = new Student("Father","Child");
           s1.getInfo();
     
        }
    }
    

    3.引用父类构造函数

    3、引用父类构造函数

    • super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
    • this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。

    this与super的区别

    • super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
    • this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
    • super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。
    • super()和this()均需放在构造方法内第一行。
    • 尽管可以用this调用一个构造器,但却不能调用两个。
    • this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
    • this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
    • 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

    static存在的主要意义

    static的主要意义是在于创建独立于具体对象的域变量或者方法。以致于即使没有创建对象,也能使用属性和调用方法

    static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

    为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

    static的独特之处

    1、被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法不属于任何一个实例对象,而是被类的实例对象所共享

    怎么理解 “被类的实例对象所共享” 这句话呢?就是说,一个类的静态成员,它是属于大伙的【大伙指的是这个类的多个对象实例,我们都知道一个类可以创建多个实例!】,所有的类对象共享的,不像成员变量是自个的【自个指的是这个类的单个实例对象】…我觉得我已经讲的很通俗了,你明白了咩?

    2、在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。

    3、static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的!

    4、被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。

    static应用场景

    因为static是被类的实例对象所共享,因此如果某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量

    因此比较常见的static应用场景有:

    1、修饰成员变量 2、修饰成员方法 3、静态代码块 4、修饰类【只能修饰内部类也就是静态内部类】 5、静态导包

    static注意事项

    1、静态只能访问静态。 2、非静态既可以访问非静态的,也可以访问静态的。

    流程控制语句

    break ,continue ,return 的区别及作用

    break 跳出总上一层循环,不再执行循环(结束当前的循环体)

    continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件)

    return 程序返回,不再执行下面的代码(结束当前的方法 直接返回)

    在 Java 中,如何跳出当前的多重嵌套循环

    在Java中,要想跳出多重循环,可以在外面的循环语句前定义一个标号,然后在里层循环体的代码中使用带有标号的break 语句,即可跳出外层循环。例如:

    public static void main(String[] args) {
        ok:
        for (int i = 0; i < 10; i++) {
            for (int j = 0; j < 10; j++) {
                System.out.println("i=" + i + ",j=" + j);
                if (j == 5) {
                    break ok;
                }
    
            }
        }
    }
    

    面向对象

    面向对象概述

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

    面向过程

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

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

    面向对象

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

    缺点:性能比面向过程低

    面向过程是具体化的,流程化的,解决一个问题,你需要一步一步的分析,一步一步的实现。

    面向对象是模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据也拥有解决问题的方法。需要什么功能直接使用就可以了,不必去一步一步的实现,至于这个功能是如何实现的,管我们什么事?我们会用就可以了。

    面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。

    面向对象三大特性

    面向对象的特征有哪些方面

    面向对象的特征主要有以下几个方面

    抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

    封装

    封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。

    继承

    继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。

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

    1. 子类拥有父类非 private 的属性和方法。

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

    3. 子类可以用自己的方式实现父类的方法。(以后介绍)。

    多态

    所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

    在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

    其中Java 面向对象编程三大特性:封装 继承 多态

    封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式,将变化隔离,便于使用,提高复用性和安全性。

    继承:继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承可以提高代码复用性。继承是多态的前提。

    关于继承如下 3 点请记住

    1. 子类拥有父类非 private 的属性和方法。

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

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

    多态性:父类或接口定义的引用变量可以指向子类或具体实现类的实例对象。提高了程序的拓展性。

    在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。

    方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。

    一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:

    • 方法重写(子类继承父类并重写父类中已有的或抽象的方法);
    • 对象造型(用父类型引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

    什么是多态机制?Java语言是如何实现多态的?

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

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

    多态的实现

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

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

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

    向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

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

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

    面向对象五大基本原则是什么(可选)

    • 单一职责原则SRP(Single Responsibility Principle)
      类的功能要单一,不能包罗万象,跟杂货铺似的。
    • 开放封闭原则OCP(Open-Close Principle)
      一个模块对于拓展是开放的,对于修改是封闭的,想要增加功能热烈欢迎,想要修改,哼,一万个不乐意。
    • 里式替换原则LSP(the Liskov Substitution Principle LSP)
      子类可以替换父类出现在父类能够出现的任何地方。比如你能代表你爸去你姥姥家干活。哈哈~~
    • 依赖倒置原则DIP(the Dependency Inversion Principle DIP)
      高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。就是你出国要说你是中国人,而不能说你是哪个村子的。比如说中国人是抽象的,下面有具体的xx省,xx市,xx县。你要依赖的抽象是中国人,而不是你是xx村的。
    • 接口分离原则ISP(the Interface Segregation Principle ISP)
      设计时采用多个与特定客户类有关的接口比采用一个通用的接口要好。就比如一个手机拥有打电话,看视频,玩游戏等功能,把这几个功能拆分成不同的接口,比在一个接口里要好的多。

    类与接口

    抽象类和接口的对比

    抽象类是用来捕捉子类的通用特性的。接口是抽象方法的集合。

    从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。

    相同点

    • 接口和抽象类都不能实例化
    • 都位于继承的顶端,用于被其他实现或继承
    • 都包含抽象方法,其子类都必须覆写这些抽象方法

    不同点

    参数抽象类接口
    声明抽象类使用abstract关键字声明接口使用interface关键字声明
    实现子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现子类使用implements关键字来实现接口。它需要提供接口中所有声明的方法的实现
    构造器抽象类可以有构造器接口不能有构造器
    访问修饰符抽象类中的方法可以是任意访问修饰符接口方法默认修饰符是public。并且不允许定义为 private 或者 protected
    多继承一个类最多只能继承一个抽象类一个类可以实现多个接口
    字段声明抽象类的字段声明可以是任意的接口的字段默认都是 static 和 final 的

    备注:Java8中接口中引入默认方法和静态方法,以此来减少抽象类和接口之间的差异。

    现在,我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。

    接口和抽象类各有优缺点,在接口和抽象类的选择上,必须遵守这样一个原则:

    • 行为模型应该总是通过接口而不是抽象类定义,所以通常是优先选用接口,尽量少用抽象类。
    • 选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用的功能。

    普通类和抽象类有哪些区别?

    • 普通类不能包含抽象方法,抽象类可以包含抽象方法。
    • 抽象类不能直接实例化,普通类可以直接实例化。

    抽象类能使用 final 修饰吗?

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

    创建一个对象用什么关键字?对象实例与对象引用有何不同?

    new关键字,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)

    变量与方法

    成员变量与局部变量的区别有哪些

    变量:在程序执行的过程中,在某个范围内其值可以发生改变的量。从本质上讲,变量其实是内存中的一小块区域

    成员变量:方法外部,类内部定义的变量

    局部变量:类的方法中的变量。

    成员变量和局部变量的区别

    作用域

    成员变量:针对整个类有效。
    局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)

    存储位置

    成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
    局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。当方法调用完,或者语句结束后,就自动释放。

    生命周期

    成员变量:随着对象的创建而存在,随着对象的消失而消失
    局部变量:当方法调用完,或者语句结束后,就自动释放。

    初始值

    成员变量:有默认初始值。

    局部变量:没有默认初始值,使用前必须赋值。

    使用原则

    在使用变量时需要遵循的原则为:就近原则
    首先在局部范围找,有就使用;接着在成员位置找。

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

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

    在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?

    帮助子类做初始化工作。

    一个类的构造方法的作用是什么?若一个类没有声明构造方法,改程序能正确执行吗?为什么?

    主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。

    构造方法有哪些特性?

    名字与类名相同;

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

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

    静态变量和实例变量区别

    静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。

    实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。

    静态变量与普通变量区别

    static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

    还有一点就是static成员变量的初始化顺序按照定义的顺序进行初始化。

    静态方法和实例方法有何不同?

    静态方法和实例方法的区别主要体现在两个方面:

    1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
    2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制

    在一个静态方法内调用一个非静态成员为什么是非法的?

    由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。

    什么是方法的返回值?返回值的作用是什么?

    方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的操作!

    内部类

    什么是内部类?

    在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是内部类。内部类本身就是类的一个属性,与其他属性定义方式一致。

    内部类的分类有哪些

    内部类可以分为四种:成员内部类、局部内部类、匿名内部类和静态内部类

    静态内部类

    定义在类内部的静态类,就是静态内部类。

    public class Outer {
    
        private static int radius = 1;
    
        static class StaticInner {
            public void visit() {
                System.out.println("visit outer static  variable:" + radius);
            }
        }
    }
    

    静态内部类可以访问外部类所有的静态变量,而不可访问外部类的非静态变量;静态内部类的创建方式,new 外部类.静态内部类(),如下:

    Outer.StaticInner inner = new Outer.StaticInner();
    inner.visit();
    
    成员内部类

    定义在类内部,成员位置上的非静态类,就是成员内部类。

    public class Outer {
    
        private static  int radius = 1;
        private int count =2;
        
         class Inner {
            public void visit() {
                System.out.println("visit outer static  variable:" + radius);
                System.out.println("visit outer   variable:" + count);
            }
        }
    }
    

    成员内部类可以访问外部类所有的变量和方法,包括静态和非静态,私有和公有。成员内部类依赖于外部类的实例,它的创建方式外部类实例.new 内部类(),如下:

    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();
    inner.visit();
    
    局部内部类

    定义在方法中的内部类,就是局部内部类。

    public class Outer {
    
        private  int out_a = 1;
        private static int STATIC_b = 2;
    
        public void testFunctionClass(){
            int inner_c =3;
            class Inner {
                private void fun(){
                    System.out.println(out_a);
                    System.out.println(STATIC_b);
                    System.out.println(inner_c);
                }
            }
            Inner  inner = new Inner();
            inner.fun();
        }
        public static void testStaticFunctionClass(){
            int d =3;
            class Inner {
                private void fun(){
                    // System.out.println(out_a); 编译错误,定义在静态方法中的局部类不可以访问外部类的实例变量
                    System.out.println(STATIC_b);
                    System.out.println(d);
                }
            }
            Inner  inner = new Inner();
            inner.fun();
        }
    }
    

    定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。局部内部类的创建方式,在对应方法内,new 内部类(),如下:

     public static void testStaticFunctionClass(){
        class Inner {
        }
        Inner  inner = new Inner();
     }
    
    匿名内部类

    匿名内部类就是没有名字的内部类,日常开发中使用的比较多。

    public class Outer {
    
        private void test(final int i) {
            new Service() {
                public void method() {
                    for (int j = 0; j < i; j++) {
                        System.out.println("匿名内部类" );
                    }
                }
            }.method();
        }
     }
     //匿名内部类必须继承或实现一个已有的接口 
     interface Service{
        void method();
    }
    

    除了没有名字,匿名内部类还有以下特点:

    • 匿名内部类必须继承一个抽象类或者实现一个接口。
    • 匿名内部类不能定义任何静态成员和静态方法。
    • 当所在的方法的形参需要被匿名内部类使用时,必须声明为 final。
    • 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。

    匿名内部类创建方式:

    new/接口{ 
      //匿名内部类实现部分
    }
    

    内部类的优点

    我们为什么要使用内部类呢?因为它有以下优点:

    • 一个内部类对象可以访问创建它的外部类对象的内容,包括私有数据!
    • 内部类不为同一包的其他类所见,具有很好的封装性;
    • 内部类有效实现了“多重继承”,优化 java 单继承的缺陷。
    • 匿名内部类可以很方便的定义回调。

    内部类有哪些应用场景

    1. 一些多算法场合
    2. 解决一些非面向对象的语句块。
    3. 适当使用内部类,使得代码更加灵活和富有扩展性。
    4. 当某个类除了它的外部类,不再被其他的类使用时。

    局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final?

    局部内部类和匿名内部类访问局部变量的时候,为什么变量必须要加上final呢?它内部原理是什么呢?

    先看这段代码:

    public class Outer {
    
        void outMethod(){
            final int a =10;
            class Inner {
                void innerMethod(){
                    System.out.println(a);
                }
    
            }
        }
    }
    

    以上例子,为什么要加final呢?是因为生命周期不一致, 局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁。而局部内部类对局部变量的引用依然存在,如果局部内部类要调用局部变量时,就会出错。加了final,可以确保局部内部类使用的变量与外层的局部变量区分开,解决了这个问题。

    内部类相关,看程序说出运行结果

    public class Outer {
        private int age = 12;
    
        class Inner {
            private int age = 13;
            public void print() {
                int age = 14;
                System.out.println("局部变量:" + age);
                System.out.println("内部类变量:" + this.age);
                System.out.println("外部类变量:" + Outer.this.age);
            }
        }
    
        public static void main(String[] args) {
            Outer.Inner in = new Outer().new Inner();
            in.print();
        }
    
    }
    

    运行结果:

    局部变量:14
    内部类变量:13
    外部类变量:12
    

    重写与重载

    构造器(constructor)是否可被重写(override)

    构造器不能被继承,因此不能被重写,但可以被重载。

    重载(Overload)和重写(Override)的区别。重载的方法能否根据返回类型进行区分?

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

    重载:发生在同一个类中,方法名相同参数列表不同(参数类型不同、个数不同、顺序不同),与方法返回值和访问修饰符无关,即重载的方法不能根据返回类型进行区分

    重写:发生在父子类中,方法名、参数列表必须相同,返回值小于等于父类,抛出的异常小于等于父类,访问修饰符大于等于父类(里氏代换原则);如果父类方法访问修饰符为private则子类中就不是重写。

    对象相等判断

    == 和 equals 的区别是什么

    == : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型 == 比较的是值,引用数据类型 == 比较的是内存地址)

    equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

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

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

    举个例子:

    public class test1 {
        public static void main(String[] args) {
            String a = new String("ab"); // a 为一个引用
            String b = new String("ab"); // b为另一个引用,对象的内容一样
            String aa = "ab"; // 放在常量池中
            String bb = "ab"; // 从常量池中查找
            if (aa == bb) // true
                System.out.println("aa==bb");
            if (a == b) // false,非同一对象
                System.out.println("a==b");
            if (a.equals(b)) // true
                System.out.println("aEQb");
            if (42 == 42.0) { // true
                System.out.println("true");
            }
        }
    }
    

    说明:

    • String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
    • 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。

    hashCode 与 equals (重要)

    HashSet如何检查重复

    两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?

    hashCode和equals方法的关系

    面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”

    hashCode()介绍

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

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

    为什么要有 hashCode

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

    当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。

    hashCode()与equals()的相关规定

    如果两个对象相等,则hashcode一定也是相同的

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

    两个对象有相同的hashcode值,它们也不一定是相等的

    因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖

    hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

    对象的相等与指向他们的引用相等,两者有什么不同?

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

    值传递

    当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递

    是值传递。Java 语言的方法调用只支持参数的值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的属性可以在被调用过程中被改变,但对对象引用的改变是不会影响到调用者的

    为什么 Java 中只有值传递

    首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。 它用来描述各种程序设计语言(不只是Java)中方法参数传递方式。

    Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。

    下面通过 3 个例子来给大家说明

    example 1

    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 20;
    
        swap(num1, num2);
    
        System.out.println("num1 = " + num1);
        System.out.println("num2 = " + num2);
    }
    
    public static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    
        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
    

    结果

    a = 20
    b = 10
    num1 = 10
    num2 = 20
    

    解析

    img

    在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。

    通过上面例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样,请看 example2.

    example 2

        public static void main(String[] args) {
            int[] arr = { 1, 2, 3, 4, 5 };
            System.out.println(arr[0]);
            change(arr);
            System.out.println(arr[0]);
        }
    
        public static void change(int[] array) {
            // 将数组的第一个元素变为0
            array[0] = 0;
        }
    

    结果

    1
    0
    

    解析

    img

    array 被初始化 arr 的拷贝也就是一个对象的引用,也就是说 array 和 arr 指向的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象上。

    通过 example2 我们已经看到,实现一个改变对象参数状态的方法并不是一件难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时引用同一个对象。

    很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调用和引用调用。有些程序员(甚至本书的作者)认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。

    example 3

    public class Test {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Student s1 = new Student("小张");
            Student s2 = new Student("小李");
            Test.swap(s1, s2);
            System.out.println("s1:" + s1.getName());
            System.out.println("s2:" + s2.getName());
        }
    
        public static void swap(Student x, Student y) {
            Student temp = x;
            x = y;
            y = temp;
            System.out.println("x:" + x.getName());
            System.out.println("y:" + y.getName());
        }
    }
    

    结果

    x:小李
    y:小张
    s1:小张
    s2:小李
    

    解析

    交换之前:

    img

    交换之后:

    img

    通过上面两张图可以很清晰的看出: 方法并没有改变存储在变量 s1 和 s2 中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝

    总结

    Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按值传递的。

    下面再总结一下Java中方法参数的使用情况:

    • 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
    • 一个方法可以改变一个对象参数的状态。
    • 一个方法不能让对象参数引用一个新的对象。

    值传递和引用传递有什么区别

    值传递:指的是在方法调用时,传递的参数是按值的拷贝传递,传递的是值的拷贝,也就是说传递后就互不相关了。

    引用传递:指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。

    Java包

    JDK 中常用的包有哪些

    • java.lang:这个是系统的基础类;
    • java.io:这里面是所有输入输出有关的类,比如文件操作等;
    • java.nio:为了完善 io 包中的功能,提高 io 包中性能而写的一个新包;
    • java.net:这里面是与网络有关的类;
    • java.util:这个是系统辅助类,特别是集合类;
    • java.sql:这个是数据库操作的类。

    import java和javax有什么区别

    刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来说使用。然而随着时间的推移,javax 逐渐的扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包将是太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准API的一部分。

    所以,实际上java和javax没有区别。这都是一个名字。

    IO流

    java 中 IO 流分为几种?

    • 按照流的流向分,可以分为输入流和输出流;
    • 按照操作单元划分,可以划分为字节流和字符流;
    • 按照流的角色划分为节点流和处理流。

    Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

    • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
    • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

    按操作方式分类结构图:

    IO-操作方式分类

    按操作对象分类结构图:

    IO-操作对象分类

    BIO,NIO,AIO 有什么区别?

    简答

    • BIO:Block IO 同步阻塞式 IO,就是我们平常使用的传统 IO,它的特点是模式简单使用方便,并发处理能力低。
    • NIO:Non IO 同步非阻塞 IO,是传统 IO 的升级,客户端和服务器端通过 Channel(通道)通讯,实现了多路复用。
    • AIO:Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO ,异步 IO 的操作基于事件和回调机制。

    详细回答

    • BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
    • NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 SocketServerSocket 相对应的 SocketChannelServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发
    • AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。

    Files的常用方法都有哪些?

    • Files. exists():检测文件路径是否存在。
    • Files. createFile():创建文件。
    • Files. createDirectory():创建文件夹。
    • Files. delete():删除一个文件或目录。
    • Files. copy():复制文件。
    • Files. move():移动文件。
    • Files. size():查看文件个数。
    • Files. read():读取文件。
    • Files. write():写入文件。

    反射

    什么是反射机制?

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

    静态编译和动态编译

    • **静态编译:**在编译时确定类型,绑定对象
    • **动态编译:**运行时确定类型,绑定对象

    反射机制优缺点

    • 优点: 运行期类型的判断,动态加载类,提高代码灵活度。
    • 缺点: 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。

    反射机制的应用场景有哪些?

    反射是框架设计的灵魂。

    在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。

    举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性

    Java获取反射的三种方法

    1.通过new对象实现反射机制 2.通过路径实现反射机制 3.通过类名实现反射机制

    public class Student {
        private int id;
        String name;
        protected boolean sex;
        public float score;
    }
    
    public class Get {
        //获取反射机制三种方式
        public static void main(String[] args) throws ClassNotFoundException {
            //方式一(通过建立对象)
            Student stu = new Student();
            Class classobj1 = stu.getClass();
            System.out.println(classobj1.getName());
            //方式二(所在通过路径-相对路径)
            Class classobj2 = Class.forName("fanshe.Student");
            System.out.println(classobj2.getName());
            //方式三(通过类名)
            Class classobj3 = Student.class;
            System.out.println(classobj3.getName());
        }
    }
    

    网络编程

    网络编程的面试题可以查看我的这篇文章重学TCP/IP协议和三次握手四次挥手,内容不仅包括TCP/IP协议和三次握手四次挥手的知识,还包括计算机网络体系结构,HTTP协议,get请求和post请求区别,session和cookie的区别等,欢迎大家阅读。

    常用API

    String相关

    字符型常量和字符串常量的区别

    1. 形式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的若干个字符
    2. 含义上: 字符常量相当于一个整形值(ASCII值),可以参加表达式运算 字符串常量代表一个地址值(该字符串在内存中存放位置)
    3. 占内存大小 字符常量只占两个字节 字符串常量占若干个字节(至少一个字符结束标志)

    什么是字符串常量池?

    字符串常量池位于堆内存中,专门用来存储字符串常量,可以提高内存的使用率,避免开辟多块空间存储相同的字符串,在创建字符串时 JVM 会首先检查字符串常量池,如果该字符串已经存在池中,则返回它的引用,如果不存在,则实例化一个字符串放到池中,并返回其引用。

    String 是最基本的数据类型吗

    不是。Java 中的基本数据类型只有 8 个 :byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(referencetype),Java 5 以后引入的枚举类型也算是一种比较特殊的引用类型。

    这是很基础的东西,但是很多初学者却容易忽视,Java 的 8 种基本数据类型中不包括 String,基本数据类型中用来描述文本数据的是 char,但是它只能表示单个字符,比如 ‘a’,‘好’ 之类的,如果要描述一段文本,就需要用多个 char 类型的变量,也就是一个 char 类型数组,比如“你好” 就是长度为2的数组 char[] chars = {‘你’,‘好’};

    但是使用数组过于麻烦,所以就有了 String,String 底层就是一个 char 类型的数组,只是使用的时候开发者不需要直接操作底层数组,用更加简便的方式即可完成对字符串的使用。

    String有哪些特性

    • 不变性:String 是只读字符串,是一个典型的 immutable 对象,对它进行任何操作,其实都是创建一个新的对象,再把引用指向该对象。不变模式的主要作用在于当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性。

    • 常量池优化:String 对象创建之后,会在字符串常量池中进行缓存,如果下次创建同样的对象时,会直接返回缓存的引用。

    • final:使用 final 来定义 String 类,表示 String 类不能被继承,提高了系统的安全性。

    String为什么是不可变的吗?

    简单来说就是String类利用了final修饰的char类型数组存储字符,源码如下图所以:

    /** The value is used for character storage. */
    private final char value[];
    

    String真的是不可变的吗?

    我觉得如果别人问这个问题的话,回答不可变就可以了。 下面只是给大家看两个有代表性的例子:

    1) String不可变但不代表引用不可以变

    String str = "Hello";
    str = str + " World";
    System.out.println("str=" + str);
    

    结果:

    str=Hello World
    

    解析:

    实际上,原来String的内容是不变的,只是str由原来指向"Hello"的内存地址转为指向"Hello World"的内存地址而已,也就是说多开辟了一块内存区域给"Hello World"字符串。

    2) 通过反射是可以修改所谓的“不可变”对象

    // 创建字符串"Hello World", 并赋给引用s
    String s = "Hello World";
    
    System.out.println("s = " + s); // Hello World
    
    // 获取String类中的value字段
    Field valueFieldOfString = String.class.getDeclaredField("value");
    
    // 改变value属性的访问权限
    valueFieldOfString.setAccessible(true);
    
    // 获取s对象上的value属性的值
    char[] value = (char[]) valueFieldOfString.get(s);
    
    // 改变value所引用的数组中的第5个字符
    value[5] = '_';
    
    System.out.println("s = " + s); // Hello_World
    

    结果:

    s = Hello World
    s = Hello_World
    

    解析:

    用反射可以访问私有成员, 然后反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。但是一般我们不会这么做,这里只是简单提一下有这个东西。

    是否可以继承 String 类

    String 类是 final 类,不可以被继承。

    String str="i"与 String str=new String(“i”)一样吗?

    不一样,因为内存的分配方式不一样。String str="i"的方式,java 虚拟机会将其分配到常量池中;而 String str=new String(“i”) 则会被分到堆内存中。

    String s = new String(“xyz”);创建了几个字符串对象

    两个对象,一个是静态区的"xyz",一个是用new创建在堆上的对象。

    String str1 = "hello"; //str1指向静态区
    String str2 = new String("hello");  //str2指向堆上的对象
    String str3 = "hello";
    String str4 = new String("hello");
    System.out.println(str1.equals(str2)); //true
    System.out.println(str2.equals(str4)); //true
    System.out.println(str1 == str3); //true
    System.out.println(str1 == str2); //false
    System.out.println(str2 == str4); //false
    System.out.println(str2 == "hello"); //false
    str2 = str1;
    System.out.println(str2 == "hello"); //true
    

    如何将字符串反转?

    使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。

    示例代码:

    // StringBuffer reverse
    StringBuffer stringBuffer = new StringBuffer();
    stringBuffer. append("abcdefg");
    System. out. println(stringBuffer. reverse()); // gfedcba
    // StringBuilder reverse
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder. append("abcdefg");
    System. out. println(stringBuilder. reverse()); // gfedcba
    

    数组有没有 length()方法?String 有没有 length()方法

    数组没有 length()方法 ,有 length 的属性。String 有 length()方法。JavaScript中,获得字符串的长度是通过 length 属性得到的,这一点容易和 Java 混淆。

    String 类的常用方法都有那些?

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

    在使用 HashMap 的时候,用 String 做 key 有什么好处?

    HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快。

    String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的

    可变性

    String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。

    线程安全性

    String中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。

    性能

    每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StirngBuilder 相比使用StringBuffer 仅能获得10%~15% 左右的性能提升,但却要冒多线程不安全的风险。

    对于三者使用的总结

    如果要操作少量的数据用 = String

    单线程操作字符串缓冲区 下操作大量数据 = StringBuilder

    多线程操作字符串缓冲区 下操作大量数据 = StringBuffer

    Date相关

    包装类相关

    自动装箱与拆箱

    装箱:将基本类型用它们对应的引用类型包装起来;

    拆箱:将包装类型转换为基本数据类型;

    int 和 Integer 有什么区别

    Java 是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类型,但是为了能够将这些基本数据类型当成对象操作,Java 为每一个基本数据类型都引入了对应的包装类型(wrapper class),int 的包装类就是 Integer,从 Java 5 开始引入了自动装箱/拆箱机制,使得二者可以相互转换。

    Java 为每个原始类型提供了包装类型:

    原始类型: boolean,char,byte,short,int,long,float,double

    包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double

    Integer a= 127 与 Integer b = 127相等吗

    对于对象引用类型:==比较的是对象的内存地址。
    对于基本数据类型:==比较的是值。

    如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用常量池中的Integer对象,超过范围 a1==b1的结果是false

    public static void main(String[] args) {
        Integer a = new Integer(3);
        Integer b = 3;  // 将3自动装箱成Integer类型
        int c = 3;
        System.out.println(a == b); // false 两个引用没有引用同一对象
        System.out.println(a == c); // true a自动拆箱成int类型再和c比较
        System.out.println(b == c); // true
    
        Integer a1 = 128;
        Integer b1 = 128;
        System.out.println(a1 == b1); // false
    
        Integer a2 = 127;
        Integer b2 = 127;
        System.out.println(a2 == b2); // true
    }
    

    常用工具类库

    单元测试

    日志

    展开全文
  • 需求挖掘的种方法

    万次阅读 2018-12-05 19:01:28
    这里分享13挖掘需求的方法。 2.1 从公司业务方向挖掘需求   很多时候,一个产品的第一个需求基本上都来自于公司内部,当然也不排除有些产品大牛具有很高的市场嗅觉,领导制定产品战略。 产品经理...

    很多刚入门的产品经理都会将大量的时间放在产品原型上面,以为画好原型就能够胜任产品经理的职位了。而我们也经常能够在一些产品经理的招聘中任职要求中写着:“熟悉使用Axure、Mindmanager、Viso,能够单独画产品原型”。于是很多人都是从学习使用Axure画原型开始走上产品之路的。

    然而,如果从做产品的流程来看,需求才是做产品的第一步。而且一个好的需求也是做出优秀产品成就优秀产品经理的前提。

     

    一、什么是需求

    圈内人经常会说到“需求”、“痛点”这样的词语,那么究竟什么是“需求”呢?我先来举个栗子:

    01

     

    1、我想吃饭,但是我不想自己煮饭,也不想出去吃,怎样才能做到不用煮饭、不用出去也能吃到好吃的饭菜?

    用户有在线点餐的需求,于是有了饿了么、百度外卖、美团外卖等外卖APP。

    2、我想唱K,但是我不想去KTV,我想随时随地唱歌并且能够与不同地方的人一起合唱,怎样才能做到这样呢?

    用户有在线唱K和在线合唱的需求,于是有了唱吧、K歌之王、K歌达人、酷狗K歌等手机K歌APP。

    除了这些场景之外,还有很多人会对某款产品有着各种各样的不满,吐槽这些产品的种种不好和使用时的不爽,这些槽点和问题也是一种需求。

    问题就是需求,而产品最终就是要解决问题的。另外,目前越来越多的人都向往着最求更加优质的生活,因此,欲望也是需求,而产品族中就是要满足用户欲望,让用户更爽的。

    《掌握需求过程》这本书中说到:“需求是产品必须完成的事以及必须具备的品质”,是在构建产品前需要发现的东西。

    1.1 需求的对产品和产品经理的重要性

     

    02

     

    需求挖掘是在构建产品前的重要一个环节,对产品具有非常重要的作用。在上一篇文章《一组漫画告诉你,互联网产品经理是什么概念》中曾说到,一个好的产品需要有需求、有优势、有利益。明确需求,挖掘用户痛点,才能让产品更加有优势;只有挖掘到了能够盈利的需求才能让产品有利益。所以说,需求是一个好产品的前提,是一个优秀产品的起点。

    《代码大全》的作者Steve McConnell报告说,60%的错误存在于设计中,而Jerry Weinberg证实了这一点。他的统计数据表明,60%的错误源于需求和分析活动。

    由此可见,需求对产品的构建以及对产品经理的发展是多么的重要。一个产品经理必须具备挖掘需求和分析需求的能力,即使一些大公司有专业的需求分析师,产品经理对需求的把握还是非常重要的。

    1.2 需求与产品生命周期的关系

    03

     

    在产品生命周期中,需求是一个动态变化的过程,产品在不同的阶段有着不同的需求。产品可分为:导入期、成长期、成熟期和衰退期。

    在产品的导入期中,也就是产品从0到1的阶段,产品经理需要挖掘更多基本的需求,从而满足用户的初级使用需求。在这个阶段,产品的前途并不是很明朗的,只是一个初级探索的阶段,这时候需要挖掘用户的初级需求,而不是还没能满足用户的基本需求就想着让用户体验所谓的更加“牛逼”的功能。

    在产品的成长期,也就是产品已经有了1的基础了,这时候产品应该选择性地去满足用户的其他需求,完善原有的需求,去掉不合理的需求,增加进一步满足用户的需求。而这些需求的选择也是需要挖掘和进行分析而得到的。

    在产品成熟期,产品已经在平稳的发展了,这时候的需求更加趋于理性,而用户的大部分需求都将得到满足,需求挖掘的难度也将会加大,产品经理需要关注更加细节方面的需求、体验性的需求,以及挖掘其他隐性需求。产品在成熟期的需求有一定的重复性,更多的是在原来的一些需求的基础上做更加细致的挖掘。

    在产品的衰退期,产品的活跃度逐渐下降,用户对产品的一些需求已经没有原有的激情,这时候产品经理需要考虑怎样去挖掘更多新的需求去满足用户,甚至开拓新的产品项目。例如,C2C的淘宝延伸出来的B2C天猫以及后来的企业店铺。

    1.3 需求的分类

    04

     

    产品经理了解需求的分类,在挖掘需求的时候就会更有方向性,减少遗漏需求的机会。在这里,我将需求分为三部分,总共8类,对象为用户的需求有:基本需求、易用性需求、可操作性需求;对象为产品运营的需求有:产品运营需求、政策及法律需求;对象为系统的需求有:安全性需求、性能需求、可维护和可移植性需求。

    基本需求是解决用户最基本问题的需求,是一个产品的源需求。一个产品的构建就是源于这种类型的需求来开展的。例如上面说到的外卖app和K歌app的例子,在线点餐是一个基本需求,在线K歌是一个基本需求。在挖掘这类需求的时候可以更多地从用户的使用场景、站在用户的角度去思考和挖掘。

    易用需求主要考虑的是用户体验方面的需求,方便用户使用的需求。例如,用户在点外卖的时候是否需要通过一些筛选条件去更快速地找到自己想要吃的东西?这时候可以考虑增加一些筛选条件去满足用户的需求,甚至根据用户的日常操作或者自定义的标签进行匹配推荐。

    可操作性需求是产品的操作环境,以及对该操作环境必须考虑的问题。有些需求并非是在任何场景下都适用的。例如,在构建PC端的产品,探索用户是否有定位的需求时,需要考虑这个定位功能的可操作性,因为PC电脑并没有LBS定位功能,这功能只适用手机,如果确实有定位方面的需求,那么就要考虑是否能够通过其他方式去实现,例如,通过IP跟踪,或者通过PC端和手机客户端的账号绑定与互通,利用手机app上的定位进行判断。

    运营需求主要对象为产品运营本身或者说公司的运营部门,这类需求是为了方便运营开展运营工作而设置的。例如,置顶、推荐、排行榜、数据统计等方面的需求。

    政策及法律需求是为了保证产品本身以及用户的使用不触犯法律。例如,斗鱼TV直播“造人”事件,事后江苏省公安厅网络安全保卫总队针对此事发布微博称,“你们真的挺会玩儿的……如果做不好内容审核,可以关停服务器整顿几个月”。由此可见,一个产品的政策及法律需求也是一个不可忽视的需求。UGC产品、社交产品要考虑敏感词汇过滤的需求,视频网站、直播网站要注意考虑防止色情淫秽内容传播的需求。

    在产品构建之前,除了要考虑用户需求和运营需求之外,还需要考虑系统方面的需求。

    安全性需求方面,需要考虑产品的安全保密性、支付的安全性,用户信息的安全性。举个常见的例子,很多使用短信验证码进行注册的产品都会做了防止被刷短信的功能,因为短信验证码也是一种成本,如果没有做相关的限制,很容易被使用相关程序进行刷短信,消耗公司的短信数量,从而造成一定的经济损失。涉及到购买和支付方面的产品也要注意安全性需求。还有在线视频教育的产品,如果没有考虑安全性方面的需求,很容易被别人盗取收费视频。此外,电子商务方面的产品以及金融类产品也要重视该方面的需求。

    性能需求是指功能的实现必须多快、多可靠、能处理过少处理量、多精确。之前我们公司有个数据统计后台的产品,被吐槽说翻页这个功能的体验做得不是很好,没有显示总共有多少页。我们给出的解释是,翻页的地方做显示总共有多少页的功能的话,系统需要先计算页数,然后再显示页数,而我们的数据量非常大,每次从大量的数据中查询后再显示会拖慢系统的速度。特别是后台类的产品或者比较大型的产品,更加需要考虑性能方面的系统。

    可维护和可移植性需求主要是考虑以后是否有系统维护、或者转移方面的需求。

     

    二、怎么挖掘需求

    需求这么重要,那么,怎么去挖掘需求呢?这里分享13种挖掘需求的方法。

    2.1 从公司业务方向挖掘需求

    05

     

    很多时候,一个产品的第一个需求基本上都来自于公司内部,当然也不排除有些产品大牛具有很高的市场嗅觉,领导制定产品战略。

    产品经理可以从公司业务方向去挖掘产品需求。上面说到,问题就是需求,欲望就是需求,对公司来说,公司遇到的问题就是需求,公司的愿景也是需求。因此,需求也可以从公司内部去挖掘。

    以我目前所在的公司为例,我们公司今年非常重视无端手游方面的业务,将推出多款H5游戏。然而,由于H5无端手游是近两年才兴起的,业内相关的运营渠道(游戏运营平台)并不是很多,高质量的渠道更是非常少。很多渠道都是这两年才开始建立的,公司需要一个平台去承载即将推出的大量H5游戏。H5技术的兴起,在游戏行业将会催生更多的H5游戏,而游戏行业一直有“渠道为王”的说法,H5游戏的兴起需要有相应的平台配合游戏的运营,所以说,公司业务方向给了我们产品的需求。除了公司的需求之外,老板或者领导因为长期对市场的接触和观察,也会有一些看法或者方向,而这也是我们的一个需求来源。还有来自运营、市场或者客服部门方面的需求来源。

    需要注意的是,从公司业务方向、老板/领导、运营、市场、客服等获取的需求,并不能直接当成最终的需求,还需要更深一层去挖掘需求,并且最终评审确定最终需求。

    2.2 通过头脑风暴挖掘需求

    11

     

    当一群人围绕一个特定的兴趣领域产生新观点的时候,这种情境就叫做头脑风暴。头脑风暴能够让一大群人自由地思考,迸发更多新思想和新观点。头脑风暴也是挖掘需求的一个常用方法。

    头脑风暴可以邀请产品经理、老板/领导、市场经理、运营经理,以及一些有深刻见解、涉猎比较广、生活阅历比较丰富的员工一起参加讨论。参与者最好有不同的阅历和学科背景,这样更容易产生更多创新的观点。

    在头脑风暴的整个过程中,需要明确讨论的目的/议题,并且要注意引导和发散思维,让所有的人都能够参与到其中,并且激发其思维。讨论时注意让参与者自由畅谈,并且不对产生的观点和说法进行任何的批评,而且产生的观点要足够多。头脑风暴是一种发散式的讨论,特别要注意对讨论内容进行详细的记录,这时候可以使用录音、录像、拍照、思维导图、excel表格等方式对整个过程进行记录,方便后期整理,避免遗漏重要观点。

    进行头脑风暴是为了挖掘多的有用的需求,因此,在头脑风暴后期,一定要对所记录下来的内容进行梳理,并且从整理的内容中提取有用的需求。

    2.3 通过文献调研挖掘需求

    作为一个互联网产品经理,应该对互联网中的事情有更多的了解。互联网行业的变化速度非常快,互联网的各种变化或许都会影响到我们的用户以及我们的产品,而互联网的各种信息也能够给我们提供更多的需求信息。

    挖掘需求的第三个方法是通过文献调研挖掘需求。这里所说的文献调研,并非仅仅局限于一些文献书籍之类的内容,它可以是一些相关的文献资料、可以是一些专业的分析报告,也可以是与之相关的各种动态。在这里,我推荐几个常看的网站,产品经理圈子相关网站——人人都是产品经理社区;TMT媒体以及创业类信息平台——36氪、虎嗅网、钛媒体、爱范儿;数据分析类网站——艾瑞网、199IT、企鹅智酷、中国互联网络信息中心。

    06

     

    这些网站有比较多的互联网信息、互联网产品信息,了解互联网动态、行业方向以及市场动态,能够帮助我们了解更多需求。在这些网站中挖掘需求时,可以用相关的关键词在这些网站搜索,找到自己想要的内容,copy下来,方便后期整理并进行分析,挖掘有用的需求。数据类的网站也是一个挖掘需求的重要渠道,各种数据、各种报告,包含着非常多有用的需求。需求的挖掘并不是随便看看就行了,建议将需要的内容保存下来,把一些报告下载下来,然后慢慢地细读,对内容进行调研分析,找出需要的需求。

    2.4 通过用户访谈挖掘需求

    user

     

    用户访谈是挖掘用户基本需求的有效方法。用户访谈的形式包括结构化和非结构化两种,结构化是指产品经理按照一定准则事先准备好一系列问题,通过用户对问题的回答来获取有关目标产品方面的内容;非结构化则是只列出一个粗糙的想法,根据访谈的具体情况来进行发挥。

    在进行用户访谈之前,怎么寻找访谈的目标用户?可以在社交平台找到一些了解目标类型的用户,例如,知乎、微博、QQ群去寻找。也可以找到竞品的用户来进行访谈,还可以是行业专家、自媒体大V、同类产品从业者。访谈对象最好是具有较高质量的目标用户,在领域内资深、对产品体验要求高、有话语权,以及擅于表达。除了这种焦点访谈形式的用户访谈之外,我们也可以约一些目标访谈对象进行一对一轻松交流,不局限在办公室内。这样的交谈方式更加轻松,或许能够获取更多的需求信息。

    不管是使用哪种交谈方式,都要注意做相应的记录,不遗漏每一个需求信息,这也为后面的需求分析提供一定的依据。使用自由一对一交流的方式的话,不是很方便不断地记录,这样会影响交谈的气氛。但是在结束交谈之后,也应该及时将刚才讨论的内容进行记录,还可以将整理好的内容发给访谈者确认,看是否有错误或者遗漏。

    2.5 通过问卷调查挖掘需求

    我们在挖掘产品需求的时候,并不能和每一个用户都进行面对面的交谈,甚至有一些关键性的访谈对象因为各种原因无法参与访谈,因此,我们还需要通过问卷调查的方式进行更大范围的调查。

    在进行问卷调查前,需要明确调查的目的,并且根据目的,有针对性地设计调查问卷,然后下发到相关的人员手中,让他们填写,再从所填写的内容中获取产品的需求信息。这里的调查问卷可以是纸质的,也可以是在线的电子版调查问卷。目前的问卷调查,线上的调查几乎是必不可少的,因为省事易操作、传播范围广、快速。目前的线上问卷调查工具网站有:麦客、问卷星、金数据等,也可以使用企业自己的调查系统进行调查。传播的渠道可以是微信公众号、微信群、QQ群或者邮箱、短信等。线下的问卷调查相对麻烦一些,可以摆摊做问卷调查,利用填写调查问卷送奖品的方式来开展。而目前更多的线下问卷调查都会与线上的调查结合,线下用二维码的形式,让被调查者扫描二维码在线上完成调查问卷的填写。

    在做调查问卷的时候,需要围绕调查目的去设计相应的问题,同时还需要注意问题的准确性,问题不能问得太过空泛或者太过虚;另外还要注意问题的长度和问题的数量,设计的问题长度应该在填写者愿意认真填写的时间长度内完成。在完成调查后,后期的统计分析也是一个非常重要的部分。

    问卷调查无法取代用户访谈在需求获取阶段的作用,其最大的不足就是缺乏灵活性,问卷调查的问题和答案具有一定的引导性,可能存在受调查者不能很好表述自己想法的限制,在某种程度上会影响结果。

    2.6 通过竞品分析挖掘需求

    竞品分析是需求挖掘的常用的方法。竞品也是经过了相关调研、探索和思考而做出来的产品,进行竞品分析,能够了解其优缺点,既能对自身产品的需求查漏补缺,也能取其精华去其糟粕。一般情况下,很多人都是以同行业同类型的产品进行竞品分析,其实我们可以用类似行业的产品进行竞品分析,有些需求或许恰好能够弥补同行产品中的某些不足。在这个跨界时代,有些需求具有一定的共性。

    我们很多时候在做竞品分析的时候,大部分能够看到的都是产品的前端展示,那么通过竞品分析如何挖掘前端的需求和后台方面的需求?

    产品前端分析,可以从一个产品的产品定位、产品结构、产品体验、产品功能、盈利模式、用户评论以及反馈去进行分析。从产品定位可以看出竞品的方向、目标用户以及模式,在这个基础上,我们可以进一步通过其他方法进行更深一步的了解和调研,从而获取相应需求。而产品结构,则可以对整个产品进行剖析,利用mindmanager将产品的信息架构图梳理出来,并对其结构进行分析。产品体验、产品功能、盈利模式的分析也能给我们一些指示,了解其产品所包含的需求。另外,在上面说到“问题就是产品”,因此,用户对竞品的评论以及反馈也是我们了解需求的一个重要方法。这些评论中可能包含有用户的问题、用户的期望或者用户的建议,这些都是我们所需要挖掘的需求。

     

    12

     

    产品后台分析以及系统、平台类的竞品分析相对前端的分析会有更大的难度。不可能有竞品会开放自己的后台去让你分析,系统、平台类的产品也是大部分是不会直接开放让你去使用的。在做这种产品的竞品分析时,我们可以从以下这几个方面去了解:演示Demo、说明文档、技术文档、开源系统、前端反推以及向程序员了解。

    有些市场化的系统,为了让大家能够更加了解其产品,所以会有演示Demo可以操作,这时候我们就可以进入该产品的Demo后台去了解该产品。很多产品连演示Demo都没有,这时候我们可以到产品官网的文档中心或者帮助中心去了解其产品说明文档、技术文档,从文档中了解竞品的相关情况。

    除了这些方法之外,我还会利用一些开源系统,在自己本地搭建一些系统,进而了解更多的后台细节,包括管理员的各种操作需求,系统的配置需求等等。如果对后台产品有一定的了解的话,我们也可以通过分析其前端,进行反推后台的相关功能和需求。还有一个方法就是多和程序员交流,不懂就请教他们,向他们了解更多技术方面的需求或者他对一些系统的了解所知道的需求。

    2.7 通过运营数据分析挖掘需求

    产品经理需要有一个非常重要的技能是数据分析能力,这个技能主要体现在需求挖掘的阶段,包括问卷调查的数据统计和分析以及运营数据的统计分析,新产品的新需求挖掘以及老产品的迭代需求挖掘。

    产品上线后,产品经理要密切关注运营数据的情况,特别是产品进行AB测试的时候,需要关注数据的变化,对数据进行统计分析得出结论。关注产品的访问量、用户数、流失率、点击率、转化率、留存率、活跃度等方面的数据。例如,如果用户数过低,就看看是否是因为注册流程过于复杂;转化率过低,检查是否是因为跳转的逻辑设计得不好还是其他问题。每一个问题的背后,或许就能够找到一些相应的需求。

    每一个产品都有一定的数据统计分析的需求,因此,产品经理在构建系统的时候就需要有数据统计分析的设计,这样对后期的产品完善和升级迭代都非常有帮助,当然,这对产品运营更是一个必不可少的功能。在挖掘产品的数据分析需求的时候,可以使用上面竞品分析中说到的方法——从演示Demo去了解。数据分析类型的需求,可以对应地从一些数据统计分析的产品Demo中去了解和分析,例如:友盟、TalkingData等。

    2.8 通过用户反馈挖掘需求

    用户反馈是一种挖掘用户基本需求以及期望需求的常用方法。产品经理能够在用户的反馈中了解到用户的使用情况,也能够通过用户的反馈了解到用户所遇到的问题,还能通过用户的反馈了解用户的想法和期望。每一个问题的背后都可能隐藏有相应的需求,因此,通过用户的反馈来挖掘用户需求的一个不错的方法。

    07

     

    收集用户反馈有哪些渠道和来源?产品内的反馈入口、产品QQ群、知乎、微博、微信、贴吧、论坛、客服等都是收集用户反馈的渠道。产品经理可以考虑铺设多个反馈的入口,让用户能够随时随地只要遇到或者想到一些问题都能够快速反馈。

    为了更加方便从用户的反馈中挖掘需求,获取大量的用户反馈数据进行分析,我们可以做一些有利于用户反馈的相关设计。在产品中加入用户反馈入口和反馈机制,让用户能够在使用产品的过程中就能够快速将遇到的一些问题和想法反馈给我们。另外,产品经理最好尽量回复用户的反馈,与用户交互,重视用户是每一个反馈,这样将能够让用户觉得他们的反馈是有用的,这样他们才会不断地反馈更多的意见和建议。另外,建立一个用户反馈引导机制也能够引导用户反馈更多有用的信息。可以通过反馈问题展示,反馈回复,采纳建议后告诉反馈者并感谢其反馈的建议,奖励被采纳建议的反馈者等方法,刺激更多的用户参与反馈。特别是产品初期,更加需要大量的用户反馈数据进行迭代需求挖掘。要想用户反馈的内容能够为自己所用,必须将用户反馈的的内容记录下来,并进行整理和分析,从而挖掘到有用的需求。

    2.9 通过搜索引擎挖掘需求

    很多时候,我们在无从下手的情况下都会通过搜索引擎去搜索一些关键词,从而获得一些灵感。确实,搜索引擎也是一种挖掘需求的方法。搜索引擎中有比较多的推广信息以及垃圾无用的信息,因此,在通过搜索引擎挖掘需求的时候注意避开这些无用的信息。我们可以分别通过泛搜索和稍微精准的搜索来进行查找,可以用多个关键词进行搭配搜索,也可以给关键词加上双引号进行搜索,这样会更加精准。另外,我们也可以使用百度自带的“搜索工具”进行更加精准的搜索。

     

    baidu_index

    baidu_need

     

    除了用与产品相关的关键词去搜索之外,百度指数也是一种挖掘需求的不错的方法。百度指数中,通过搜索关键词,可以看到到关键词的趋势研究、需求图谱、舆情洞察、人群画像,这些内容对我们进行需求挖掘非常有意义。这里简单说一些百度指数中的需求图谱。需求图谱是通过用户在搜索该词的前后的搜索行为变化中表现出来的相关检索词需求。我这里用“产品经理”的关键词来进行搜索,这里看到的是,与产品经理相关的需求有:产品经理学习与培训(包括产品经理书籍、产品经理课程/培训、产品经理学习网站)、产品经理基本了解(产品经理的职责、产品助理、产品专员、项目经理)、产品经理招聘。其中,产品经理学习与培训方面的需求是最大的,产品经理招聘的上升趋势是最大的。当然,仅仅凭借这样的一些数据并不能作为最终的需求,需求还需要更多的挖掘、调研、统计、分析综合得到。

    2.10 通过社交平台挖掘需求

    08

     

    社交平台也是挖掘需求的一个非常重要的渠道。例如,知乎、微博、百度知道、百度贴吧,这些平台都能够成为我们挖掘需求的一个渠道,另外,有些行业也有该行业的垂直社交平台的。社交平台是一个聚集了百家之言的一个地方,各种潜在用户都在社交平台中发表想法、提出问题、回答问题、讨论问题,因此,这里面有些问题正是我们想要挖掘的一些需求。

    在社交平台中挖掘需求,可以通过关键词搜索,找到相应的内容;也可以自己发起提问或者讨论,从而引导其平台内的用户进行回答和讨论;还可以通过已知的需求或者搜索的关键词,挖掘更多的长尾需求。

    上面使用百度指数了解到产品经理对学习和培训的需求量最大,在这里,我再次以“产品经理”为例,在知乎上搜索产品经理的关键词,进一步细分“产品经理”的学习和培训需求。产品经理需要哪些方面的学习和培训?在知乎上搜索的结果中有:

    1. 产品经理如何入门,没人带的情况下如何学习?——产品经理入门学习和培训,产品经理自学(书籍/在线教学视频)。

    2. 产品经理如何进行竞品分析——产品经理竞品分析学习和培训。

    3. 产品经理一般是怎么收集产品不好用之处的?——产品经理用户反馈收集方面的学习需求。

    以上仅仅作为例子来说明,如果想要更加深入地了解用户需求,还需要更加认真地进行更深一层的挖掘和扩展。

    2.11 通过场景分析挖掘需求

    产品经理经常需要考虑用户的使用场景,同样的,产品经理也能通过一些场景模拟去挖掘需求。我这里所说到的场景分析也叫用户模拟,主要是通过模拟场景以及用户,从而发现一些需求。常见的方式有:基于文本的场景模型和故事版。

     

    10

     

    下面以一款约一起运动的APP为例,简单说明一下。

    业务事件:组织一起打羽毛球

    场景:喜欢打羽毛球的朋友太少了

    背景:小李希望有更多的人一起去打

    情节1:

    动作:小李打电话邀朋友小张一起去打

    结果:小张说太远了,不愿意过去

    情节2:

    动作:小李又给朋友小敏打电话

    动作:小敏问了一下她的闺蜜小菲

    结果:小菲已经约了人,所以不去了

    结果:最熟悉的闺蜜不去,小敏也不想去了

    需求:

    1、解决共同朋友少的问题——匹配相同兴趣的朋友

    2、解决距离不一致的问题——定位附近的朋友

    3、解决一个人不想参加的问题——邀请熟悉的朋友一起报名参加

    这个模式并不是一成不变的,可以按照自己的模拟方式来开展,例如,用文字按照场景,模拟一段故事,然后对这个故事进行分析,了解这个故事场景中所需要用到的需求。

    2.12 通过现场观摩沟通挖掘需求

    俗话说:“百闻不如一见”。有些需求,我们无法通过场景模拟、搜索引擎、社交平台等方法来挖掘需求,我们不妨走到现场去看看,通过现场的观摩和在真实的场景中面对面的沟通,从而了解最真实的需求。

    2.13 培养自己的产品嗅觉

    有人问乔布斯:“如何通过市场调查了解大众需求,才能让产品如此成功?”乔布斯的回答是:“不用做调查,消费者并不知道他们需要的是什么,而苹果会告诉他们什么才是潮流!”乔布斯从来不和用户交谈就能够知道用户需求?这看起来有点神话,或者说乔布斯是神一般的产品经理。

    在此,我想说的是,乔布斯的这些传奇是有前提的。在做iPhone之前,他就已经有丰富的经验和积累了,他对用户的了解、对市场以及产品的嗅觉非常的敏锐。一些拥有丰富经验的资深产品经理很快就能够定位出相应的需求。

    而对于我们来说,我们也需要不断地积累更多的知识和经验,培养自己的产品嗅觉。从而让自己在多年后也能够快速定位出产品的需求,轻轻松松就能做出一款成功的产品。培养自己的产品嗅觉,可以参考以下下面几方面内容:

    1. 多总结。写工作笔记/博客/产品白皮书。

    2. 多看书。博览群书,阅读产品相关书籍、互联网相关书籍、商业 书籍、心理书籍、盈利模式相关书籍。

    3. 多观察互联网动态。了解互联网发展动向。

    4. 多体验各种产品。把自己当成一个测试机,了解各种产品,并分 别从用户角度和产品经理角度去思考该产品。

    5. 多逛逛各种社交平台。时刻获取各种产品灵感,最好能够记录下来。

    6. 多与圈内人交流。包括微信群、QQ群、线下活动等。

    三、如何进行需求管理

    在通过上面的方法收集到相应的需求之后,产品经理还需要懂得如何对需求进行管理。收集到需求的时候,注意建立需求池对需求进行记录和整理。

    1、建立需求池

     

    xuqiubiaoge

     

    2、需求加减法

    经过一番努力,收集了一大堆需求,如何处理?产品的需求可以说是无上限的,大量的堆积需求,会使得产品非常臃肿,而且毫无特色,而需求的过多,还会导致工期过长,拖慢了产品推出市场的进度,对产品百害而无一利。因此,产品经理需要了解产品的加减法。

    在什么时候需要加?什么时候减?在需求收集阶段,我们一直在做需求的加法,不断地增加需求的量,增加所有能够得到的需求。在进行需求分析、需求评审的时候,我们则需要不断地对需求做减法,确认了需求之后,需要对需求进行优先级排序。减掉的需求并不代表这以后都不会使用,所以记得先保留着不删。

    3、如何判断产品的优先级

    在判断产品的优先级时,一般通过KANO模型进行判断。KANO模型定义了三个层次的用户需求:基本型需求、期望型需求和兴奋型需求。基本需求是必须具备的,即使不说也应该做到,这部分需求一般是产品初期需要做的功能。期望型需求是用户期望的,用户能够较清晰地知道的。而兴奋型需求是超出用户预期的,用户不知道有这方面的需求,如果提供,用户满意度会更高。

     

    KANO2

     

    KANO模型后面还有了其他方面的一些延伸:

    • 魅力需求:用户意想不到的,如果不提供此需求,用户满意度不会降低,但当提供此需求,用户满意度会有很大提升;

    • 期望需求:当提供此需求,用户满意度会提升,当不提供此需求,用户满意度会降低;

    • 必备需求:当优化此需求,用户满意度不会提升,当不提供此需求,用户满意度会大幅降低;

    • 无差异需求:无论提供或不提供此需求,用户满意度都不会有改变,用户根本不在意;

    • 反向需求:用户根本都没有此需求,提供后用户满意度反而会下降。

    kano1

    09

     

    四、如何进行需求评审

    15

     

    并不是得到需求之后就可以由产品经理直接拍脑袋开始做产品了,我们在做收集完需求之后,在真正开始做产品之前,会有一个需求评审会议。对收集到的需求进行最终确定,避免做过多无用需求、减少需求变更的风险、保证需求质量、避免后期过多矛盾,需求评审时降低需求风险的一个重要的手段。在这个过程中会砍掉一些需求,也可能增加一些需求。

    在做需求评审之前,需要准备好需求文档以及之前整理好的需求列表等文档,还有低保真原型。邀请相关的人员参与评审,参加需求评审会议的可以有产品经理、老板/领导、运营以及市场相关人员、开发经理、测试经理或者专家等,参加的人员示具体情况而定,主要是与产品或者需求相关的人以及一些有经验、懂需求的人。为了保证需求评审能够顺利进行,最好提前做好相关的准备,这时候,原来做的一些需求分析也会在评审会上用到。产品经理要能够讲清楚需求的来源,为什么用这个需求,加入这个需求有什么意义,这个需求需要哪些配合,同类竞品是否有该需求……整个需求评审的过程,考验了产品经理对需求的熟悉程度以及对需求的判断能力。同时,参与评审的人也将会对你提出的需求提出自己的看法,是否同意该需求,并且会提出同意或者不同意该需求的理由。需求评审是多人围绕已经收集到的需求进行评审的过程,聚集大家的智慧,能够避免一个人闭门造车的局限。

    在评审会议上,产品经理可以通过事先准备的低保真原型(或者原型草图)来讲解,辅助说明,让大家更加理解这个需求以及需求以后会是怎样的样子,这样也能够让自己在讲解需求的时候更加有依有据,避免错过一些有用的需求。

    需求作为一个产品的起点,对产品的构建以及以后的发展有着重要的作用。因此,学习如何挖掘需求,如果进行需求分析,以及如何将需求转化成产品,是产品经理必须重视并且不断学习的必备技能。

    希望这些内容能够帮助到各位成长中的产品经理。

    展开全文
  • C++ 字符串 对象 ...C++ 字符串 对象 创建方法 C++ 字符串 对象 输出到控制台 C++ 字符串 拼接 C++ 字符串 方法调用 ( 栈内存对象 ) C++ 字符串 方法调用 ( 堆内存对象 ) C / C++ 字符串 完整代码示例



    C++ 字符串 对象


    C++ 字符串 :

    • 1.string 类 : C++ 中的字符串是 string 类 对象 ;
    • 2.string 类定义位置 : 该 string 类定义在 iostream 头文件中 , 不必引入另外的头文件 ;
    #include <iostream>
    



    C++ 字符串 对象 创建方法


    C++ 字符串 对象 创建方法 :

    • 1.直接赋值 : 直接使用 C 字符串赋值 ;
    	//① 使用字符串赋值
    	string string_c_plus_1 = " Hello ";
    
    • 2.构造方法 : 调用 string 构造方法 创建 string 对象 ;
      • ① 传入 string 参数 : string 构造方法可以传入 string 对象 ;
      • ② 传入 C 字符串参数 : string 构造方法也可以传入 一个 C 字符串 ;
    	//② 调用构造方法 初始化字符串
    	string string_c_plus_2(string_c_plus_1);
    	string string_c_plus_3(" World ");
    
    • 3.使用 new 分配内存 : 使用 new 为 String 对象分配一块堆内存空间 , 返回 string * 类型的指针 ;
    	//③ 使用 new 申请的内存 , 需要使用 delete 释放
    	string *string_c_plus_4 = new string(" New ");
    	delete string_c_plus_4;
    

    调用该 string* 对象的方法需要使用 -> 进行调用 ;

    堆内存使用原则 :
    ① 使用 new 申请的内存 , 需要使用 delete 释放 ;
    ② 使用 new [] 申请的数组 , 需要使用 delete[] 释放 ;
    ③ 使用 malloc 申请的内存 , 需要使用 free 释放 ;




    C++ 字符串 对象 输出到控制台


    C++ 字符串 对象 输出到控制台 :

    • 1.不能直接使用 cout 输出 : 下面的用法是错误的 ; 使用 cout 不能直接将 string 对象输出 ;
    	//这种用法是错误的
    	string string_c_plus_1 = " Hello ";
    	cout << string_c_plus_1 << endl;
    
    • 2.输出方法 : 需要将 string 对象转成 C 字符串 , 然后再输出 :
    	//调用 string 对象的 c_str() 方法 , 获取其 C 字符串 , 然后再输出到控制台
    	string string_c_plus_1 = " Hello ";
    	cout << string_c_plus_2.c_str() << endl;
    

    在 Java 中输出 String 对象 , 默认会调用其 toString 方法 , 但是在 C 中不可以直接使用 ;




    C++ 字符串 拼接


    C++ 字符串拼接 :

    • 1.使用 “+” 符号拼接 : 这里的加号进行了操作符重载 , 字符串之间相加代表了字符串的拼接操作 ;
    	//① "+" : 操作符重载 , 重新定义了 加号运算符的行为 , 
    	//		这里加号可以实现字符串拼接 , 与 Java 类似
    	string string_c_plus_5 = string_c_plus_1 + string_c_plus_3;
    
    • 2.调用 string 对象的 append 方法 : 调用 string 对象的 append() 方法 , 传入要拼接的字符串 ;
    	//② 调用 string 对象的 append 方法 , 拼接字符串
    	string string_c_plus_6 = string_c_plus_1.append( string_c_plus_3 );
    
    • 3.代码示例 :
    	//C++ 字符串拼接
    	//① "+" : 操作符重载 , 重新定义了 加号运算符的行为 , 这里加号可以实现字符串拼接 , 与 Java 类似
    	//② 调用 string 对象的 append 方法 , 拼接字符串
    	string string_c_plus_5 = string_c_plus_1 + string_c_plus_3;
    	string string_c_plus_6 = string_c_plus_1.append( string_c_plus_3 );
    
    • 4.运行结果 :
     Hello  World
     Hello  World
    

    在这里插入图片描述

    操作符重载 : 重新定义了操作符的作用 , 这里的 “+” 就是重新定义了其作用 , 拼接字符串 ;




    C++ 字符串 方法调用 ( 栈内存对象 )


    C++ 字符串 方法调用 : 该字符串 ( string ) 对象 在栈内存中 ;

    • 1.获取字符串长度 : 调用 string 对象的 size() 方法 , 即可返回字符串长度 ;
    	//① 使用字符串赋值
    	string string_c_plus_1 = " Hello ";
    	//获取 C++ 字符串长度 : 调用 string 对象的 size() 方法 , 获取字符串长度
    	int string_c_plus_1_size = string_c_plus_1.size();
    
    • 2.判断字符串是否为空 : 调用 string 对象的 empty() 方法 , 判断字符串是否为空 ;
    	//① 使用字符串赋值
    	string string_c_plus_1 = " Hello ";
    	//判断 C++ 字符串是否为空 : 调用 string 对象的 empty() 方法 ; 
    	bool string_c_plus_1_empty = string_c_plus_1.empty();
    
    • 3.代码示例 :
    	//使用字符串赋值
    	string string_c_plus_1 = " Hello ";
    	
    	//获取 C++ 字符串长度 : 调用 string 对象的 size() 方法 , 获取字符串长度
    	int string_c_plus_1_size = string_c_plus_1.size();
    	cout << "string_c_plus_1_size : " << string_c_plus_1_size << endl;
    
    	//判断 C++ 字符串是否为空 : 调用 string 对象的 empty() 方法 ; 
    	bool string_c_plus_1_empty = string_c_plus_1.empty();
    	cout << "string_c_plus_1_empty : " << string_c_plus_1_empty << endl;
    
    • 4.运行结果 :
    string_c_plus_1_size : 14
    string_c_plus_1_empty : 0
    

    在这里插入图片描述

    使用 “.” 方式调用栈内存对象的方法 ;




    C++ 字符串 方法调用 ( 堆内存对象 )


    C++ 字符串 堆内存对象 方法调用 :

    • 1.堆内存对象创建 : 使用 new 创建的 string 对象 需要在堆内存中为其分配内存 , 返回的是 string* 指针类型 ;
    	//使用 new 创建的对象 , 就不能使用 . 访问其方法和变量 , 需要使用 -> 符号进行访问 
    	// -> 相当于 (*). 运算, 先读取指针内容 , 然后访问其方法或变量
    
    	string* string_c_plus_7 = new string(" New String ");
    
    • 1.获取字符串长度 : 调用 string 对象的 size() 方法 , 即可返回字符串长度 ; 需要使用 -> 代替 . 操作 ;
    	//① 获取字符串长度 : 
    	int string_c_plus_7_size = string_c_plus_7->size();
    
    • 2.判断字符串是否为空 : 调用 string 对象的 empty() 方法 , 判断字符串是否为空 ; 需要使用 -> 代替 . 操作 ;
    	//② 判断字符串是否为空 : 
    	bool string_c_plus_7_empty = string_c_plus_7->empty();
    
    • 3.使用指针的好处 :
      • ① 扩大作用域 : 如果在栈内存中使用 , 有作用域限制 , 出了栈内存 作用域 , 该对象就无效了 ;
      • ② 方便参数传递 : 指针 大小为 4 ( 32 位系统 ) 或 8 ( 64 位系统 ) 个字节 , 其当做参数传递 比直接传递对象 ( 动辄几十上百字节甚至更高 ) 效率更高 ;
    • 4.代码示例 :
    	//使用 new 创建的对象 , 就不能使用 . 访问其方法和变量 , 需要使用 -> 符号进行访问 
    	// -> 相当于 (*). 运算, 先读取指针内容 , 然后访问其方法或变量
    
    	string* string_c_plus_7 = new string(" New String ");
    	
    	//① 获取字符串长度 : 
    	int string_c_plus_7_size = string_c_plus_7->size();
    	cout << "string_c_plus_7 : " << string_c_plus_7_size << endl;
    
    	//② 判断字符串是否为空 : 
    	bool string_c_plus_7_empty = string_c_plus_7->empty();
    	cout << "string_c_plus_7_empty : " << string_c_plus_7_empty << endl;
    
    	//释放堆内存
    	delete string_c_plus_7;
    
    	//使用指针的好处 : 
    	// ① 如果在栈内存中使用 , 有作用域限制 , 出了栈内存 作用域 , 该对象就无效了 ; 
    	// ② 指针 大小为 4 ( 32 位系统 ) 或 8 ( 64 位系统 ) 个字节 , 
    	//	  其当做参数传递 比直接传递对象 ( 动辄几十上百字节甚至更高 ) 效率更高 
    
    • 5.运行结果 :
    string_c_plus_7 : 12
    string_c_plus_7_empty : 0
    

    在这里插入图片描述




    C / C++ 字符串 完整代码示例


    // 001_CMake_1.cpp: 定义应用程序的入口点。
    //
    
    #include "001_CMake_1.h"
    #include "c_extern.h"
    
    using namespace std;
    
    //定义方法接收 int& 引用类型变量
    //并在方法中修改该变量的值
    void quote(int& b) {
    	b = 888;
    }
    
    int main()
    {
    	cout << "Hello CMake。" << endl;
    
    	//1. C C++ 兼容
    	//博客地址 : https://hanshuliang.blog.csdn.net/article/details/98840708
    	//调用 c_extern.h 头文件中定义的方法
    	//该方法定义在了 C 语言文件中
    	add(1, 2);
    
    
    	//2. 引用数据类型
    	//博客地址 : https://hanshuliang.blog.csdn.net/article/details/99239635
    	//代码 展示 流程 : 
    	//① 定义 普通 类型 变量
    	int a = 8;
    	//② 定义 引用类型变量, 格式 : 类型名称& 变量名 = 对应类型变量名称 ;
    	int& b = a;
    	//③ 调用函数传入引用类型参数 : 将引用类型传给接收引用类型的方法
    	quote(b);
    	//④ 打印引用数据类型的修改结果 , 结果是 b 被修改成了 888
    	cout << b << endl;
    
    	//引用数据类型定义与使用 : 
    	// ① 引用数据类型定义 : 类型名称& 变量名 = 对应类型变量名称 ;
    	// ② 引用数据类型的使用方法 : 直接当做原来的变量使用即可, 可以替换原来变量的位置使用
    
    	//引用类型解析 : 
    	// ① int& 是引用数据类型 , b 是 a 的引用 
    	// ② 分配一块内存存放 int 类型数据 8 , 将该内存赋予一个别名 a
    	// ③ 同时又给该内存赋予另外一个别名 b 
    
    
    	//3. 字符串使用
    	//C 字符串 表示方法 : 
    	// ① 字符数组 : 本质是 字符 数组 char[] , 这里注意字符数组要以 NULL 或 '\0' 结尾; 
    	char string_c[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
    	// ② 指针 : 使用指针形式表示字符串 , 默认末尾增加 '\0' ;
    	char* string_c_p = "hello";
    
    	//字符串打印 : 
    	// ① 打印字符串 , cout 后的 << 后可以打印 字符串 , 也可以打印变量
    	// ② 输出 cout << 字符串或变量1 << 字符串或变量2 ... << endl 可以拼接 输出信息
    	cout << "string_c : " << string_c << endl;
    	cout << "string_c_p : " << string_c_p << endl;
    
    	//C 语言中的字符串操作
    	//拷贝字符串 
    	char string_c_copy_destination[6];
    	char string_c_copy_source[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
    	// ① 参数 : strcpy 方法是拷贝字符串的方法 , 第一个参数是目标字符串 , 第二个参数是源字符串
    	// ② 作用 : 该方法是将 源字符串 拷贝到 目标字符串中
    	strcpy(string_c_copy_destination, string_c_copy_source);
    	// ③ 打印拷贝结果 : 
    	cout << "string_c_copy_destination : " << string_c_copy_destination << endl;
    
    	//拼接字符串 
    	//① 定义目标字符串 : 拼接字符串的目标字符串的大小一定要大于等于要拼接的两个字符串大小之和, 否则会报错
    	char string_c_cat_destination[30] = " cat dst ";
    	char string_c_cat_source[] = " cat src ";
    	//② 拼接字符串方法参数 : 第一个参数是目标字符串 , 第二个参数是源字符串
    	//③ 目标字符串大小 : 注意 目标字符串的 大小一定要大于 两个字符串实际大小
    	strcat(string_c_cat_destination, string_c_cat_source);
    	//④ 打印字符串拼接结果 : 
    	cout << "string_c_cat_destination : " << string_c_cat_destination << endl;
    
    
    	//获取字符串长度
    	//① 参数 : 传入要获取的字符串 , 该长度不含 '\0' 结尾标志
    	//② 作用 : 获取实际的字符串长度 , 即自动识别 '\0' 位置 , 获取其长度 , 与所占用的内存大小无关
    	char string_c_len[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
    	char string_c_len2[20] = { 'h', 'e', 'l', 'l', 'o', '\0' };
    	char * string_c_len3 = "hello";
    	
    	//① 字符数组长度 , 测量从开始到 '\0' 的长度, 不包括 '\0'
    	int len1 = strlen(string_c_len);
    	//② 指定大小的字符数组长度 , 结果不是指定的大小的值 , 获取的是实际字符串长度
    	int len2 = strlen(string_c_len2);
    	//③ 指针表示的字符串 , 其获取的大小是实际字符串大小, 不包含自动添加的 '\0' 
    	int len3 = strlen(string_c_len3);
    	//④ 打印 三个字符串大小
    	cout << "len1 : " << len1
    		<< " len2 : " << len2
    		<< " len3 : " << len3
    		<< endl;
    
    
    	//字符串比较
    	// ① 参数说明 : 参数是需要比较的两个字符串 , 第一个参数 str1 , 第二个参数 str2
    	// ② 对比规则 : str1 和 str2 两个字符串 , 从左到右 逐个对比 ASCII 码 大小 ; 
    	//		a. 如果 str1 等于 str2 , 返回 0; 
    	//		b. 如果 str1 > str2 , 返回值 大于 0 ;
    	//		c. 如果 str1 < str2 , 返回值 小于 0 ;
    
    	//定义需要比较的字符串
    	char* string_c_comp_1 = "Hello";
    	char* string_c_comp_2 = "Hello";
    	char* string_c_comp_3 = "hello";
    
    	// ① 两个字符串相等
    	int cmp_result_1_2 = strcmp(string_c_comp_1, string_c_comp_2);
    	// ② "Hello" 字符串 (H 对应 ASCII 72) 小于 "hello" 字符串 (h 对应 ASCII 104) , 返回值 小于 0
    	int cmp_result_1_3 = strcmp(string_c_comp_1, string_c_comp_3);
    	// ③ "hello" 字符串 (h 对应 ASCII 104) 大于 "Hello" 字符串 (H 对应 ASCII 72) , 返回值 大于 0
    	int cmp_result_3_1 = strcmp(string_c_comp_3, string_c_comp_1);
    
    	//输出字符串对比结果
    	cout << "cmp_result_1_2 : " << cmp_result_1_2 
    		<< " cmp_result_1_3 : " << cmp_result_1_3
    		<< " cmp_result_3_1 : " << cmp_result_3_1
    		<< endl;
    
    
    	// C++ string 类 : 该类定义在 iostream 头文件中
    	//创建 string 类型对象有三种方法 : 
    	//① 直接使用字符串赋值 
    	//② 调用构造方法赋值 
    	//③ 最后可以调用 new 为字符串分配一块内存
    
    	//① 使用字符串赋值
    	string string_c_plus_1 = " Hello ";
    
    	//② 调用构造方法 初始化字符串
    	string string_c_plus_2(string_c_plus_1);
    	string string_c_plus_3(" World ");
    
    	//上面的三种字符串不需要释放 , 因为其定义在栈内存中 , 下面使用 new 创建字符串的情况需要 delete 释放内存 ; 
    
    	//③ 使用 new 申请的内存 , 需要使用 delete 释放
    	string *string_c_plus_4 = new string(" New ");
    	delete string_c_plus_4;
    
    	//使用 new [] 申请的数组 , 需要使用 delete[] 释放
    	//使用 malloc 申请的内存 , 需要使用 free 释放
    
    	//C++ 字符串输出
    	//字符串对象不能直接在 cout 中输出, cout << string string_c_plus_5 << endl; 是错误的
    	//cout << string_c_plus_2 << endl;
    	//要将 string 对象打印到控制台上, 需要将其转为 C 字符串 , char* 或 char[] 才能输出
    	cout << string_c_plus_1.c_str() << endl;
    
    
    	//C++ 字符串拼接
    	//① "+" : 操作符重载 , 重新定义了 加号运算符的行为 , 这里加号可以实现字符串拼接 , 与 Java 类似
    	//② 调用 string 对象的 append 方法 , 拼接字符串
    	string string_c_plus_5 = string_c_plus_1 + string_c_plus_3;
    	string string_c_plus_6 = string_c_plus_1.append( string_c_plus_3 );
    
    	//输出拼接的字符串
    	cout << string_c_plus_5.c_str() << endl;
    	cout << string_c_plus_6.c_str() << endl;
    	
    
    
    	//获取 C++ 字符串长度 : 调用 string 对象的 size() 方法 , 获取字符串长度
    	int string_c_plus_1_size = string_c_plus_1.size();
    	cout << "string_c_plus_1_size : " << string_c_plus_1_size << endl;
    
    	//判断 C++ 字符串是否为空 : 调用 string 对象的 empty() 方法 ; 
    	bool string_c_plus_1_empty = string_c_plus_1.empty();
    	cout << "string_c_plus_1_empty : " << string_c_plus_1_empty << endl;
    
    	//使用 new 创建的对象 , 就不能使用 . 访问其方法和变量 , 需要使用 -> 符号进行访问 
    	// -> 相当于 (*). 运算, 先读取指针内容 , 然后访问其方法或变量
    
    	string* string_c_plus_7 = new string(" New String ");
    	
    	//① 获取字符串长度 : 
    	int string_c_plus_7_size = string_c_plus_7->size();
    	cout << "string_c_plus_7 : " << string_c_plus_7_size << endl;
    
    	//② 判断字符串是否为空 : 
    	bool string_c_plus_7_empty = string_c_plus_7->empty();
    	cout << "string_c_plus_7_empty : " << string_c_plus_7_empty << endl;
    
    	//释放堆内存
    	delete string_c_plus_7;
    
    	//使用指针的好处 : 
    	// ① 如果在栈内存中使用 , 有作用域限制 , 出了栈内存 作用域 , 该对象就无效了 ; 
    	// ② 指针 大小为 4 ( 32 位系统 ) 或 8 ( 64 位系统 ) 个字节 , 
    	//	  其当做参数传递 比直接传递对象 ( 动辄几十上百字节甚至更高 ) 效率更高 
    
    
    
    
    
    	return 0;
    }
    

    展开全文
  • 2016年11月16日 16:58:21 阅读数:7873 ...一个Demo,集合常用的十种设计模式,每个模式使用易被人们接受的案例讲述,按模式分包,使用设计模式前后对比,界面显示定义讲解,让你更深刻的了解每设计模...
  • Java面试题大全(2020版)

    万次阅读 多人点赞 2019-11-26 11:59:06
    hashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。 hashTable同步的,而HashMap是非同步的,效率上逼hashTable要高。 hashMap允许空键值,而hashTable不允许。 22. 如何...
  • 十种排序算法

    万次阅读 多人点赞 2017-12-06 17:10:51
    十种常见排序算法一般分为以下几:  (1)非线性时间比较类排序:交换类排序(快速排序和冒泡排序)、插入类排序(简单插入排序和希尔排序)、选择类排序(简单选择排序和堆排序)、归并排序(二路归并排序和多路...
  • UML基本构造块之十种图(二)

    千次阅读 2016-04-19 19:58:21
     这几天一直在学习UML的十种图,之前是对UML十种图的主要概念进行理解,现在对其及其之间的关系进行理解 学习。  一、用例图(Use Case Diagram):  最开始学习的第一个图是用例图,用例图主要用于为...
  • OpenCore引导配置说明一版说明-基于OpenCore-0.6.4正式版 一、 OC配置的基本条件与工具软件 1.1、 准备Mac平台,包括实体机平台和虚拟机平台。 1.2、 下载最新镜像并核对MD5,制作安装U盘。 1.3、 工具软件: ...
  • 总的来说,当得到系统的输出后,将输出经过比例,积分,微分3运算方式,叠加到输入中,从而控制系统的行为,下面用一个简单的实例来说明。 比例控制算法 我们先说PID中最简单的比例控制,抛开其他两个不谈...
  • Pandas是python的一个数据分析包,提供了大量的快速便捷处理数据的函数和方法。其中Pandas定义了Series 和 DataFrame两数据类型,这使数据操作变得更简单。Series 是一一维的数据结构,类似于将列表数据值与索引...
  • springboot的注解的作用说明(全)

    万次阅读 多人点赞 2019-04-23 11:21:32
    @RestController注解相当于@ResponseBody + @Controller合在一起的作用 @Controller 注解,在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面 若返回json等内容到页面,则需要加@...
  • 需求工程规格说明、需求验证、需求管理

    千次阅读 多人点赞 2020-04-24 18:52:14
    一章 需求规格说明 需求获取:目标是得到用户需求——收集需求信息 需求分析:目标是更深刻的理解用户需求——界定能够让用户满意的解决方案准则 需求规格说明:目标是定义用户需求——准确描述需求及其解决方案...
  • 白话空间统计二四:地理加权回归(七)ArcGIS的GWR工具扩展参数说明 近期无论是开发者大会,还是个人工作,相当的忙,所以停了一段时间……不过地理加权回归写到第七章,自我感觉也差不多了,无论是基础理论...
  • C语言

    万次阅读 多人点赞 2019-12-18 23:01:50
    42.C语言是一计算机高级语言。 43.C语言允许直接访问物理地址,能进行位操作。 44.C语言是结构化程序设计语言 45.c程序要通过编译,连接才能得到可执行的目标程序 46.用c语言编写程序,可以编写出任何类型的程序 ...
  • 入门学习Linux常用必会60个命令实例详解doc/txt

    千次下载 热门讨论 2011-06-09 00:08:45
    这里笔者把比较重要和使用频率最多的命令,按照它们在系统中的作用分成下面六个部分一一介绍。 ◆ 安装和登录命令:login、shutdown、halt、reboot、install、mount、umount、chsh、exit、last; ◆ 文件处理命令...
  • OFDM完整仿真过程及解释(MATLAB)

    万次阅读 多人点赞 2019-04-19 17:03:45
    因为是复制过来,如果出现图片显示不完整以及需要源程序请点击下面... ... 目录: 一、说明 二、ofdm总体概述 三、基本原理 四、过程中涉及的技术 五、OFDM基本参数的选择 六、OFDM的MATLAB仿真程序 一、说...
  • mysql分表的3种方法

    千次阅读 2018-02-08 13:55:34
    推荐阅读 微服务:springboot系列教程学习 源码:Javaweb练手项目源码下载 调优:五篇好文回顾 面试笔试:面试笔试整理系列一,先说一下为什么要分表当一张的数据达到几百万时,你查询一次所花的时间会变多,...
  • 多线程面试题(值得收藏)

    万次阅读 多人点赞 2019-08-16 09:41:18
    金九银快到了,即将进入找工作的高峰期,最新整理的最全多线程并发面试47题和答案总结,希望对想进BAT的同学有帮助,由于篇幅较长,建议收藏后细看~ 1、并发编程三要素? 1)原子性 原子性指的是一个或者多个操作,...
  • 列举几个常用的linux命令以及说明

    千次阅读 2018-11-27 12:07:13
    作用:显示目录内容,类似DOS下的DIR -格式:LS【options】【filename】 -常用参数:  &gt;-a:all,不隐藏任何以"."字符开始的文件  &gt;-l:使用较长的格式列出信息  &gt;-r:按照...
  • 前端面试题

    万次阅读 多人点赞 2019-08-08 11:49:01
    简述列举文档对象模型DOM里document的常用的查找访问节点的方法并做简单说明 72 希望获取到页面中所有的checkbox怎么做?(不使用第三方框架) 72 简述创建函数的几方式 73 Javascript如何实现继承? 73 ...
  • JavaScript 对象是拥有属性和方法的数据。在JavaScript中,几乎所有的事物都是对象。(这和Java一样啊,万物皆对象!!!) 可以使用字符来定义和创建 JavaScript 对象,定义 JavaScript 对象可以跨越多行,空格跟...
  • 23 设计模式详解(全23

    万次阅读 多人点赞 2019-06-09 00:21:59
    创建型模式,共五:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一:...
  • PID控制实际上是一很灵活的控制方法,大家不要光被前面所讲的定义所封住了思想,只要你通过PID把一个系统调好了,这就是一个好的PID,不管你在过程中用了什么方法 其实PID控制是根据实际情况有很多控制方法的 而...
  • Python内置函数

    万次阅读 多人点赞 2019-05-10 15:10:36
    >>> print chr(48), chr(49), chr(97) # 进制 0 1 a Python classmethod 修饰符 描述: classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用...
  • 物联网常见的十种定位技术的优缺点

    万次阅读 多人点赞 2018-07-25 10:02:00
     射频识别室内定位技术作用距离很近,但它可以在几毫秒内得到厘米级定位精度的信息,且由于电磁场非视距等优点,传输范围很大,而且标识的体积比较小,造价比较低。但其不具有通信能力,抗干扰能力较差,不...
  • 2021【软件测试】面试题合集大放送

    万次阅读 多人点赞 2019-09-10 18:04:37
    又到了金九银跳槽求职旺季。准备好一场面试不仅需要在简历上多下功夫,还需要为面试问答做好充足的准备,简历书写请参考:https://blog.csdn.net/leboxy/article/details/100658701。以下是“大佬”本人从乐搏学院...
  • Java 语法

    千次阅读 多人点赞 2017-09-10 21:46:41
    B:把数据能够输出,说明我们的程序是可以独立运行的,而程序要独立运行,必须定义main方法 C:把数据输出在控制台,必须使用输出语句 实现: A:java语言提供了一个关键字: class 用来定义类,后面跟的是类名 B...
  • python格式化字符串的三种方法(%,format,f-string)

    万次阅读 多人点赞 2019-07-18 23:25:51
    到目前为止,我所知道的,python格式化字符串有三种方法,第一是早期就有的%,其次是2.5之后的format(),还有就是3.6添加的f字符串调试 7.1 %格式化字符串 %格式化字符串是python最早的,也是能兼容所有版本的一...
  • 答案:错误。 众所周知,被abstract修饰的类是抽象类,抽象类不能被...在书中有明确说明:抽象类的构造方法定义为protected,因为他只能被子类使用,即用super(paraments); 参考文献:Java语言程序设计(第版)P426页

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 223,952
精华内容 89,580
关键字:

十种说明方法的作用