Java第三次作业

Deadline: 2018-4-19 23:00

一、学习要点

认真看书并查阅相关资料,掌握以下内容:

掌握类的继承概念和设计
掌握构造方法的继承原则
掌握方法重写
掌握super键字和final关键字
掌握对象转型,理解通过向上转型实现对象多态。
掌握抽象类的设计
掌握接口的设计
掌握接口回调
理解简单工厂设计模式
理解抽象类和接口的区别
掌握包装类的应用
掌握对象的比较方法和比较器的使用
学习使用日期操作类
学习匿名内部类的使用
二、作业要求

发布一篇随笔,主要包括以下几部分的内容:

(一)学习总结

1.阅读下面程序,分析是否能编译通过?如果不能,说明原因。应该如何修改?程序的运行结果是什么?为什么子类的构造方法在运行之前,必须调用父 类的构造方法?能不能反过来?

class Grandparent {
    public Grandparent() {
        System.out.println("GrandParent Created.");
    }
    public Grandparent(String string) {
        System.out.println("GrandParent Created.String:" + string);
    }
}
class Parent extends Grandparent {
    public Parent() {        
        System.out.println("Parent Created");
        super("Hello.Grandparent.");
    }
}
class Child extends Parent {
    public Child() {
        System.out.println("Child Created");
    }
}
public class Test{
    public static void main(String args[]) {
        Child c = new Child();
    }
}

答:
编译不能通过,super关键字应放在子类构造方法的最前面,因为在实例化子类对象时要先调用父类的构造方法,隐含的一条语句是super();,也就是说super关键字在构造方法的第一行,若要调用含参的构造方法则同样需要将super放在第一条语句。不能反过来,可以说有了父类才会有子类,子类继承父类,那么首先要存在这样一个父类的空间,所以说不能反过来。
结果:

当没有super("Hello.Grandparent.");此语句时结果如下:

2.阅读下面程序,分析程序中存在哪些错误,说明原因,应如何改正?正确程序的运行结果是什么?

class Animal{
  void shout(){
      System.out.println("动物叫!");
  }
}
class Dog extends Animal{
      public void shout(){  
          System.out.println("汪汪......!");  
     }
      public void sleep() {
       System.out.println("狗狗睡觉......");
      } 
}
public class Test{
    public static void main(String args[]) {
        Animal animal = new Dog(); 
        animal.shout();
        animal.sleep();
        Dog dog = animal;
        dog.sleep(); 
        Animal animal2 = new Animal();
        dog = (Dog)animal2;
        dog.shout();
    }
}

答:
<1>animal.sleep();错误,向上转型只能调用子类继承、重写过的方法而不能调用子类的新方法和父类原有的方法
<2>Dog dog = animal;错误,下转型时要注意,父类是可以有多个子类的,而子类只能有一个父类,所以说下转型需要让父类对象清楚这是否为他的子类才可以决定转型与否
<3>dog = (Dog)animal2;错误,强制类型转换的前提是父类引用指向的对象的类型是子类的时候才可以进行强制类型转换,如果父类引用指向的对象的类型不是子类的时候将产生java.lang.ClassCastException异常
改正:
<1>在Animal类里加入一个空的sleep方法
<2>将语句改为Dog dog = (Dog) animal;
<3> 将子类实例赋给父类对象,Animal animal2 = new Dog();
结果:

3.运行下列程序

class Person { 
   private String name ; 
   private int age ; 
   public Person(String name,int age){ 
         this.name = name ; 
         this.age = age ; 
   } 
}
public class Test{  
      public static void main(String args[]){ 
             Person per = new Person("张三",20) ; 
             System.out.println(per);
             System.out.println(per.toString()) ; 
  } 
}

(1)程序的运行结果如下,说明什么问题?
Person@166afb3
Person@166afb3

答:说明toString方法不写也可以调用,并且对象名称隐含的包括toString方法

(2)那么,程序的运行结果到底是什么呢?利用eclipse打开println(per)方法的源码,查看该方法中又调用了哪些方法,能否解释本例的运行结果?

    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

答:这是源码中的内容,返回了该类的类名、'@'字符、引用地址,所以结果为Person@166afb3

(3)在Person类中增加如下方法

public String toString(){ 
        return "姓名:" + this.name + ",年龄:" + this.age ; 
 } 

重新运行程序,程序的执行结果是什么?说明什么问题?
结果:

答:这说明了所有的类均为Object类的子类,因为当该类添加了toString方法后,覆盖了原有的方法,那么对象调用的就是子类重写过后的方法,即子类重写了父类方法

4.汽车租赁公司,出租汽车种类有客车、货车和皮卡三种,每辆汽车除了具有编号、名称、租金三个基本属性之外,客车有载客量,货车有载货量,皮卡则同时具有载客量和载货量。用面向对象编程思想分析上述问题,将其表示成合适的类、抽象类或接口,说明设计思路。现在要创建一个可租车列表,应当如何创建?
<1>首先创建一个出租汽车抽象类(或者父类、接口此处以抽象类举例),它具有编号、名称、租金三个基本属性,并附加一个标记属性(int),租借出去后为0,未租借出去为1,静态方法welcome和welcomenext
<2>定义客车类、货车类、皮卡类均继承 出租汽车抽象类,并且客车具有自己的载客量属性,货车具有自己的载货量属性、皮卡则具有载客量和载货量两个自己的属性分别写出写出相应的getter 和 setter 方法以及toString方法
<3>可租车列表需要创建三个对象的对象数组,来表示有几辆客车、货车和皮卡,当租借成功后,应该将租借的对象的标记属性改为0,当显示库存时为0的显示无法租借的字样
<4>在租借开始显示菜单信息参数为三个对象数组,并显示各种车目前的辆数
<5>定义一个显示库存的方法,参数为出租汽车类型的对象数组,利用循环显示该类的对象数组的成员信息
<6>当租借的对象其标记属性为0时,显示租借失败,为1则返回租借成功
5.阅读下面程序,分析代码是否能编译通过,如果不能,说明原因,并进行改正。如果能,列出运行结果

    interface Animal{    
        void breathe();
        void run();
        void eat();
    }
    class Dog implements Animal{
        public void breathe(){
            System.out.println("I'm breathing");
        }
        void eat(){
            System.out.println("I'm eating");
        }
    }
    public class Test{
        public static void main(String[] args){
            Dog dog = new Dog();
            dog.breathe();
            dog.eat();
        }
    }

答:不能。
原因:<1>Dog为非抽象类,必须重写接口的所有方法
<2>需要指明eat方法的权限范围,并且不能低于父类权限范围

改正:
<1>在Dog类中添加public void run()方法,如:

    public void run() {
	    System.out.println("I'm running");		
    }

并在Test中调用
<2> 在void eat()前,加public

结果:

6.其他需要总结的内容。
<1>接口:
(1)接口中只存在常量和抽象方法,并且默认其中的方法为抽象方法
(2)Java中的接口实现多态,一个类可以有多个接口解决了Java中单继承的弊端
(3)接口实现为辐射式设计
<2>抽象类:
(1)抽象类中可以有抽象方法也可以有普通方法
(2)抽象类不能用new实例化,但他的子类可以,利用向上转型
(3)子类非抽象类时必须重写抽象类中所有的抽象方法
<3>对象转型:
(1)上转型:子类实例赋给父类对象,上转型调用方法时,只能调用子类继承和重写过的方法,而不会是子类新增的方法,也不会是父类原有的方法
(2)下转型:父类实例赋给子类对象,通过instanceof关键字来判断某一个对象是否为某一个类的或者是它的子类的一个实例。

(二)实验总结

本次实验包括实验四和实验五两次的内容:
对完成实验内容过程中遇到的问题、解决方案以及程序的设计思路和思考等进行归纳总结。
格式如下:
题目:

程序设计思路:
<1>定义一个银行类和一个交易类
<2>定义两个静态方法welcome()和welcomenext(),方便在交易类中调用(不需要创建对象直接通过类名调用)
<3>构造方法需要接受的用户信息有用户名、密码、交易额,在构造方法中令交易额减去10开卡费就是当前余额
<4>存款需要修改余额,即让余额直接加上本次交易额即可
<5>取款需要验证密码和余额,首先用equalsIIgnoreCase()方法判断密码是否正确,不正确则返回0,正确则继续判断余额是否小于本次交易额,若小于则返回-1,大于则返回1,通过trade类判断
<6>Trade类编写一个菜单方法,调用菜单和switch case结构,选择开户、存款、取款和退出,分别调用Bank类的方法
问题:无
需注意问题:nextline()会读入回车,所以在开户时输入用户密码用next()

题目:

程序设计思路:
<1>定义员工类为父类,编写无参和含参的构造函数,以及每个属性相应的set和get方法,还有一个toString方法返回员工的基本属性
<2>定义管理层类,继承员工类,具有员工类的属性,并设立其职务和年薪
<3>定义职员类,继承员工类,具有部门和月薪
<4>测试类将数据存入一个管理层类对象数组和一个职员类员工数组
问题1:没有正确理解向上转型的使用方法,写了一个错误的向上转型(已保留)
解决方案:多看书emmmmm,看下理论知识,理论稍微有些薄弱

题目:

程序设计思路:
<1>定义一个平面类的抽象函数,他的子类有矩形、三角形、圆形,分别实现求周长、求面积,三角形的稍微特殊,三角形需要先判断是否可以构成三角形,所以通过边来判断是否可以为一个三角形,那么只需要随机产生三条边就可以了,再判断a+b>c?大于则满足,小于则让c在a+b的范围内产生一个随机数,其他均类似,已知三条边就可以确定一个三角形,并可以通过海伦——秦九昭公式算出面积
<2>定义一个立体图形类,他的子类有圆柱、圆锥、球,分别实现求表面积、体积的问题
<3>测试类,通过一个答题小游戏的形式调用这些方法,第一回合为平面几何问题,答对加10分,答错不加分,第一回合结束后,让用户选择是否继续,并告知接下来的题目是立体几何问题答对加15分答错不加分,若用户选择继续则调用立体类图形的方法,如用户选择退出给出提示语“BeyBey”
问题1:double的结果,在3.14*5或者5的倍数时会出现本来应该是显示两位小数点后两位却显示出一串小数点后几位,导致回答的答案和真正的答案不匹配
原因:计算时精度失真
解决方案:让用户输入的答案和真正的答案做差取绝对值,当绝对值在1e-6之间时,判定用户回答正确,显示答案时控制输出格式即可

题目:

程序设计思路:
<1>定义了一个Animal的抽象类,包含food属性和name属性以及两个抽象方法(传数组的和传单个对象的)
<2>利用上转型,将eat方法里面的形参定义为Animal对象,实参为子类实例
<3>定义饲养员类,调用Animal的eat方法,当定义一个food属性时,可以把代码简化
问题1:第一遍没有读懂题目,贸然就做题,没有加Feeder方法就很尴尬,没办法在对象数组做实参的测试类里用对象来调用相应的传数组的eat方法
原因:忘记弄Feeder类
解决方案:修改其他的几个动物类加一个food属性,让people随意为Animal子类的一个对象,通过people来广义利用向上转型实现功能,这样修改过后的几个类不仅很方便还解决了这个问题

题目:

程序设计思路:
<1>定义一个宠物接口,含有获得价格、数量、种类、品种、编号、改变数量的方法
<2>定义宠物猫类和宠物狗类,重写接口的方法并增加:每个属性相应的set方法、构造方法、 展示基本信息的方法
<3>定义一个宠物商店类,先写构造方法即定义宠物商店的大小,再写放入宠物的方法,然后展示宠物,最后是购买宠物的方法(还尝试了关键字查找的方法)
<4>定义一个模拟购买交易的类。先创建宠物商店,再存放宠物,写一个菜单,分别调用宠物商店里的函数
问题1:将宠物商店中的宠物类型的数量当做宠物的数量
原因:未能充分理解宠物类的数量属性
解决方案:在宠物商店的属性中增加一个宠物总量属性
问题2:忽略了购买完毕后宠物数量会减少的问题
解决方案:在宠物接口中,通过set宠物数量的方法来实现对宠物数量的改变

题目:

程序设计思路:
<1>设置一个接口Animal,包含cry()和getAnimalName()的方法
<2>定义一个猫类和一个狗类实现Animal接口,分别重写cry()、getAnimalName()方法,拥有自己的属性name
<3>定义模拟器类,调用猫类和狗类的方法
<4>测试类中创建一个模拟器类对象,调用其playSound()方法,分别传递一个猫类和狗类的匿名对象
问题:无

题目:

程序设计思路:
跟着PPT一步一步来,emmmmm真心没的讲,老师的思路跟着走完全不会出问题
问题:无

题目:

程序设计思路:
<1>取消实验三的Date类,在Employee类中直接用Date定义birthday和worktime,修改相应的getter和setter方法,toString方法中用SimpleDateFormat类的format()方法转换为字符串形式
<2>compareTo接口比较有多少毫秒,毫秒多则生日小,从大到小排序
<3>测试类通过Arrays.sort()方法进行排序
<4>定义一个类实现comparator接口,实现将生日从大到小输出排列
<5>定义一个comparator()接口类,实现比较
问题1:在调用sdf.parse()的方法时,编译出错
原因:忽略了throws Exception
解决方案:熟悉SimpleDateFormat类的使用方法
问题2:compareTo接口排序不正常
原因:在getbirthday()方法里返回的是字符串
解决方案:修改返回类型
问题3:初始时,忘记了Dtae类有直接获得年月日的方法,compareTo接口的方法如下:

		//不知道哪错了反正运行不出正确结果
		String str1=sdf.format(this.getbrithday());//日期转字符串
		String str2=sdf.format(o.getbrithday());
		String cstr1[]=str1.split("-");//字符串按“-”分割
		String cstr2[]=str1.split("-");
		int[] date1 = new int[cstr1.length];//存放this.birthday的数据
		int[] date2 = new int[cstr2.length];//存放o.birthday的数据
		for(int i=0;i<cstr1.length;i++) {//字符串转int数组
			date1[i]=Integer.parseInt(cstr1[i]);
		}
		for(int i=0;i<cstr2.length;i++) {//字符串转int数组
			date2[i]=Integer.parseInt(cstr2[i]);
		}
		for(int i=0;i<date1.length;i++) {//比较
			if(date1[i]>date2[i]) {
				return -1;
			}
			else if(date1[i]<date2[i]) {
				return 1;
			}
		}
		return 0;

原因:未知
解决方案:用Date类的getTime()的方法获得从生日到现在的精确到毫秒的时间来比较
问题4:修改问题3后,排序仍存在小错误,当我修改好没有三个相同年,不同月的以后,就没有问题了,打算实验课上问一下老师

原因:月份忘记了大写,导致排序出现三个相同年份的生日就会出错
解决方案:改正为MM
问题5:调用comparator()方法总是编译出错
原因:调用此比较器时,使用方法错误
解决方案:查书,正确格式为Arrays.sort(employee, new Birthcomparator());
(三)代码托管(务必链接到你的项目)
https://gitee.com/hebau_java_cs16/java_cs02_liu_meng

posted @ 2018-04-18 11:51  宁萌啊  阅读(403)  评论(2编辑  收藏  举报