Vi/Vim
Vim是从vi发展出来的一个文本编辑器,支持代码补全,编译和错误跳转等方便编程的功能。
vi/vim有三种模式:
- 命令模式
- 输入模式
- 底线命令格式
命令模式
启动vi/vim即进入命令模式,在此状态下敲击键盘会被vim识别为命令,而非输入字符。
在此模式下可以对文件进行常规的编辑操作,例如:定位,翻页,赋值,粘贴,删除等。
常用的命令:
i
切换到输入模式,以输入字符x
删除当前光标所在处的字符:
切换到底线命令模式,可以在最小面一行输入命令。
输入模式
在命令模式下,输入i即可进入输入模式。
- 字符按键以及Shift组合,输入字符
- ENTER,回车键,换行
- BACK SPACE,退格键,删除光标前一个字符
- DEL,删除键,删除光标后一个字符
- 方向键,在文本中移动光标
- HOME/END,移动光标到行首/行尾
- Page Up/Page Down,上/下翻页
- Insert,切换光标为输入/替换模式,光标将变成竖线/下划线
- ESC,退出输入模式,切换到命令模式
底线命令模式
在命令模式下,输入:
即可进入底线命令模式。
底线命令模式是vi的出口。
按ESC键可随时退出底线命令模式。
命令 | 功能 |
---|---|
w | 保存 |
q | 退出,如果没有保存,不允许退出 |
q! | 强行退出,不保存退出 |
wq | 保存并退出 |
x | 保存并退出 |
vi/vim使用示例
- 打开或新建文件:在终端中输入
vim 文件名
- 如果文件不存在则会新建一个文件。
- 如果文件存在则直接打开该文件。
其次当我们需要打开文件并定位到指定行是时:
vim 文件名+行数
- 打开文件之后,按下i进入编辑模式。进入编辑模式之后,键盘上除了Esc键之外都可以视作一般输入按钮。
- 编辑结束之后,按Esc键进入底线命令模式,一般情况下按下
:wq
即可保存后离开。
vi/vim按键说明
- 要熟练使用 vi,首先应该学会怎么在 命令模式 下样快速移动光标
- 编辑操作命令,能够和 移动命令 结合在一起使用
- 上、下、左、右
命令 | 功能 |
---|---|
h或← | 向左 |
j或↓ | 向下 |
k或↑ | 向上 |
l或→ | 向右 |
2)行内移动
命令 | 功能 |
---|---|
w | 向后移动一个单词 |
b | 向前移动一个单词 |
0 | 行首 |
^ | 行首,第一个不是空白字符的位置 |
$ | 行尾 |
- 行数移动
命令 | 功能 |
---|---|
gg | 文件顶部 |
G | 文件末尾 |
数字gg | 移动到 数字 对应行数 |
数字G | 移动到 数字 对应行数 |
:数字 | 移动到 数字 对应行数 |
移动(程序)
- 段落移动
- vi 中使用 空行 来区分段落
- 在程序开发时,通常 一段功能相关的代码会写在一起 —— 之间没有空行
命令 | 功能 |
---|---|
{ | 上一段 |
} | 下一段 |
- 括号切换
在程序世界中,()、[]、{} 使用频率很高,而且 都是成对出现的
命令 | 功能 |
---|---|
% | 括号匹配及切换 |
- 标记
- 在开发时,某一块代码可能需要稍后处理,例如:编辑、查看
- 此时先使用 m 增加一个标记,这样可以 在需要时快速地跳转回来 或者 执行其他编辑操作
- 标记名称 可以是 a~z 或者 A~Z 之间的任意 一个 字母
- 添加了标记的 行如果被删除,标记同时被删除
- 如果 在其他行添加了相同名称的标记,之前添加的标记也会被替换掉
命令 | 功能 |
---|---|
mx | 添加标记 x,x 是 a~z 或者 A~Z 之间的任意一个字母 |
'x | 直接定位到标记 x 所在位置 |
4.3 选中文本(可视模式)
- 学习 复制 命令前,应该先学会 怎么样选中 要复制的代码
- 在 vi 中要选择文本,需要先使用 Visual 命令切换到 可视模式
- vi 中提供了 三种 可视模式,可以方便程序员选择 选中文本的方式
- 按 ESC 可以放弃选中,返回到 命令模式
命令 | 模式 | 功能 |
---|---|---|
v | 可视模式 | 从光标位置开始按照正常模式选择文本 |
V | 可视行模式 | 选中光标经过的完整行 |
Ctrl + v | 可视块模式 | 垂直方向选中文本 |
- 可视模式下,可以和 移动命令 连用,例如:ggVG 能够选中所有内容
4.4 撤销和恢复撤销
在学习编辑命令之前,先要知道怎样撤销之前一次 错误的 编辑动作!
命令 | 功能 |
---|---|
u | 撤销上次命令 |
CTRL + r | 恢复撤销的命令 |
4.5 删除文本
命令 | 功能 |
---|---|
x | 删除光标所在字符,或者选中文字 |
d(移动命令) | 删除移动命令对应的内容 |
dd | 删除光标所在行,可以 ndd 删除多行 |
D | 删除至行尾 |
提示:如果使用 可视模式 已经选中了一段文本,那么无论使用 d 还是 x,都可以删除选中文本
复制、粘贴
vi 中提供有一个 被复制文本的缓冲区
复制 命令会将选中的文字保存在缓冲区
删除 命令删除的文字会被保存在缓冲区
在需要的位置,使用 粘贴 命令可以将缓冲区的文字插入到光标所在位置
命令 | 功能 |
---|---|
y(移动命令) | 复制 |
yy | 复制一行,可以 nyy 复制多行 |
p | 粘贴 |
提示
- 命令 d、x 类似于图形界面的 剪切操作 —— CTRL + X
- 命令 y 类似于图形界面的 复制操作 —— CTRL + C
- 命令 p 类似于图形界面的 粘贴操作 —— CTRL + V
- vi 中的 文本缓冲区同样只有一个,如果后续做过 复制、剪切 操作,之前缓冲区中的内容会被替换
注意
- vi 中的 文本缓冲区 和系统的 剪贴板 不是同一个
- 所以在其他软件中使用 CTRL + C 复制的内容,不能在 vi 中通过 P 命令粘贴
- 可以在 编辑模式 下使用 鼠标右键粘贴
替换
命令 | 功能 工作模式 |
---|---|
r | 替换当前字符 命令模式 |
R | 替换当前行光标后的字符 替换模式 |
R 命令可以进入 替换模式,替换完成后,按下 ESC 可以回到 命令模式
替换命令 的作用就是不用进入 编辑模式,对文件进行 轻量级的修改
查找并替换
- 在 vi 中查找和替换命令需要在 末行模式 下执行
- 命令格式:
:%s///g
- 全局替换
- 一次性替换文件中的 所有出现的旧文本
- 命令格式如下:
:%s/旧文本/新文本/g
- 可视区域替换
先选中 要替换文字的 范围
命令格式如下:
:s/旧文本/新文本/g
1 - 确认替换
如果把末尾的 g 改成 gc 在替换的时候,会有提示!推荐使用!
:%s/旧文本/新文本/gc
- y - yes 替换
- n - no 不替换
- a - all 替换所有
- q - quit 退出替换
- l - last 最后一个,并把光标移动到行首
- ^E 向下滚屏
- ^Y 向上滚屏
vim配置
在终端使用vim .vimrc
打开配置文件,然后可以对其进行简单的配置。
也可以从网上找一份完全配置好的配置文件进行复制粘贴。
Java
对象和类
Java作为一种面向对象的语言,支持以下基本概念:多态、继承、封装、抽象、类、对象
实例、方法、重载。
- 对象:对象是类的一个实例,有状态和行为。
- 类:类是一个模板,它描述一类对象的行为和状态。
创建对象
对象是根据类创建的,在Java中,使用关键字new来创建一个新的对象。创建对象需要以下三步:
(1) 声明:声明一个对象,包括对象名称和对象类型。
(2) 实例化:使用关键字new来创建一个对象。
(3) 初始化:使用new创建对象时,会调用构造方法初始化对象。
构造方法
每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
public class Puppy{
public Puppy(String name){
//这个构造器仅有一个参数:name
System.out.println("小狗的名字是 : " + name );
}
public static void main(String []args){
Puppy myPuppy = new Puppy( "tommy" );
}
}
Import语句
在Java中,如果给出一个完整的限定名,包括包名、类名,那么Java编译器就可以很容易地定位到源代码或者类。Import语句就是用来提供一个合理的路径,使得编译器可以找到某个类。
基本数据类型
Java语言提供了八种基本类型
- byte
- short
- int
- long
- float
- double
- boolean
- char
Java继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的好处就是可以减少重复的代码,提高代码的维护性,代码也更加简洁,提高代码的复用性。
class 父类 {
}
class 子类 extends 父类 {
}
继承的特性
- 子类拥有父类非private的属性,方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。 子类可以用自己的方式实现父类的方法。
- Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,这是java继承区别于C++继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系)。
继承关键字
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类
extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)
super和this关键字
- super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
- this关键字:指向自己的引用。
final关键字
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写
构造器
子类不能继承父类的构造器(构造方法或者构造函数),但是父类的构造器带有参数的,则必须在子类的构造器中显式地通过super关键字调用父类的构造器并配以适当的参数列表。
如果父类有无参构造器,则在子类的构造器中用super调用父类构造器不是必须的,如果没有使用super关键字,系统会自动调用父类的无参构造器
Java重写与重载
重写
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。
方法的重写规则
- 参数列表必须完全与被重写方法的相同;
- 返回类型必须完全与被重写方法的返回类型相同;
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。
- 父类的成员方法只能被它的子类重写。
- 声明为final的方法不能被重写。
- 声明为static的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为public和protected的非final方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个方法,则不能重写这个方法。
重载
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
只能重载构造函数。
重载规则
- 被重载的方法必须改变参数列表(参数个数或类型或顺序不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载是一类中多态性的一种表现。
Java多态
多态是同一个行为具有多个不同表现形式或形态的能力。多态性是对象多种表现形式的体现。
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象
Java 抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。
在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
在Java语言中使用abstract class来定义抽象类。
抽象方法
如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。
Abstract关键字同样可以用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。
抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
声明抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。
Java 接口
接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口与类相似点:
- 一个接口可以有多个方法。
- 接口文件保存在 .java 结尾的文件中,文件名使用接口名。
- 接口的字节码文件保存在 .class结尾的文件中。
- 接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与类的区别
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多重继承。
Ant
Ant是Java的生成工具,类似于Make工具,用于编译,生成Java项目,它可以实现项目的自动构建和部署,其中内置了javac,java,创建目录,复制文件等等,极大程度上简化了java项目的构建和部署操作。
Ant基础
ant默认生成build.xml。在终端输入ant后,ant会在当前目录下查找是否存在build.xml文件,若找到即运行。当然,也可以指定运行文件:ant -f filename.xml
ant生成的文件是xml,其基本结构为:
<?xml version="1.0">
<project default="targetname">
<target name="name">
</target>
</project>
project是xml文件的根元素,target表示一个任务;
一个project中可以有多个target,即一个项目中可以有多个任务。
Ant的元素
- project
project元素是Ant构建文件的根元素,Ant构件文件至少包含一个project元素。
project的属性介绍
(1) name:用于指定project元素的名称
(2) default:用于指定project默认执行时所执行的target的名称
(3) basedir:用于指定基路径的位置。该属性没有指定时,使用Ant的构件文件的附目录作为基准目录。
-
target
target是Ant的基本执行单元,它可以包含一个或多个具体的任务。多个target之间可以存在相互依赖的关系。
(1) name:指定target的名称,这个名称在整个project中是唯一的,我们可以通过指定target元素的名称来指定某个target
(2) depends:用于描述target之间的依赖关系,偌与多个target存在依赖关系时,需要以","间隔。Ant会依照depends中target初夏的顺序依次执行每个target。被依赖的target会先执行。
(3) if:用于验证指定的属性是否存在,若不存在,该target将不会执行。
(4)unless:与if相反,若不存在,该target将执行
(5)description:该属性是关于target功能的简短描述和说明。 -
property
此元素可以看作是参量或参数的定义,project的属性可以通过property来设定,也可在Ant之外设定。若要在外部引入某文件,例如build.properties文件,可以通过<property file="build.properties"/>
Ant本身还有一些内置的属性:
(1) basedir:project基目录的绝对路径
(2) ant.file:buildfile的绝对路径
(3) ant.version:Ant的版本
(4) ant.project.name:当前指定的project的名字
(5)ant.java.version:Ant检测到的JDK版本
Ant的常用任务
Ant工具中,每个人物都封装了具体要执行的功能,是Ant工具的基本执行单位。下面是Ant常用的任务。
在Ant中Task是target的子元素,即一个target中可以有多个task;而Task分为:
(1)核心Task;
(2)可选Task;
(3)自定义Task;
下面介绍一些常用的核心Task。
<echo>
用于单纯输出,如:
<echo>hello</echo>
<javac>
用于编译java文件,一般形式如下:
<javac srcdir="src" destdir="class" [classpath=" "]/>
- srcdir是编译此文件夹下或子文件夹下的全部java文件;
- destdir是编译后的class文件放置路径;
- classpath指定第三方类库;
<java>
运行java类,一般形式如下:
<Java classname=" " fork="yes">
【<arg line="param1 param2 param3"/>】
</java>
- classname用于指定运行的类名称;
fork=”yes”表示另起一个JVM来执行java命令,而不是中断ANT命令,因此fork必须为yes;
打包成jar包;一般形式如下:
<jar destfile="main.jar" basedir=" ">
<manifest>
<attribute name="Main-Class" value="classname"/> <!--指定主类-->
</manifest>
</jar>
- destfiie的值为jar包的名称,一般为${dest}/main.jar;
- basedir的值是需要打成jar包的目录,一般为${classes};
- manifest表示设置META-INF;
<mkdir>
创建目录,可以多层创建,比如a\b\c,则可以连续创建,一般形式如下:
<mkdir dir="a\b"/>
<delete>
删除目录,一般形式如下:
<delete dir="a\b"/>
可以删除a目录下的b目录;
<delete file="1.txt"/>
可以删除文件;
<copy>
复制文件,一般形式如下:
<copy file="file1" tofile="file2"/>
- file是源文件;
- tofile是目标文件;
<move>
移动文件,一般形式如下:
<move file="file1" tofile="file2"/>
- file是源文件;
- tofile是目标文件;
<replace>
用于替换字符串,类似于String的replace操作,一般形式如下:
<replace file="filename" token="old" value="new"/>
- file表示要执行替换的文件;
- token表示被替换的字符串;
在这里插入代码片
value表示替换的字符串。
Junit
Junit4是java单元测试框架,主要特性是利用Java5的Annotation特性简化测试用例的编写。
Junit4的基本使用
Annotation,元数据,是用来描述数据的数据,在Java里面可以用来和public,static等关键字一样来修饰类名,方法名,变量名。
在Junit4中,单元测试样例:
import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
public class AddOperationTest {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void add() {
System.out.println(\"add\");
int x = 0;
int y = 0;
AddOperation instance = new AddOperation();
int expResult = 0;
int result = instance.add(x, y);
assertEquals(expResult, result);
}
}
下面介绍以下上述代码用到的元数据:
- @Before:使用了该元数据的方法在每个测试方法执行前都要执行依次
- @After:使用了该元数据的方法在每个测试方法执行之后要执行一次
- @Test:Test(expeted=*.class),指定要测试方法,expected
- @ignore:
检查
1. 检查ANT、Junit。主要是通过检查HelloWorld是否通过编译,部署和测试。(检查点:1.是否使用ANT;2.是否使用Junit)
JAVA:HelloWorld代码
使用ant:
编写build.xml:
自动编译结果:
编译成功,在build/classes目录下产生.class文件。
使用Junit:
编写测试类:
运行测试类:
2.检测SonarQube的使用情况。(SonarQube是否正常运行,Java小程序的分析结果)
启动SonarQube
编写Java小程序
package calculator;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Calculator extends JFrame {
private String operator = "";
private JPanel panel;
private JTextField num1, num2, ans, operating;
public Calculator() {
// window setting
this.setBounds(300, 200, 400, 300);
this.setTitle("Simple Calculator");
this.setLayout(new BorderLayout());
num1 = new JTextField("12");
num2 = new JTextField("6");
ans = new JTextField();
operating = new JTextField();
panel = new JPanel();
panel.setLayout(new GridLayout(2, 5));
}
public void fun() {
panel.add(num1);
panel.add(operating);
panel.add(num2);
panel.add(useButton("="));
panel.add(ans);
//function
panel.add(useButton("+"));
panel.add(useButton("-"));
panel.add(useButton("*"));
panel.add(useButton("/"));
panel.add(useButton("OK"));
this.add(panel);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public JButton useButton(final String key) {
JButton button = new JButton(key);
button.setFont(new Font("SimSun",1,25));
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
JButton buttonT = (JButton) event.getSource();
String keyT = buttonT.getText();
action(keyT);
}
});
return button;
}
private void action(String key) {
switch(key) {
case "+":
operator = "+";
operating.setText("+");
break;
case "-":
operator = "-";
operating.setText("-");
break;
case "*":
operator = "*";
operating.setText("*");
break;
case "/":
operator = "/";
operating.setText("/");
break;
case "=":
calculate();
break;
default:
calculate();
break;
}
}
public Boolean isNumber(String num) {
for(int i = 0; i < num.length(); ++i) {
if(num.charAt(i) < '0' || num.charAt(i) > '9'){
return false;
}
}
return true;
}
public void cal(int numberFirst, int numberSecond) {
double answer = 0;
switch(operator) {
case "+":
answer = 1.0*numberFirst+numberSecond;
break;
case "-":
answer = 1.0*numberFirst-numberSecond;
break;
case "*":
answer = 1.0*numberFirst*numberSecond;
break;
case "/":
answer = 1.0*numberFirst/numberSecond;
break;
default:
break;
}
ans.setText(String.valueOf(answer));
}
public void calculate() {
//judge wheather can be calculated
//set the invalid num be null
String a = num1.getText();
String b = num2.getText();
if(!a.equals("") && !b.equals("")){
if(!operator.equals("") && isNumber(num1.getText()) && isNumber(num2.getText())) {
int numberFirst = Integer.parseInt(num1.getText());
int numberSecond = Integer.parseInt(num2.getText());
cal(numberFirst, numberSecond);
}
}
else if(!isNumber(num1.getText())) {
//set the invalid num be null
num1.setText("");
}
else if(!isNumber(num2.getText())){
//set the invalid num be null
num2.setText("");
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
Calculator calculate = new Calculator();
calculate.fun();
}
}
运行结果:
使用SonarQube分析Java小程序