BUAA-OO pre2-面向对象先导

pre2-面向对象先导

基础知识

java的“对象”

在现实中,拿一条狗来举例,它的状态有:名字、品种、颜色,行为有:叫、摇尾巴和跑。

对比现实对象和软件对象,它们之间十分相似。软件对象也有状态和行为。软件对象的状态就是属性,行为通过方法体现。在软件开发中,方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成。

java的“类”

类可以看成是创建 Java 对象的模板。例如,public class dog是一个类,dog puppy就是这个类下的一个对象。

只包含属性的类和C的结构体相似。

构造一个类

java类使用变量定义数据域,其中数据域应当定义为private类型进行封装。

public class Bookset {
    //类下定义的变量(类似结构体中的变量)
    private String name;
    public double price;
    public int num;

   
    //构造函数(一般命名和类的名称相同)
    public Bookset(String name,double price,int num)
    {
        this.name = name;
        this.price = price;
        this.num = num;
    }
}   
类的方法

java类使用方法定义行为。

 	//访问属性
    public String getName() {
        return name;
    }
    
   //修改属性
    public void setName(String name) {
        this.name = name;
    }

输入输出

import java.util.Scanner

Scanner in = new Scanner(System.in);
int a = in.nextInt();
double b = in.nextDouble();
String nextline = in.nextLine();

System.out.println("Hello world!");
System.out.print("a+b+nextline");

容器

java中不推荐使用静态数组,一般用容器作为替代,常见容器如ArrayList,HashMap,HashSet,LinkedList等,此处先介绍ArrayList

ArrayList

ArrayList 是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。

初始化
import java.util.ArrayList; // 引入 ArrayList 类

ArrayList<E> objectName =new ArrayList<>();  // 初始化
  • E: 泛型数据类型,用于设置 objectName 的数据类型,只能为引用数据类型(即为基本类型的包装类)。

  • 在这里插入图片描述

  • 此外,BigInteger、BigDecimal 用于高精度的运算,BigInteger 支持任意精度的整数,也是引用类型,但它们没有相对应的基本类型。

  • objectName: 对象名。

常见方法
方法描述
add()将元素插入到指定位置的 arraylist 中
addAll()添加集合中的所有元素到 arraylist 中
clear()删除 arraylist 中的所有元素
clone()复制一份 arraylist
contains()判断元素是否在 arraylist
get()通过索引值获取 arraylist 中的元素
indexOf()返回 arraylist 中元素的索引值
removeAll()删除存在于指定集合中的 arraylist 里的所有元素
remove()删除 arraylist 里的单个元素
size()返回 arraylist 里元素数量
isEmpty()判断 arraylist 是否为空
subList()截取部分 arraylist 的元素
set()替换 arraylist 中指定索引的元素
sort()对 arraylist 元素进行排序
toArray()将 arraylist 转换为数组
toString()将 arraylist 转换为字符串
ensureCapacity()设置指定容量大小的 arraylist
lastIndexOf()返回指定元素在 arraylist 中最后一次出现的位置
retainAll()保留 arraylist 中在指定集合中也存在的那些元素
containsAll()查看 arraylist 是否包含指定集合中的所有元素
trimToSize()将 arraylist 中的容量调整为数组中的元素个数
removeRange()删除 arraylist 中指定索引之间存在的元素
replaceAll()将给定的操作内容替换掉数组中每一个元素
removeIf()删除所有满足特定条件的 arraylist 元素
forEach()遍历 arraylist 中每一个元素并执行特定操作

继承

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

extends

extends 只能继承一个类。

class 父类 {
}
 
class 子类 extends 父类 {
}
implements

使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

public interface A {
    public void eat();
    public void sleep();
}
 
public interface B {
    public void show();
}
 
public class C implements A,B {
}
方法

super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。

class Animal {
  void eat() {
    System.out.println("animal : eat");
  }
}
 
class Dog extends Animal {
  void eat() {
    System.out.println("dog : eat");
  }
  void eatTest() {
    this.eat();   // this 调用自己的方法
    super.eat();  // super 调用父类方法
  }
}

异常

捕获异常
try
{
   // 程序代码
}catch(ExceptionName e1)
{
   //Catch 块
}

Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。

如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。

实例:

import java.io.*;
public class ExcepTest{
 
   public static void main(String args[]){
      try{
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

可以在catch块后再添加catch块形成多重捕获。

抛出异常

如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。

实例:

import java.io.*;
public class className
{
   public void withdraw(double amount) throws RemoteException, InsufficientFundsException
   {
       // Method implementation
   }
   //Remainder of class definition
}

一个方法抛出多个异常↑。

finally关键字

finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行。

实例:

try{
  // 程序代码
}catch(异常类型1 异常的变量名1){
  // 程序代码
}catch(异常类型2 异常的变量名2){
  // 程序代码
}finally{
  // 程序代码
}
自定义异常类型
//自定义异常类,继承Exception类
public class InsufficientFundsException extends Exception
{
  //此处的amount用来储存当出现异常(取出钱多于余额时)所缺乏的钱
  private double amount;
  public InsufficientFundsException(double amount)
  {
    this.amount = amount;
  } 
  public double getAmount()
  {
    return amount;
  }
}



public class CheckingAccount
{
  //balance为余额,number为卡号
   private double balance;
   private int number;
   
  //方法:取钱
   public void withdraw(double amount) throws InsufficientFundsException
   {
      if(amount <= balance)
      {
         balance -= amount;
      }
      else
      {
         double needs = amount - balance;
         throw new InsufficientFundsException(needs);
      }
   }
} 



public class BankDemo
{
   public static void main(String [] args)
   {
      CheckingAccount c = new CheckingAccount(101);
      System.out.println("Depositing $500...");
      c.deposit(500.00);
      try
      {
         System.out.println("\nWithdrawing $100...");
         c.withdraw(100.00);
         System.out.println("\nWithdrawing $600...");
         c.withdraw(600.00);
      }catch(InsufficientFundsException e)
      {
         System.out.println("Sorry, but you are short $" + e.getAmount());
          //打印异常栈
         e.printStackTrace();
      }
    }
}

task5似乎没有啥新的知识点。。。

字符串比较

str.equals(str2)

作业简介

task1

构造基本的书架类和访问、修改方法即可,注意浮点数在double精度范围内,整数在long的范围内。

task2

每个Bookset作为一个元素,构造ArrayList类作为书架。

public class Bookcase {
    private ArrayList<Bookset> booksetArrayList = new ArrayList<>();
}

注意:

//容器对应指针,需要初始化
for (int i = 0; i < n; i++) {
    Bookcase bookset = new Bookcase();
    bookcaselist[i] = bookset;
}

对于每个操作,分别构造一个方法,例如查询丛书总价:

//查询书架丛书的总价
public BigDecimal getTotal() {
    int i;
    BigDecimal totalprice = new BigDecimal(0.0);
    for (i = 0; i < booksetArrayList.size(); i++) {
        totalprice = totalprice.add(booksetArrayList.get(i).getTotal());
    }
    return totalprice;
}

坑点

  • 数据求和时可能超出精度范围,因此需要使用BigInterger等类型,尤其需要注意该类型的转换方法。
  • (经讨论区dl提出)即使书架类的丛书总价求和方法采用了 BigDecimal 来求和,但如果单种丛书的 totalPrice 溢出也会导致程序错误。

task3

数据读取:

因为每行数据都可能不相同,因此建议直接读取一行数据,再用split函数进行分割,每次需要使用的数据直接用values[n]即可。

Scanner in = new Scanner(System.in);
String inline = in.nextLine();
String[] values = inline.split(" ");

继承关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dKX3ujnV-1614595384755)(D:\QQ\DATA\2987805870\FileRecv\MobileFile\0E786DBB52665BC89404C10DC2C5F60F.png)]

依次建立几种图书类后,其他方法都可以从父类继承,只需重新定义构造函数和对新增属性的访问、修改方法可,以math类为例:

public class Math extends OtherS {
    //声明数据域
    private Math(String type, String name, double price, long num, long year) {
        super(type, name, price, num, year);
    }
    private long grade;

    //构造函数
    public Math(String type, String name, double price, long num, long year, long grade) {
        super(type, name, price, num, year);
        this.grade = grade;
    }

    //访问方法
    public long getGrade() {
        return grade;
    }
}

工厂模式:

工厂模式主要解决接口选择的问题。

即定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

在本题中,即创建新的丛书时,根据题目需要进行创建,具体实现如下:

case ("OtherA"): {
    long age = Long.parseLong(values[6].trim());
    Bookset book = new OtherA(type, name, price, num, age);
    bookcaselist[serial].AddBook(book);
    break;
}

注意:

可以用trim()函数清除字符串前后的空格。

task4

根据题目要求定义4种异常类型,在main或者Bookcase类里面使用try catch语句进行捕获即可。

坑点:

  • 对于第一种操作而言,捕获异常的类型应该时先判断是不是空书架,再判断是否有名为name的书。

task5

新增加了 一个合并操作,也只需要针对这个操作添加相应的方法即可。

此处由于需要判断是否为同种书,我采用了较笨的逐个遍历的方法,先将case1的书全部复制到newcase,再将newcase的书和case2逐个比较判断。

此处判断用了一点技巧:先看书名,如果书名相同再看类型;类型都相同则比较价格,最后判断其他特有属性。这样可以减少比较次数。

private static boolean Compare(Bookset book, Bookset book2) {
    if (book.getType().equals(book2.getType())) {
        if ((book.getPrice() - book2.getPrice()) > 1e-5
                || (book2.getPrice() - book.getPrice()) > 1e-5) {
            return false; } else {
            switch (book.getType()) {
                    
                //以novel为例
                case "Novel": {
                    Novel son = (Novel) book;
                    Novel son2 = (Novel) book2;
                    if ((son.getAge() == son2.getAge())
                            && (son.getFinish() == son2.getFinish())) {
                        return true; } else {
                        return false; } }
                default:
                    throw new IllegalStateException("Unexpected value: " + book.getType()); }
        }
    } else {
        return false;
    }
}

坑点:

  • 复制书架不能直接使用bookcase.clone()!这样复制过去的是指针而非书中的元素,因此我新写了一个Clone方法,利用原书架中的丛书的值生成新对象,再逐个复制。

  • public void CloneBook(Bookset bookorigin) {
        String type = bookorigin.getType();
        String name = bookorigin.getName();
        double price = bookorigin.getPrice();
        long num = bookorigin.getNum();
        switch (type) {
        	//以Other为例
            case ("Other"): {
                Bookset book = new Bookset(type, name, price, num);
                booksetArrayList.add(book);
                break;
            }
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值