多态

来源:互联网 发布:软件需求说明书包括 编辑:程序博客网 时间:2024/05/19 05:05

9多态

9.1Object 类是所有类的父类

Object类经常被重写的方法

方法

说明

equals()

比较两个对象是否是同一个对象,是则返回true

hasCode()

返回该对象的哈希代码值

getClass()

获取当前对象所属的类信息,返回Class对象

toString()

返回当前对象本身的有关信息,按字符串对象返回


 

举例:Student类重写toString方法  

com.nj.polyphism.Student@150bd4d  包名+类名+”@“ +该对象的hashcode的对应的16进制字符串如果重写了,按你重写之后的内容显示

@Override

public String toString() {

return "学号:"+this.sid+",姓名:"+this.name+",年龄:"+this.age;

}

Object类的equals()方法

比较两个对象是否是同一个对象,是则返回true

操作符==

简单数据类型,直接比较值。如1==2

引用类型,比较两者是否为同一对象

1Object类的equals()方法与==没区别

2)当有特殊需求,如认为属性相同即为同一对象时,需要重写equals()

3Java.lang.String重写了equals()方法,把equals()方法的判断变为了判断其值

举例:Student类 名字,学号相同,则认为是同一个人。重写equals()方法

/**

 * toS + alt+ /

 * eq +alt+ /

 * 对象Ainstanceof 类型B   判断对象A是否是类型B这种类型的,如果是,返回true,否则返回false  dog instanceOf Dog dog对象是否是Dog这种类型的

 * @author Administrator

*/

public class Student {

private int sid;//学号

private String name; //名字

private int age;//年龄

public Student() {

}

public Student(int sid, String name,int age) {

super();

this.sid = sid;

this.name = name;

this.age = age;

}

public int getSid() {

return sid;

}

public void setSid(int sid) {

this.sid = sid;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

/**

 * 方式1

 * 学号,姓名相等,认为是同一个对象

 */

/*@Override

public boolean equals(Object obj) {

if(this==obj){ //自身和自身比

return true;

}

//判断obj是不是Student类型 ,如果不是返回false

if(!(obj instanceof Student)){

 return false;

}

//如果代码能够通过if判断,执行到此次,那么传入的obj肯定是Student类型的

Student s = (Student)obj;

if(this.sid==s.sid && this.name.equals(s.name)){

return true;

}

return false;

}*/

/**

 * 方式2:

 */

public boolean equals(Object obj){

if(!(obj instanceof Student)){

 return false;

}

return (this.sid == ((Student)obj).sid)  && ((Student)obj).name.equals(this.name);

}

}

package com.njwb.polyphism2;

/**

 * == 对于基本数据类型而言,比较的是基本数据类型的值

 * == 对于引用数据类型而言,比较的是内存地址

 * equals()Object类的方法,作用和“==”是一样的,都是用来比较内存地址的,但是用户可以根据自己的需求改写,比方说

 * java.lang.String类重写了equals()方法,将其变成比较字符串的内容是否相等

 * 需求:如果姓名,学号相等,就认为是同一个人,也就是说equals()比较结果,要返回true

 * @author Administrator

*/

public class TestStudent01 {

public static void main(String[] args) {

Student stu1 = new Student(101,"张三",18);

Student stu2 = new Student(101,"张三",18);

// 比较2个对象的内存地址

System.out.println("比较内存地址方式1"+(stu1==stu2));

//没有重写equals()方法之前,equals()作用和“==”是一样,都是用来比较内存地址的

//System.out.println("重写前比较内存地址方式2"+stu1.equals(stu2));

//重写equals()方法,认为名字,学号相等,就是同一个人

//System.out.println("重写后比较的是内容是自己设定的:"+stu1.equals(stu2));

Dog dog = new Dog();

System.out.println("两个对象的之间的比较:"+stu1.equals(dog));

Student stu3 = new Student(102,"李四",19);

System.out.println("两个对象之间的比较:"+stu1.equals(stu3));

}

}

Object类的hashCode()方法

public int hashCode()

返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。

对于包含容器类型的程序设计语言来说,基本上都会涉及到hashCode。在java中也一样,hashCode方法的主要作用也是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet,HashMap,HashTable.

为什么这么说呢?考虑一种情况,当向集合中插入对象时,如何判别在集合中是否已经存在该对象了?(注意:集合中不允许重复的元素存在),也许大多数人都会想到调用equals()方法去逐一比较,这个方法确实可行。但是如果集合中已经存在一万条数据或者更多的数据,如果采用equals方法去逐一比较,效率必然是一个问题。此时hashCode方法的作用就体现出来了,当集合要添加新的对象时,先调用这个对象的hashCode方法,得到对应的hashCode值,实际上在HashMap的具体实现中会用一个table保存已经存进去的对象的hashCode值,如果table中没有该hashCode值,它就可以直接存进去,不用再进行任何比较了;如果存在该hashcode值,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址,所以这里存在一个冲突解决的问题,这样一来实际调用equals方法的次数就大大降低了,说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址, 对象的字段等)映射成一个数值,这个数值称作散列值。从HashMapput方法的具体实现可以看出,hashCode的存在是为了减少equals方法的调用次数,从而提高程序效率。

问题:可以直接根据hashCode值判断两个对象是否相等吗?肯定不可以。因为不同的对象可能会生成相同的hashcode值。虽然不能根据hashCode值判断两个对象是否相等,但是可以直接根据hashcode值判断两个对象不等,如果两个对象的hashcode值不等,则必定是两个不同的对象。

如果要判断两个对象是否真正相等,必须通过equals方法。

对于两个对象,如果调用equals方法得到的结果为true,则两个对象的hashcode值必定相等;

如果equals方法得到的结果为false,则两个对象的hashcode值不一定不同;

如果两个对象的hashcode值不等,则equals方法得到的结果必定为false;

如果两个对象的hashcode值相等,则equals方法得到的结果未知。

举例:在有些情况下,程序设计者在设计一个类的时候为需要重写equals方法,比如String类,但是千万要注意,根据equals重写的要求,重写equals的同时,最好hashcode也相同。

public class Student {

private int sid;//学号

private String name; //名字

private int age;//年龄

public Student() {

}

public Student(int sid, String name,int age) {

super();

this.sid = sid;

this.name = name;

this.age = age;

}

public int getSid() {

return sid;

}

public void setSid(int sid) {

this.sid = sid;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

/**

 * 方式2:

 */

public boolean equals(Object obj){

if(!(obj instanceof Student)){

 return false;

}

return (this.sid == ((Student)obj).sid)  && ((Student)obj).name.equals(this.name);

}

@Override

public int hashCode() {

return name.hashCode()*57+sid+10;

}

}

public class TestStudent01 {

public static void main(String[] args) {

Student stu1 = new Student(101,"张三",18);

System.out.println("****stu1的内存地址:"+stu1.toString());

//-Student类型 ,值-Integer

Map<Student,Integer> map = new HashMap<Student,Integer>();

//添加元素

map.put(stu1, Integer.valueOf(1));

//根据键获取值

System.out.println("stu1这个键对应的值是:"+map.get(stu1));

//根据键获取值 ,换一种方式stu1和下面这句中new Student(101,"张三”,18)不是同一个对象,不在同一块内存

//获取的是null,但是如果重写hashcode()方法,让stu1和下句中new Student()在逻辑上保持一致性,就可以获取到值1

System.out.println("根据键获取值:"+map.get(new Student(101,"张三",18)));

Student stu2 = new Student(101,"张三",18);

System.out.println("根据键获取值:"+map.get(stu2));

System.out.println("****stu2的内存地址:"+stu2.toString());

}

}

public class TestStudent02 {

public static void main(String[] args) {

Student stu1 = new Student(101,"张三",18);

System.out.println("创建后的****stu1的内存地址:"+stu1.toString());

//-Student类型 ,值-Integer

Map<Student,Integer> map = new HashMap<Student,Integer>();

//添加元素

map.put(stu1, Integer.valueOf(1));

//根据键获取值

System.out.println("stu1这个键对应的值是:"+map.get(stu1));

//更改stu1中的属性的值,hashcode()方法,equals()方法依赖此属性值,所以下方获取的是null

stu1.setName("李四");

//更改stu1中的属性值agehashcode()方法,equals()方法不依赖此属性,所以下方不受影响,仍旧能获取到1

//stu1.setAge(39);

System.out.println("属性更改后的****stu1的内存地址:"+stu1.toString());

System.out.println("根据键获取值:"+map.get(new Student(101,"张三",18)));

Student stu2 = new Student(101,"张三",18);

System.out.println("根据键获取值:"+map.get(stu2));

System.out.println("****stu2的内存地址:"+stu2.toString());

}

}

面试题:==”和equals的区别?

对于基本数据类型而言 ==”比较的是基本数据类型的值 ,对于引用数据类型而言,“==”比较的是内存地址,equals()方法是Object类提供的,作用和“==”一样,都是比较的内存地址,但是用户可以根据自己的需求来改写,比方说java.lang.String类,就将equals()方法改写成了比较字符串内容是否相等。根据equals重写的要求,重写equals的时候,最好hashcode()也相同。

 

9.2 为什么使用多态?

package com.njwb.polyphism4.d0428;

/**

 * 主人类 ,1个方法,宠物生病了,主人带宠物区看病,如果这个时候养了新的宠物,主人需要带猫看病

 * 实现思路: 1.创建类Class cat extends Pet  2.修改主人类 添加 猫看病的方法   public void cure(Cat cat){....具体猫看病的方法} 3.测试

 * 这样,会造成一个问题,频繁修改主人类,动物写不尽的,主人类非常的庞大

 * 这个时候,需要用多态来解决

 * 1.创建类Class  cat extends Pet  2.主人类 只提供1个方法 ,父类做形参   public void cure(Pet pet){//宠物去病} 3.修改父类,父类 提供1个空方法

 * public void toHospital(){ }  4.每个子类去重写toHospital()方法,每个子类看病,看病的方式放在自己的类去实现.

 * 5.测试的时候,一定  父类引用,指向子类对象Pet p = new Dog(); 父类类型 变量名= new子类();一定调用的是子类重写之后的方法,而不会调用父类的方法

 * @author Administrator

 *

 */

public class Host {

/**

 * 狗狗看病

 * @param dog

 */

public void cure(Dog dog){

if(dog.getHealth()<60){

System.out.println("狗狗看病:打针,吃药");

dog.setHealth(60);

}

}

/**

 * 企鹅看病

 * @param pgn

 */

public void cure(Penguin pgn){

if(pgn.getHealth()<60){

System.out.println("企鹅看病:吃药,疗养");

pgn.setHealth(60);

}

}

}

如果这个时候,再添加个XXX类,需要给XXX看病呢?频繁的修改主人类,代码可扩展性,可维护性差。使用多态优化。

9.3什么是多态?

同一个引用类型,使用不同的实例,而执行不同的操作。

多态的使用一:演示多态示例。宠物看病。

package com.njwb.polyphism4.d0428;

/**

 * 主人类

 * @author Administrator

 *

 */

public class Master {

/**

 * Pet父类做形参

 * @param pet

 */

public void cure(Pet pet){

//宠物去看病

pet.toHospital();

}

}

package com.njwb.polyphism4.d0428;

public class Pet {

private String name; //名字

private int health;//健康值

private int love;//亲密度

public Pet() {

}

public Pet(String name,int health, int love) {

super();

this.name = name;

this.health = health;

this.love = love;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getHealth() {

return health;

}

public void setHealth(int health) {

this.health = health;

}

public int getLove() {

return love;

}

public void setLove(int love) {

this.love = love;

}

public void print(){

System.out.print("宠物的自白:\n我叫"+this.getName()+",我的健康值是:"+this.getHealth()

+",和主人的亲密度为:"+this.getLove());

}

public void toHospital(){

}

}

package com.njwb.polyphism4.d0428;

public class Dogextends Pet {

private String strain; //品种

public String getStrain() {

return strain;

}

public void setStrain(String strain) {

this.strain = strain;

}

public Dog() {

}

public Dog(String name,int health, int love,String strain) {

super(name,health,love);

this.strain = strain;

}

public void print(){

super.print();

System.out.println(",我是一只:"+this.getStrain());

}

/**

 * 子类看病的方式放在子类里去实现,跟父类,根主人类无关

 */

public void toHospital(){

if(this.getHealth()<60){

System.out.println("狗狗看病:打针,吃药");

this.setHealth(60);

}

}

}

package com.njwb.polyphism4.d0428;

public class TestPet02 {

public static void main(String[] args) {

Pet p = new Dog("旺财",19,90,"吉娃娃");

p.print();

//实例化主人类

Master m = new Master();

m.cure(p);

System.out.println("-------------看病后------------------");

p.print();

System.out.println("===============以下是企鹅看病===================");

p = new Penguin("小花", 30, 33,"Q");

p.print();

m.cure(p);

System.out.println("-------------看病后------------------");

p.print();

System.out.println("===============以下是猫看病===================");

p = new Cat("小猫咪",18,39);

p.print();

m.cure(p);

System.out.println("-------------看病后------------------");

p.print();

}

}

 

9.4抽象类和抽象方法的使用

什么是抽象方法?

抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。

抽象方法必须用abstract关键字进行修饰

声明格式:

abstract void fun();

注意直接在普通类中写抽象方法会报错。

什么是抽象类?

包含抽象方法的类。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。

特殊情况:如果一个abstract修饰,里面却没有抽象方法,也是抽象类,只不过没有意义。

为什么要用抽象类?

因为抽象类中方法不包含具体的业务代码,仅仅是方法的声明,无法实现功能,所以不能用抽象类创建对象(不能实例化抽象类)。

抽象类存在的意义?

抽象类就是为了继承而存在的,如果定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为不能用它来做任何事情。

什么时候用抽象类?

对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

抽象类包含什么

抽象类不仅包含抽象方法,而且抽象类和普通类一样,可以拥有成员变量和普通的成员方法。

抽象类和普通类的区别:

语法:

普通方法

[访问修饰符]返回值类型 方法名(参数列表){

方法体

}

抽象方法

[访问修饰符]abstract 返回值类型方法名(参数列表);

l 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),如果是default(缺省的默认修饰符,那么子类必须在本包内);抽象方法没有方法体;

l 抽象类不能用来创建对象;不能被实例化。

l 抽象方法必须在抽象类里(反过来抽象类里不一定有抽象方法)

l 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为abstract(换种说法抽象方法必须在子类中被实现,除非子类是抽象类)

l abstract修饰符不能和final修饰符一起使用

l 可以拥有普通类所拥有的一切成员(属性,方法,代码块,静态代码块等还可以拥有抽象方法)。

示例:

abstract class AbsDemo{

public abstract int calNum(int a,int b);

public abstract void showNum();

//public final abstract void showName(); // final abstract冲突 ,不能在一起使用

}

/**

 * 普通的子类必须实现父类的所有抽象方法

 * @author Administrator

 *

 */

class SubDemo extends AbsDemo{

@Override

public int calNum(int a,int b) {

return 0;

}

@Override

public void showNum() {

}

}

/**

 * 抽象的子类可以不用实现父类的所有抽象方法

 * @author Administrator

 *

 */

abstract class SubSecDemoextends AbsDemo{

@Override

public int calNum(int a,int b) {

return 0;

}

}

 

public class TestAbstractDemo {

public static void main(String[] args) {

//AbsDemo ad = new AbsDemo();

}

}

Pet类:

public abstract class Pet {

public abstract void toHospital();

}

课堂练习

需求说明宠物饿了,主人需要为宠物喂食,使用多态实现该过程, 不同宠物吃的东西不一样,不同宠物吃完东西后恢复健康值不一样

健康值达到100时,不需要继续喂食

狗狗:健康值增加3 企鹅:健康值增加5

Master 类  public  void feed(Pet pet){ //宠物吃饭  pet.toEat()} ; Pet父类:public  abstract void toEat(); 具体的喂食的方法放在具体的子类里去实现 。

Dog类  public void toEat(){ this.getHealth>=100 //打印狗狗吃饱了,不需要再喂了。如果健康康<100, 狗狗吃饱了,健康值增3  this.setHealth(this.getHealth+3);}

测试类  Pet p = new Dog(“旺财”,10,29,”吉娃娃”);

Dog类中:

@Override

public void toEat() {

if(this.getHealth()>=100){

System.out.println("狗狗吃饱了,不需要再喂了");

}else{

//判断目前的健康值是否大于97大于97,健康值不能加3

int liang =this.getHealth()>97?(100-this.getHealth()):3;

System.out.println("狗狗吃饱了,健康值加"+liang);

this.setHealth(this.getHealth()+liang);

}

}

测试类中:

public static void main(String[] args) {

//父类引用指向子类对象

Pet p = new Dog("旺财",87,80,"吉娃娃");

p.print();

//实例化主人类

Master m = new Master();

m.feed(p);

System.out.println("-------------喂食后-----------------");

p.print();

}

9.5 向上转型

向上转型:父类引用指向子类对象,自动进行类型转换,

Pet p = new Dog("旺财",87,80,"吉娃娃");

 

注意:

<父类型> <引用变量名> = new <子类型>();

n 此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法(调用是子类重写之后的方法),不是父类的方法,。

此时通过父类引用变量无法调用子类特有的方法 ,该如何解决? 只能向下转型

动态绑定(dynamic binding又名动态链接:父类引用指向子类对象,调用方法时会调用子类的实现,而不是父类的实现。

9.6 向下转型

向下转型:将一个指向子类对象的父类引用赋给一个子类的引用,即:父类类型转换为子类类型。需强制类型转换。  

Pet p = new Dog(旺财,87,80,吉娃娃);

Dog dog = (Dog) p;

dog.catchFlyingDisc();

注意:

<子类型> <引用变量名> = (<子类型> )<父类型的引用变量>;

在向下转型的过程中,如果没有转换为真实子类类型,会出现类型转换异常

9.7 instanceof

如何减少在向下转型的过程中,没有转换为真实子类类型的类型转换异常?

//这个时候,需要先判断p实际是什么类型,就转化成对应的子类类型

if(p instanceof Dog){

Dog d = (Dog)p;

d.catchFlyingDisc();

}else if(pinstanceof Penguin){

Penguin pgn = (Penguin)p;

pgn.swim();

}

使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类在继承上有上下级关系

对象A(引用数据类型)   instanceof类型(可以是类,接口,可以是对应的包装类)

Object num = Integer.valueOf(12);

if(num instanceof Integer){

System.out.println("numInteger这种类型的");

}else if(numinstanceof Double){

System.out.println("numDouble这种类型的");

}else if(numinstanceof Short){

System.out.println("numShort这种类型的");

}

9.8 多态的应用

9.8.1 使用父类作为方法的形参

public void cure(Petpet){

//宠物去看病

pet.toHospital();

}

public void feed(Pet pet){

//宠物吃饭

pet.toEat();

}

9.8.2 使用父类作为方法的返回值

/**

 * 主人类

 * @author Administrator

 *

 */

public class Host {

/**

 * 捐赠动物 ,父类做返回值

 * @param type动物的类型

 * @return

 */

public Animal donate(String type){

Animal an = null;

if(type.equals("鸭子")){

an = new Duck();

}else if(type.equals("狗狗")){

an = new Dog();

}else if(type.equals("小猫")){

an = new Cat();

}

return an;

}

}

/**

 * 抽象父类

 * @author Administrator

 *

 */

abstract class Animal{

public abstract void cry();

}

class Cat extends Animal{

@Override

public void cry() {

System.out.println("小猫叫:喵喵喵");

}

}

class Dog extends Animal{

@Override

public void cry() {

System.out.println("小狗叫:汪汪汪");

}

}

 

class Duck extends Animal{

@Override

public void cry() {

System.out.println("小鸭子叫:嘎嘎嘎");

}

}

public class TestAnimal {

public static void main(String[] args) {

//实例化主人类

Host host = new Host();

//想要鸭子

Animal an = host.donate("鸭子");

//获取鸭子后,控制鸭子叫

an.cry();

}

}

 

 

课堂练习:

自定义类和方法,使用父类作为返回值实现打印不同类型商品价格功能

父类:Goods(商品类)

子类:TVs (电视类),Foods(食品类)

分析: 抽象父类 abstract class Goods{

Public abstract void printPrice(); //打印价格

}

子类 class TVs extends Goods{

Public void printPrice(){

//打印电视机价格

}

}

商品哪里来的?工厂生产出来的。

Class Factory{

//根据传入的参数,确定具体的商品对象

Public Goods generateGoods(String type){

Goods goods = null;

//多重if

Return  goods;

}

}

测试类:

abstract class Goods{

public abstract void printPrice();

}

class TVs extends Goods{

@Override

public void printPrice() {

System.out.println("打印电视机价格");

}

}

class Foods extends Goods{

@Override

public void printPrice() {

System.out.println("打印食品价格");

}

}

public class TestGoods {

public static void main(String[] args) {

//实例工厂类

Factory fac = new Factory();

//想打印电视机价格

Goods goods = fac.generateGoods("TV");

//调用方法打印

goods.printPrice();

//打印食品价格

goods = fac.generateGoods("食品");

goods.printPrice();

}

}

public class Factory {

/**

 * 父类做返回值

 * @param type

 * @return

 */

public Goods generateGoods(String type){

Goods goods = null;

if(type.equals("TV")){

goods = new TVs();

}else if(type.equals("食品")){

goods = new Foods();

}

return goods;

}

}

9.9面向对象的三大特性总结

l 封装隐藏了类的内部实现机制,可以在不影响使用者的前提下修改类的内部结构,同时保护了数据;

l 继承是为了重用父类代码,子类继承父类就拥有了父类的成员。

l 多态允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。

9.10多态存在的三个必要条件

l 要有继承;

l 要有重写;

l 父类引用指向子类对象。

9.11多态的好处

可替换性。多态对已存在代码具有可替换性。例如,多态对圆Circle类工作,对其他任何圆形几何体,如圆环,也同样工作。

可扩充性。多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。例如,在实现了圆锥、半圆锥以及半球体的多态基础上,很容易增添球体类的多态性。

接口性。多态是父类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。

灵活性。它在应用中体现了灵活多样的操作,提高了使用效率。

简化性。多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。

9.12多态总结

l 使用父类类型的引用指向子类的对象; 

l 该引用只能调用父类中定义的方法和变量; 

l 如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用) 

变量不能被重写(覆盖),“重写”的概念只针对方法,如果在子类中“重写”了父类中的变量,那么在编译时会报错。

9.13 动态绑定 静态绑定

/**

 * 动态绑定 :多态  父类引用指向子类对象,调用的一定是子类重写之后的方法(普通方法)

 * 静态绑定:  普通变量  ,静态变量,静态方法 调用的方法由变量p前面的父类类型决定,调用的是父类中的方法,访问的变量的值也是有变量p前面的类型决定的

 * ,访问父类中的变量的值。

 * @author Administrator

 *

 */

class Person{

String name= "person";

int num = 10;

static int num2 = 20;

public void shout(){

System.out.println(name);

}

public static void say(){

System.out.println("我是一个人类");

}

}

class Teacher extends Person{

String name = "teacher"; //定义了一个和父类中同名的属性 ,现在Teacher类而言,2name属性,一个是从父类继承的,一个是自身的

int num = 15;

static int num2 = 25;

public void ceshi(){

System.out.println("本类中的name="+this.name+",从父类继承的name="+super.name);

}

public void shout(){

System.out.println(name);

}

public static void say(){

System.out.println("我是一个教师");

}

}

public class TestPerson {

public static void main(String[] args) {

Person p = new Teacher();

p.say();

System.out.println("父类引用指向子类对象 普通变量的值:"+p.num+",父类引用指向子类对象 静态变量的值:"+p.num2);

//p.shout();

/*Teacher t = new Teacher();

t.ceshi();*/

}

}

9.14作业

1. 抽取用户管理系统和图书管理系统中公共方法到抽象类,并继承。

见《继承和多态》上机实践2

《多态》

商品管理系统

//需要哪些类

Goods 商品类  

goodsPrice价格

kucun 库存

type  类别

remainingDays  保质期

抽象类  定义几个抽象方法  Manager  

Public  abstract void showAllGoods(); //显示所有商品  ,支持分类显示  

类别编号    类别名称

1 奶制品

2  零食

3  肉制品

4   水果类

5   所有类别

请选择要显示的类别编号: 1

“奶制品”类别下的所有商品如下:

商品编号 商品名称  单价  库存    

1           旺仔牛奶  3.3   200    

2         蒙牛牛奶   5.6   300

3         伊利牛奶  2.3   200

 

 

Public abstract void addGoods(); //添加商品  需要重名验证  ,类别应该选(显示类别列表,让用户选择类别编号,不要让用户输入类别)

Public abstract void updateGoods(); //根据商品名称 修改商品的信息(价格,库存)

Public abstact  void delGoods(); //删除商品  //根据商品名称  提示是否删除成功

Public abstract void buyGoods(); // 先显示商品列表,然后用户输入商品编号,进行购买  买东西的时候,记得减少库存  ,验证 超出库存的,要提示用户无法购买

商品编号   商品名称  单价  库存    类别

1            康师傅   2.8   100     零食

2            瓜子    6.7    1003      零食

3           旺仔牛奶   3.4    200    奶制品  

 

请输入购买编号: (编号只能在1-3范围内,如果输入错误,提示用户输入范围不正确,请重输)

 

Public abstract void updateReamingDays(String typeName) ;// 针对某一个类别 ,调用一次,该类别下的所有商品保质期都要减少1

 

Public abstract void checkRemaingDays() ;//模拟的假方法,在该方法里调用10次减少保质期的方法,看是否有商品过期,如果有的话,删除该商品

抽象类的实现类  GoodsManager (业务类)

无参构造里  初始化数据至少初始化5条商品信息  

 

程序的入口  GoodsManagerSystem

工具类  NumsUtil  定义几个方法,用于接收正整数 ,正的浮点数

 

GoodsManagerSystem包括main方法,用来调用

GoodsManager商品管理类,实现增删改查,继承Manager抽象类

Goods商品类,private通过getset访问

需求:

(1) 能够显示出所有的商品。

(2) 能够添加商品

(3) 能够根据商品的名称,编辑商品的价格、库存

(4) 能够删除商品

(5) 购买商品,先输出名称,让用户挑选。

(6) 买完商品,能够自动减少库存,如果库存为0,用户购买时看不到商品。

 

需求part2

1系统启动时,自带了5商品。

2)添加商品时,如果商品名称重复,提示用户商品名称重复,要求用户重新输入商品名称。

3)编辑商品,如果用户输入的价格库存不正确,如价格汉字或负值,要提示用户输入错误重新输入。

4)删除商品时,要提示删除成功如果用户删除的商品不存在数组中,提示删除失败。

5)购买商品输出的商品列表,每个商品左侧要有数字表示商品的编号,用户可以输入一个数字来选择商品而不用输入商品的名称。如果输入的数字不范围内,提示输入不正确重新输入。

6购买商品时,用户输入的购买数量如果大于库存,要给出提示。

需求part3:

(1) 添加商品增加一个类型属性,用于标记该商品分类,如“生活用品”、“食物”等。

(2) 编辑,允许编辑类型属性。

3)  除了支持直接输出所有商品的列表,还支持根据类型输出商品,进入该功能时,输出系统中所有的商品类型,用户输入商品类型,根据商品类型输出相应的商品。

4)  新增保质期属性RemainingDays(剩余天数),该属性保存商品保质期剩余天数,如:6

5)  新编写一个方法,叫做updateRemainingDays。该方法执行一次,所有商品的保质期减1。如果执行后有商品到期,在控制台输出到期的商品列表,并从数组删除到期的商品。