1. 本周学习总结

2. 书面作业

注释的应用:
(1)源文件注释采用 /** …… */,在每个源文件的头部要有必要的注释信息,包括:文件名;文件编号;版本号;作者;创建时间;文件描述包括本文件历史修改记录等。中文注释模版:

(2)类(模块)注释采用 /** …… */,在每个类(模块)的头部要有必要的注释信息,包括:工程名;类(模块)编号;命名空间;类可以运行的JDK版本;版本号;作者;创建时间;类(模块)功能描述(如功能、主要算法、内部各部分之间的关系、该类与其类的关系等,必要时还要有一些如特别的软硬件要求等说明);主要函数或过程清单及本类(模块)历史修改记录等。

使用类的注释与方法的注释为前面编写的类与方法进行注释,并在Eclipse中查看。(截图) ![](http://images2015.cnblogs.com/blog/1109779/201703/1109779-20170318125736823-1420589250.jpg)

2.1 将在网上商城购物或者在班级博客进行学习这一过程,描述成一个故事。(不得少于50字,参考QQ群中PPT的范例)

想描述一下关于手机听歌的一个过程,因为科研立项就是做的这个类似的,正好理一下思路。
  • (1)首先搜索想听的歌曲,因为有同名歌曲,所以还要再看看歌手名字
  • (2)然后选择歌曲到播放列表,喜欢这首歌可以把他放到“喜爱”分区里
  • (3)听歌过程中随时可以暂停播放,因为有播放列表,所以可以上一曲下一曲切换。看看进度条好像快听完了,想再听一遍。点击单曲循环。
  • (4)想看看刚才的歌词,把进度条拉回之前的位置

2.2 通过这个故事我们能发现谁在用这个系统,系统中包含的类及其属性方法,类与类之间的关系。尝试找到这些类与属性,并使用思维导图描述类、属性、方法及类与类之间的关系。

2.3 尝试使用Java代码实现故事中描述的这一过程(不必很完善),将来要在这个基础上逐渐完善、扩展成一个完整的面向对象的系统。(可选:加分)

3.分析ManagerTest.zip中的代码,回答几个问题:

3.1 在本例中哪里体现了使用继承实现代码复用?回答时要具体到哪个方法、哪个属性。

class Manager extends Employee
{
   /**
    * @param n the employee's name
    * @param s the salary
    * @param year the hire year
    * @param month the hire month
    * @param day the hire day
    */
   public Manager(String n, double s, int year, int month, int day)
   {
      super(n, s, year, month, day);
      bonus = 0;
   }
  • 这一部分使用了继承。Manager类继承了Employee类。属性包括姓名,基础薪水,年月日。继承的方法是计算工作日方法。

3.2 Employee类及其子类Manager都有getSalary方法,那怎么区分这两个方法呢?

  • 当子类和父类都有相同的字段,子类的字段就会代替或者隐藏父类的字段,子类方法中访问的是子类中的字段,父类方法中访问的是父类的字段。
  • 如果子类方法想访问父类中的同名字段,可以通过super关键字访问。
  • 但是:A x=new B();调用方法的时候,因为实际类型是B,所以永远调用子类B的方法。

3.3 文件第26行e.getSalary(),到底是调用Manager类的getSalary方法还是Employee类的getSalary方法。

  • for (Employee e : staff) e是Employee类的,因为是父类,所以调用的是Employee的getSalary方法
  • staff[0]=boss;e.getSalary()调用的是Manager类的方法。同一操作,e作用于不同的对象,产生不同的结果,多态的定义。
  • 动态绑定:程序运行的时候,我们程序的行为,特别是内存行为,可以按照需求改变,这种就叫动态绑定。这种改变对应到代码上就是不同的对象行为,不同的对象,对应的是不同代码,不同的代码对应又是不同的内存操作,不同的代码会有不同的名字。

3.4 Manager类的构造函数使用super调用父类的构造函数实现了代码复用,你觉得这样的有什么好处?为什么不把父类构造函数中的相关代码复制粘贴到Manager的构造函数中,这样看起来不是更直观吗?

  • 首先是简洁。代码太过繁杂,即使更直观,也会使代码整体冗余。重复代码太多,没有什么意义。反而是清晰简介的代码,让人一目了然,且不会因为长度而混乱。
  • 同时也方便子类重写方法中调用父类同名方法

4.Object类

4.1 编写一个Fruit类及属性String name,如没有extends自任何类。使用System.out.println(new Fruit());是调用Fruit的什么方法呢?该方法的代码是从哪来的?尝试分析这些代码实现了什么功能?

  • 输出Fruit的地址信息,如图

  • 因为Fruit类是自定义类,什么方法都没有。也没有定义构造函数,因为没有显式继承,所以默认继承Object类,系统默认一个Object类的无参构造函数。这个构造函数只能给对象开辟地址空间,不会完成初始化。由于Object的toString的返回值 return getClass().getName() + "@" + Integer.toHexString(hashCode());所以代码运行结果是一个地址。

4.2 如果为Fruit类添加了toString()方法,那么使用System.out.println(new Fruit());调用了新增的toString方法。那么其父类中的toString方法的代码就没有了吗?如果同时想要复用其父类的toString方法,要怎么操作?(使用代码演示)

  • 添加了toString()方法之后,代码运行结果```Fruit [name=null]````
  • 父类中的toString还是存在的,只是因为我们重写toString,父类的就被隐藏了。如果同时想要复用父类的,可以用super。
class Fruit11{
	private String name;

	@Override
public String toString() {
return "Fruit [name=" + name + "]"+super.toString();

}
}

4.3 Fruit类还继承了Object类的equals方法。尝试分析其功能?自己编写一个equals方法覆盖父类的相应方法,功能为当两个Fruit对象name相同时(忽略大小写),那么返回true。(使用代码证明你自己覆盖的eqauls方法是正确的)

  • equals方法源代码
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
  • 如果两个相等地址,返回true(比较的是对象的地址,所以在实际使用中,基本没什么太大用处。尤其是在对两个对象的比较时,基本都要重写equals)
  • instanceof(它的作用是判断其左边对象是否为其右边类的实例),如果传入的是字符串,则一个个字符进行比较判断,相同返回true。
public class Test{
    		public static void main(String[] arge){
    		
    		System.out.println(new Fruit(""));
    		Scanner in=new Scanner(System.in);
    		Fruit str=new Fruit(in.next());
    		Fruit str1=new Fruit(in.next());
    		if(str1.equals(str)){
    			System.out.println("相等");
    		}
    		else System.out.println("不相等");
    		
    		}	
    		}
    
    	class Fruit{
    	private String name;
    	
    	@Override
    	public String toString() {
    		return "Fruit [name=" + name + "]";
    	}
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		 this.name=name;
    	}
    
    	public Fruit(String name){
    		 this.name=name;
    	}
    
    
    	@Override
    	public int hashCode() {//重写equals方法的时候,一定要重写hashCode方法
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((name == null) ? 0 : name.hashCode());
    		return result;
    	}
    	
    	
    	@Override
    	public boolean equals(Object obj){		
    		if(this==obj)
    			return true;
    		if(obj==null)
    			return false;
    		if(getClass()!=((Fruit) obj).getClass())
    			return false;
    		Fruit other=(Fruit) obj;
    		if(name==null){
    			if(other.name!=null)
    				return false;
    		}
    		else if(!name.equalsIgnoreCase(other.name))//这句一直没想到怎么办,虽然找到了equalsIgnoreCase的方法,但是之前一直不知道该在哪里用,感谢大佬
    			return false;
    		return true;
    	}	
    }

4.4 在4.3的基础上使用ArrayList<Fruit> fruitList存储多个fruit,要求如果fruitList中已有的fruit就不再添加,没有的就添加进去。请编写相关测试代码。并分析ArrayList的contatins方法是如何实现其功能的?

  • 关于这个,首先不允许重复。从查到的资料上来看,List是一个有序的,允许重复的列表。
  • HashSet比较是根据HashCode的值来比较的,HashCode值是根据内存地址换算出来的。因为我们在重写equals的时候也对hashCode进行了重写,所以对于相同的对象,就不插入了。
  • 综上,用HashSet可能更好点......但是既然题目要求,使用ArrayList,fruitList.contains())也是可以的,用来查找某个对象在不在列表之中。
  • 代码实现
public static void main(String[] arge){
		
		System.out.println(new Fruit(""));
		Scanner in=new Scanner(System.in);
		Fruit str=new Fruit("");
		Fruit str1=new Fruit(in.next());
		if(str1.equals(str)){
			System.out.println("相等");
		}
		else System.out.println("不相等");
		ArrayList<Fruit> fruitList=new ArrayList<Fruit>();
		//HashSet<Fruit> fruitList1=new HashSet<Fruit>();	
		for(int i=0;i<5;i++){//因为题目其他要求,为了方便检测,就设置成了只读5个
				Fruit a=new Fruit(in.next());
				//System.out.println(a.hashCode());
				if(!fruitList.contains(a))
					fruitList.add(a);	
		}
		System.out.println(fruitList);//测试
		//System.out.println(fruitList1);
	}	
}
  • 只粘贴了main函数部分,Fruit类跟前面相同。注释地方是使用HashSet的情况,实测也可以使用
  • 运行结果如下图

5.代码阅读:PersonTest.java(abstract、多态)

5.1 画出类的继承关系

5.2 读懂main函数,将自己推测的出代码运行结果与真正运行结果进行比较。尝试分析原因

  • main里面对年龄进行排序,之后用了一个增强for循环顺序输出。
  • 输出的时候,toString()一起输出,方便看出继承的关系。因为调用的是super,所以都会输出自己父类的toString()。但是只会到上一级的父类,而不会调用到父类的父类。

5.3 子类中里面使用了super构造函数,作用是什么?如果将子类中的super构造函数去掉,行不行?

  • 子类使用super构造函数,是为了调用父类的构造函数,对变量初始化。如果去掉子类的super构造函数,那子类的构造函数没法完成初始化。
  • 报错信息:隐式的super构造函数person()是未定义的。必须显式调用另一构造函数

5.4 PersonTest.java中的代码哪里体现了多态?你觉得多态有什么好处?多态和继承有什么关系吗?

  • 继承是多态的基础,继承是子类使用父类的方法,而多态则是父类使用子类的方法
  • 继承就是一种由已有的类创建新类的机制,是指在已有类的基础上扩展功能。继承中分为子类和父类,类可以有两种重要的成员:成员变量和方法。子类的成员中有一部分是子类自己声明定义的,另一部分是从它的父类继承的。
  • 多态的好处:运行时,根据实际创建的对象类型动态决定使用哪个方法。
	for (Person person : peoples) {//person
			System.out.println(person);
  • person 虽然是定义为Person类,但是这只是代码中所有类的父类,给persond的类型选择提供一个接口但是不代表person一定是Person类。他会在运行时,根据实际创建的对象类型,动态决定是Student,Manager,Programmer,还是Employee。

3. 码云代码提交记录

4. 实验总结

(1)boolean equals(Object anObject) 比较此字符串与指定的对象;
(2) boolean equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 进行比较,不考虑大小写,是String自己定义的方法;
(3)==这个是用来比较两个对象是否引用同一个对象
(4)CharSequence就是字符序列,String, StringBuilder和StringBuffer本质上都是通过字符数组实现的
(5)ArrayList.Contains方法可以用来查找某个对象在不在列表之中,不在!
(6)ArrayList.Add方法用于添加一个元素到当前列表的末尾
(7) 关于ArrayList的一些使用
(8)当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。 如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。 所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。
(9)抽象类前使用abstract关键字修饰,则该类为抽象类。抽象类不能实例化。
posted on 2017-03-16 20:11  谷LL  阅读(234)  评论(2编辑  收藏  举报