怎么结构化的设计一个java程序?学会使用注释的方法。
去看UML图设计程序,从这个方面去做题目,对规范设计程序很有帮助!!!(有关联关系、依赖关系的UML图。)
花大量时间思考这个问题。
问题一:模拟收音机使用电池,收音机使用一次,电池减少10.(可以使用不同的电池类型)
属于引用类型参数的传值问题。
解答:首先创建一个主类,看会用到哪些参数。(pass)更改:应该首先是创建类,最后才是创建主类去调用这些其它类的方法。
问题二:一个手机可以组合任何SIM卡,模拟手机和SIM卡的组合关系。
属于类与对象中的组合和运用知识点。
解答:使用注释的方法,注释://创建SIM卡,能存放号码,能查看号码
//创建手机 ,可以更改SIM卡,可以查看号码
然后就能通过主类去存放号码,可以更改手机的SIM卡。
例题模型:最常用的一种结构使用。计算梯形的面积
首先 //创建梯形,设置上底 , 设置下底 , 设置高 ,设置计算公式
然后调用主类。主类不参与计算,只是调用数字进去和打印结果。
例如下面这个程序就描述了一个程序的设计过程,自己设计的。
在讲一遍过程:首先不要去写主类,先写需要的类,首先就是写注释:
//创建梯形 ,设置上底(一个方法) ,设置下底(一个方法),设置高(一个方法),计算公式(一个方法)
然后等功能都差不多实现了,就可以写主类,
// 传上底,传下底,传高,计算结果。
package com;
public class Lader {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Area area = new Area();
area.seta(12);
area.setb(12);
area.seth(10);
double s=area.area();
System.out.println(s);
}
}
class Area{
double 上底,下底,高;
//设置上底
void seta(double a){
this.上底=a;
}
//设置下底
void setb(double b){
this.下底=b;
}
//设置高
void seth(double h){
this.高=h;
}
//计算面积
double area(){
return (上底+下底)*高*1/2;
}
}
问题三:
第四章 类与对象 应用举例
问题描述:对有理数进行封装,能进行四则运算,能计算前n项和,能用分数、小数表示。
看书,它画了一个UML图,看图写代码。
package com;
public class Lader {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Rational r1 = new Rational();
r1.setNumberatorAndDenominator(1, 5);
Rational r2 = new Rational();
r2.setNumberatorAndDenominator(3, 2);
Rational result=r1.add(r2);
int a = result.getDenominator();
int b = result.getNumberator();
System.out.println("1/5 + 3/2 ="+a+"/"+b);
//意料之外,没想到result,a,b可以重复使用。因为每次result都被重新赋予了值,所以对上一个结果没有影响。
result = r1.sub(r2);
a = result.getDenominator();
b = result.getNumberator();
System.out.println("1/5 + 3/2 ="+a+"/"+b);
}
}
class Rational{
int numerator,denominator;
//设置分子和分母
void setNumberatorAndDenominator(int n,int m){
this.numerator=n;
this.denominator=m;
}
//败笔:疏忽要求得到分子与分母,在下面那个加法运算中,因为缺少这一步而卡住。
int getNumberator(){
return numerator;
}
int getDenominator(){
return denominator;
}
//使用加法运算, 这里注意一下,题目给的a和b是1,5以及3,2是固定的
Rational add(Rational r){
int a = r.getNumberator();
int b = r.getDenominator();
//败笔:这里注意一下numerator是全局的分子,也就是说一开始设置时,它就会存在
int newNumberator = numerator*b +denominator*a;
int newDenominator = denominator*b;
//败笔:以为需要返回两个值,一个新分子,一个新分母,
//(但是发现返回两个值的情况好像除非返回元组才会这样,于是把它返回改成对象就可以了,这样就可以调用对象的方法得到新分子和新分母的值)
Rational result = new Rational();
result.setNumberatorAndDenominator(newNumberator, newDenominator);
return result;
}
//减法的方法和加法差不多,只要改一个符号
Rational sub(Rational r){
int a = r.getNumberator();
int b = r.getDenominator();
int newNumberator = numerator*b - denominator*a;
int newDenominator = denominator*b;
Rational result = new Rational();
result.setNumberatorAndDenominator(newNumberator, newDenominator);
return result;
}
//败笔:计算多个有理数相加,以为可以放在封装类,但不现实,因为不知道有多少个有理数相加
//败笔:以为算法都放在其它类。请修改笔记。
}
问题四(流水线):
搭建流水线,和UML图有点不太一样!,但是,后面我们会学关于依赖和关联关系的UML图,所以其实这个还是属于UML图范围内的。
问题描述:模拟歌手比赛,评委打分,去掉一个最高分和最低分,得到最后的平均数即最后的得分。
注释://创建歌唱比赛SingGame类,这个就是主类
//InputScore类,录入分数
//DelScore类,删除分数
//ComputerAver类,平均得分
我的代码和书上的稍微有点不一样,但是也用到的是流水线的方式,大概流水线怎么用心里有点数了。记住掌握流水线的方法吧,它可以实现很通顺的写代码的感觉。它的优点是可以实现将本类不方便传参数的值或数组交给下一个类。(而我们一般的方式都是在写一个方法用来获取数据,但是如果碰到遍历的情况,就不太适用。或许可以用全局变量的方式,但是我现在不太清楚可不可以使用。)
package com;
import java.util.Arrays;
import java.util.Scanner;
//歌唱比赛,得到最后的分数.//wc所以这是主函数,之前一直以为这是个部分
public class SingGame {
public static void main(String args[]){
InputScore input = new InputScore();
input.inputscore();
}
}
//录入分数, 没学流水线之前:返回分数集合!!!
class InputScore{
// double score[]; //不能这样创建,这样创建的是一个空指针
int number;
void inputscore(){
System.out.println("请输入评委数量:");
Scanner scanner = new Scanner(System.in);
number = scanner.nextInt();
System.out.println("请输入各个评委的分数:");
double score[] = new double[number];
for (int i = 0; i < number; i++) {
score[i] = scanner.nextDouble();
}
// System.out.println(Arrays.toString(score));
//正确的方法,在这里调用delCcore的类,这样就可以继承score这个分数集合。
DelScore del = new DelScore();
del.delete(score);
}
//查找录入分数,于是出现问题了,因为分数集合不是全局变量,在这里就会报错。
// void getscore(){
// return Arrays.toString(score);
// }
}
class DelScore{
void delete(double score[]){
java.util.Arrays.sort(score);
System.out.println("去掉一个最高分"+score[score.length-1]);
System.out.println("去掉一个最低分"+score[0]);
double b[] = new double[score.length-2];
for (int i = 1; i < score.length-1; i++) {
b[i-1] = score[i];
}
// System.out.println(Arrays.toString(b));
ComuterAver computer = new ComuterAver();
computer.giveAver(b);
}
}
class ComuterAver{
double sum=0;
double aver;
void giveAver(double b[]){
for (int i = 0; i < b.length; i++) {
sum+=b[i];
}
aver=sum/b.length;
System.out.println("选手最后得分:"+aver);
}
}
练习:书本p111。第四题:编程题,用类描述计算机中CPU的速度和硬盘的容量。
问题五(继承关系的UML):
使用子类继承的方法可以减少很多代码量的编写,比如关于父类的属性和方法就可以交给子类的对象去完成。(像前面的类型,我们都设置了一个设置某一个量和获取某一个量,如果使用继承关系,就不需要再多加那两个方法。(set 和 get 的方法就可以省略不用了))
例子:
package com;
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Student zhang = new Student();
zhang.age = 12;
zhang.number = 123456;
zhang.showPeopleMess();
zhang.tellNumber();
int result = zhang.add(12, 12);
System.out.println("会做加法12+12="+result);
}
}
//定义人的属性
class People{
int age,leg=2,hand=2;
void showPeopleMess(){
System.out.printf("%d岁,%d只脚,%d只手\n",age,leg,hand);
}
}
//设置学生的学号
class Student extends People{
int number;
void tellNumber(){
System.out.println("学号:"+number);
}
//会做加法
int add(int x,int y){
return x+y;
}
//会做乘法
int multi(int x,int y){
return x*y;
}
}
方法重写可以隐藏继承的方法。使用super可以继续使用被隐藏的变量。
一般出现的情况就是,在子类里面将父类的方法重写了一遍,这个时候子类重写的这个方法就继承不了父类的变量。如果要用,就使用super关键字。
final类不能被继承。
普通类中的final方法不能被重写。
问题六:abstract类的使用
它可以先声明需要的一些方法,也是一种思考模式。(抽象一些行为标准,不给予实现)
GirlFriend friend = new ChinaGirl(); //这就是上转型对象,只用于父类与继承子类中。
//第一次碰到这种用法,前面是创建父类的空间,后面初始化是分配继承的子类。
问题描述:
男孩找女朋友,用abstract类封装他女朋友所具有的行为。
典型代码:
package com;
public class Gril {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Boy xieqi = new Boy();
GirlFriend friend = new ChinaGirl();//第一次碰到这种用法,前面是创建父类的空间,后面初始化是分配继承的子类。
xieqi.setGirlFriend(friend);
xieqi.showGirlFriend();
friend = new AmericanGril();
xieqi.setGirlFriend(friend);
xieqi.showGirlFriend();
}
}
//抽象女朋友的行为,说和煮
abstract class GirlFriend{
abstract void speak();
abstract void cooking();
}
//中国女朋友
class ChinaGirl extends GirlFriend{
void speak(){
System.out.println("你好");
}
void cooking(){
System.out.println("水煮鱼");
}
}
//美国女朋友
class AmericanGril extends GirlFriend{
void speak(){
System.out.println("hello");
}
void cooking(){
System.out.println("roast beef");
}
}
//注意:不需要继承。
class Boy{
GirlFriend friend;
//交女朋友
void setGirlFriend(GirlFriend friend){
this.friend=friend;
}
//展示女朋友的行为
void showGirlFriend(){
friend.speak();
friend.cooking();
}
}
问题七:面向抽象编程
会看UML图。属于第五章 子类与继承 的应用举例。
问题描述:用类封装手机的基本属性和功能,要求手机既可以使用移动公司的SIM卡,也可以使用联通公司的SIM卡(可以使用任何公司的SIM卡)。
代码实现:
package com;
public class MobileTelephone {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
SIM card = new Unicom();
card.setNumber("123456");
Mobilephone phone = new Mobilephone();
phone.useSim(card);
card = new Mobile();
card.setNumber("54321");
phone.useSim(card);
}
}
// 抽象化要使用的SIM卡,定义卡号码,卡名字
abstract class SIM {
// 注意是String类型,因为我定义的是返回对象
abstract String giveNumber();
abstract String giveCorpName();
abstract void setNumber(String s);
}
// 联通卡 ..必须全部重写抽象类的方法,不然会报错
class Unicom extends SIM {
String number;
void setNumber(String s) {
this.number = s;
}
String giveNumber() {
return number;
}
String giveCorpName() {
return "中国联通";
}
}
// 移动卡
class Mobile extends SIM {
String number;
void setNumber(String s) {
this.number = s;
}
String giveNumber() {
return number;
}
String giveCorpName() {
return "中国电信";
}
}
//定义手机类
class Mobilephone {
SIM card;
//使用某个类型的卡。
void useSim(SIM card) {
// card.setNumber("12345");
String name=card.giveCorpName();
String num = card.giveNumber();
System.out.println("使用的卡是:"+name);
System.out.println("手机号码是:"+num);
}
}
例题训练:
书本P143,看UML图编写程序。
代码分析:
在主类调用含有对象的方法有两种方式。
public static void main(String[] args) {
// TODO Auto-generated method stub
Simulator simulator = new Simulator();
//原来还可以在这个里面使用new的方法,涨见识了。看看其它方式
simulator.playSound(new Dog());
simulator.playSound(new Cat());
// simulator.playSound(animal)
//尝试使用第二种方式
// Animal dog = new Animal(); //不能使用这种方式,抽象类相当于一个接口
// simulator.playSound(Animal dog);
//在前面学到的第二种方式。
simulator.playSound(simulator.getAnimal());
}
playSound(Animal animal){} //这是playSound的方法。使用像这种里面是一个类型的参数的方法,有两种方法使用:
第一种:new Dog() //第一种最简便
第二种:对象.getAnimal()。 //第二种方式需要去simulator类里面定义一个getAnimal方法,它的类型为Animal类型 ,使其返回对象。
问题八:面向接口编程(用法和前面抽象类一样)
使用关键词interface定义接口。(和抽象类相似。都是只定义方法,而不去实现)
接口里面的变量、方法都属于抽象变量和抽象方法。
应用举例:书本P155
设计广告牌,使设计的广告牌可以展示许多公司的广告词。
画UML图:这种类型的UML图建议记一下!这是一种直接面向接口的UML图的基本结构!!!
代码分析:
class AdvertisementBoard{
//原来接口是这样使用的,可以直接调用接口Adevertisement去创建对象。然后这个对象就能直接使用它们的子类了!
public void show(Adevertisement corp){
System.out.println(corp.getCorpName()+"的广告词如下");
//误区在这里,corp要调用一次才能使用
corp.showAdvertisement();
}
}
问题八:内部类与异常类
异常类的对象有三种方法可以调取获得有关异常的信息:
getMessage():String
printStackTrace():void
toString:String
说明几种常用的方法:
第一种:系统自带的异常类,例如:ArithmeticException异常类。
使用方法,如果是系统自带的异常类,那么可以不用throw去抛出异常对象。(相当于它默认有一个throw抛出异常。)
throw new 异常类()。
try {
int result=1/0;
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("出现算术异常"+e.getMessage());
}
它的完整的写法应该是:
try {
int result=1/0;
throw new ArithmeticException(); //多了这一句,因为是系统自带的,所以这一句可以不写
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("出现算术异常"+e.getMessage());
}
自定义异常类的写法:比上面多一个对自定义异常类的声明。
就是:throws 异常类. //注意一下throws关键词和throw不一样。
throws放在方法头上,throw放在方法体内。
异常类的常规用法:
一般都会分为两个类,try --catch语句放在主类中。
另外一个类用if语句决定抛出什么异常。
常规用法:
下面这个是主类。throw抛出异常的方法一般都不会放在主类里面。
RuntimeException异常类记一下,这个可以抛出字符串。
应用举例:
模拟货船装载集装箱,如果超重就拒绝装载。(可以用异常语句实现。只要出现异常就会中断执行。)
package com;
public class Test3 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
CargoBoat boat = new CargoBoat(1000);
try {
boat.loading(400);
boat.loading(700);
boat.loading(700);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e.getMessage());
}
}
}
class CargoBoat{
int realContent; //默认为0
int maxContent;
public CargoBoat(int max){
this.maxContent=max;
}
public void loading(int m){
realContent += m;
if(realContent>maxContent){
System.out.println("无法再装载"+m+"吨货物");
throw new RuntimeException("超重"); //抛出这个异常,下面的语句就不会在实现。
}
System.out.println("目前装载了"+realContent+"吨货物");
}
}