2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

时间:2023-03-08 17:04:00
2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

实验要求

  • 没有Linux基础的同学建议先学习《Linux基础入门(新版)》《Vim编辑器》 课程
  • 完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导
  • 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。
  • 请大家先在实验楼中的~/Code目录中用自己的学号建立一个目录,代码和UML图要放到这个目录中,截图中没有学号的会要求重做,然后跟着下面的步骤练习。

实验步骤

(一)单元测试

  • 三种代码
    • 伪代码:将问题抽象出来,写出需要计算机执行的步骤
    • 产品代码:用特定的编程语言翻译
    • 测试代码:测试代码有没有问题
  • 单元测试:对类实现的测试
    • 点击New->Directory新建一个test目录,再右键点击设置环境变量,选择Mark Directory->Test Sources Root即可

      2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

  • 设计一个测试用例:将正常情况,异常情况,边界情况一一排查,检查出所有bug并修改,才能保证所写代码比较健全准确

    • 正常情况

      2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

    • 边界情况:一般容易遗漏边界情况,而且容易出错

      2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

    • 异常情况 ->依据所出现的异常情况,就应该针对此问题修改源代码,直至测试成功。

      2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

(二)以 TDD的方式研究学习StringBuffer

- TDD(Test Driven Devlopment, 测试驱动开发):先写测试代码,再写产品代码。
  • 步骤:
    • 明确当前要完成的功能,记录成一个测试列表
    • 快速完成编写针对此功能的测试用例
    • 测试代码编译不通过(没产品代码呢)
    • 编写产品代码
    • 测试通过
    • 对代码进行重构,并保证测试通过(重构下次实验练习)
    • 循环完成所有功能的开发
  • 安装JUnit插件

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

  • 下载完成后,在IDEA中新建空类,鼠标单击类名会出现一个灯泡状图标,单击图标或按Alt + Enter,在弹出的菜单中选择Create Test

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

  • 选择创建JUnit3的测试用例

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

    • 如果TestCase是红色的,需要在IDEA中的项目(模块)中加入junit.jar包,junit.jar包的位置可以在Everything中查找
    • 在弹出的对话框中选择Dependancies标签页,单击+号,选择JARs or Directories...,输入上面找到的C:\Users\13015\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-1\171.4073.35\lib\junit.jar

      2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告
StringBuffer
  • capacity返回的是目前的最大容量而length返回的是字符串长度

    • 默认值为16
    • 根据capacity的构造方法,可以指定初始容量

      2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告
  • charAt返回该位置上的字符

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

  • indexOf返回第一次出现的指定子字符串在该字符串中的索引

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

StringBuilder、StringBuffer、String类之间的关系
  • String类:String的值是不可变的,因此每次对String操作都会生成新的String对象,浪费大量内存空间。为理解这个,我从书上摘取了一个小栗子~a最后指向56EF,但最后12AB和56EF地址中的数据仍然存在,因此String的操作都是改变赋值地址而不是改变值操作。

    String a = "你好"

    a = "boy"

    a = "12.97"

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

  • StringBuffer是可变类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量,非常人性化。

    StringBuffer buf=new StringBuffer(); //分配默认长16字节的字符缓冲区

    StringBuffer buf=new StringBuffer(512); //分配长512字节的字符缓冲区

    StringBuffer buf=new StringBuffer("this is a test")//在缓冲区中存放了字符串,并在后面预留了16字节的空缓冲区。

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

  • StringBuilder与StringBuffer功能基本相似,主要区别在于StringBuffer类的方法是多线程、安全的,而StringBuilder不是线程安全的,相比而言,StringBuilder类会略微快一点。

    • 多线程:每一个任务称为一个线程。可以同时运行一个以上线程的程序称为多线程程序。
  • 总结

    • String:适用于少量的字符串操作的情况
    • StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
    • StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况

(三)面向对象三要素

  • 抽象:抽出事物的本质特征而暂不考虑细节,对于复杂的问题分层求解
    • 过程抽象:结果是函数
    • 数据抽象:结果是抽象数据类型
  • 封装,继承与多态(面向对象的三要素)
    • 封装:将数据与相关行为包装在一起以实现信息隐藏,java中使用类进行封装,接口是封装准确描述手段
    • 继承:关键在于确认子类为父类的一个特殊类型,以封装为基础,继承可以实现代码复用,继承更重要的作用是实现多态。
    • 多态:同一消息可以根据发送对象的不同而采用多种不同的行为方式

(四)设计模式初步

  • S.O.L.I.D原则
    • SRP(Single Responsibility Principle,单一职责原则)
    • OCP(Open-Closed Principle,开放-封闭原则)
      • 对扩充开放,对修改封闭:抽象和继承;面向接口编程
    • LSP(Liskov Substitusion Principle,Liskov替换原则)
    • ISP(Interface Segregation Principle,接口分离原则)
    • DIP(Dependency Inversion Principle,依赖倒置原则)
  • 设计模式
    • Pattern name:描述模式,便于交流,存档
    • Problem:描述何处应用该模式
    • Solution:描述一个设计的组成元素,不针对特例
    • Consequence:应用该模式的结果和权衡(trade-offs)

(五)练习

  • 练习题目1:让系统支持Double类,并在MyDoc类中添加测试代码表明添加正确,提交测试代码和运行结的截图,加上学号水印
    • 产品代码
// Sever Classer
abstract class Data{
public abstract void DisplayValue();
}
class Integer extends Data{
int value;
Integer(){
value = 100;
}
public void DisplayValue(){
System.out.println(value);
}
}
class Double extends Data{
double value;
Double(){
value = 5.0;
}
public void DisplayValue(){
System.out.println(value);
}
}
// Pattern Classes
abstract class Factory{
public abstract Data CreateDataObject();
}
class IntFactory extends Factory{
public Data CreateDataObject(){
return new Integer();
}
}
class DoubleFactory extends Factory{
public Data CreateDataObject(){
return new Double();
}
}
//Client classes
class Document {
Data pd;
Document(Factory pf){
pd = pf.CreateDataObject();
}
public void DisplayData(){
pd.DisplayValue();
}
}
public class MyDoc {
static Document d;
static Document f;
public static void main(String[] args) {
d = new Document(new IntFactory());
d.DisplayData();
f = new Document(new DoubleFactory());
f.DisplayData();
}
}
  • 运行结果

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

  • 练习题目2:以TDD的方式开发一个复数类Complex,

    • 伪代码
// 定义属性并生成getter,setter
double RealPart;
double ImagePart;
// 定义构造函数
public Complex()
public Complex(double R,double I)
//Override Object
public boolean equals(Object obj)
public String toString()
// 定义公有方法:加减乘除
Complex ComplexAdd(Complex a)
Complex ComplexSub(Complex a)
Complex ComplexMulti(Complex a)
Complex ComplexDiv(Complex a)
  • 产品代码
public class MyComplex{
//定义属性并生成getter,setter
private double realPart;
private double imagePart;
public double getRealPart(){
return realPart;
}
public double getImagePart(){
return imagePart;
} //定义构造函数
public MyComplex(){}
public MyComplex(double r,double i){
realPart = r;
imagePart = i;
}
//Override Object
@Override
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(!(obj instanceof MyComplex)) {
return false;
}
MyComplex complex = (MyComplex) obj;
if(complex.realPart != ((MyComplex) obj).realPart) {
return false;
}
if(complex.imagePart != ((MyComplex) obj).imagePart) {
return false;
}
return true;
}
@Override
public String toString(){
String s = new String();
if(imagePart >0 && realPart!=0){
s = ""+getRealPart()+"+"+getImagePart()+"i";
}
if(imagePart >0 && realPart==0){
s= getImagePart()+"i";
}
if(imagePart <0 &&realPart!=0)
{
s = ""+getRealPart()+getImagePart()+"i";
}
if(imagePart <0 && realPart==0){
s= getImagePart()+"i";
}
if(imagePart ==0 &&realPart!=0)
{
s = ""+getRealPart();
}
if(imagePart ==0 && realPart==0){
s= "0";
}
return s;
}
//定义公有方法:加减乘除
public MyComplex complexAdd(MyComplex a){
return new MyComplex(realPart+a.realPart, imagePart +a.imagePart);
}
public MyComplex complexSub(MyComplex a){
return new MyComplex(realPart-a.realPart, imagePart -a.imagePart);
}
public MyComplex complexMulti(MyComplex a){
return new MyComplex(realPart * a.realPart - imagePart * a.imagePart, realPart * a.imagePart + imagePart * a.realPart);
}
public MyComplex complexDiv(MyComplex a){
return new MyComplex((realPart * a.realPart + imagePart * a.imagePart) / (a.imagePart * a.imagePart + a.realPart * a.realPart), (imagePart * a.realPart - realPart * a.imagePart) / (a.realPart * a.realPart + a.realPart * a.realPart));
} }
  • 测试代码
import junit.framework.TestCase;
import org.junit.Test; public class MyComplexTest extends TestCase {
MyComplex a = new MyComplex(2.0,4.0);
MyComplex b = new MyComplex(0.0,-3.0);
MyComplex c = new MyComplex(-5.0,0.0);
@Test
public void testgetRealpart(){
assertEquals(2.0,a.getRealPart());
assertEquals(0.0,b.getRealPart());
assertEquals(-5.0,c.getRealPart());
}
@Test
public void testgetImagePart(){
assertEquals(4.0,a.getImagePart());
assertEquals(-3.0,b.getImagePart());
assertEquals(0.0,c.getImagePart());
}
@Test
public void testMyComplexAdd(){
String q = a.complexAdd(b).toString();
String w = b.complexAdd(c).toString();
String e = c.complexAdd(a).toString();
assertEquals("2.0+1.0i",q);
assertEquals("-5.0-3.0i",w);
assertEquals("-3.0+4.0i",e);
}
@Test
public void testMyComplexSub(){
String r = a.complexSub(b).toString();
String t = b.complexSub(c).toString();
String y = c.complexSub(a).toString();
assertEquals("2.0+7.0i",r);
assertEquals("5.0-3.0i",t);
assertEquals("-7.0-4.0i",y);
}
@Test
public void testMyComplexMulti(){
String u = a.complexMulti(b).toString();
String i = b.complexMulti(c).toString();
String o = c.complexMulti(a).toString();
assertEquals("12.0-6.0i",u);
assertEquals("15.0i",i);
assertEquals("-10.0-20.0i",o);
}
@Test
public void testMyComplexDiv(){
String p = c.complexDiv(a).toString();
assertEquals("-0.5+2.5i",p);
}
@Test
public void testtoString(){
assertEquals("2.0+4.0i",a.toString());
assertEquals("-3.0i",b.toString());
assertEquals("-5.0",c.toString());
}
}
  • 运行结果

    2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

实验中遇到的问题

Q: junit 使用org.junit不存在,点到代码中红色的部分显示:Cannot resolve symbol 'junit'

2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

A:File -> Project Struct... -> Libraies -> 点击绿色的加号 -> Java -> 找到 IDEA 安装路径下的 Lib 中的junit-4.12 ->点击OK

2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

Q:在对append进行测试的时候,明明期望的值和实际值相同,但还是测试失败

2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

A:将StringBuffer转为字符串再比较,即可得出答案

public void testappend() throws Exception{
String q,w,e;
a = a.append("abc");
b = b.append("abc");
c = c.append(ch,2,3);
q = a.toString();
w = b.toString();
e = c.toString();
assertEquals("StringBufferabc",q);
assertEquals("StringBufferStringBufferabc",w);
assertEquals("StringBufferStringBufferStringBufferc12",e);
}
  • 单元测试的好处

    单元测试可以帮助我测试一些边界,异常情况,就比如说我的结对项目,运行完之后往往找不到出错点,有很多细节问题都没有考虑到代码中,这是通过单元测试检测出一些bug,因此可以对产品代码加以修改和补充,完善产品代码,写出更加健全符合要求的程序。

代码托管Link

2018-2019-20175205实验二面向对象程序设计《Java开发环境的熟悉》实验报告

参考博客

org.junit不存在