//65-面向对象-接口-接口的思想
/*
举例:笔记本电脑。 1,接口的出现对功能实现了扩展。
2,接口的出现定义了规则。
3,接口的出现降低了耦合性。(解耦) 接口的出现完成了解耦,说明有两方,一方在使用这个规则,另一方在实现这个规则。
比如笔记本电脑在使用这个规则,而外围设备在实现这个规则。
*/
//66-67面向对象-接口-接口和抽象的区别及总结:
/*
接口和抽象类的区别: 描述事物:
犬。按照功能分类。导盲犬,缉毒犬... 犬:
吼叫();
吃饭();
*/ abstract class 犬
{
public abstract void 吼叫();
public abstract void 吃饭();
}
class 缉毒犬 extends 犬
{
public void 吼叫(){}
public void 吃饭(){}
//public void 缉毒(){}
} //对于缉毒,有可能还有缉毒猪。具备着缉毒功能。应该将这个缉毒的功能抽取。
//对缉毒进行描述。
abstract class 缉毒
{
public abstract void 缉毒(){}
} /*
缉毒犬既需要犬的功能又需要缉毒的功能。
无法直接多继承。
是否可以多实现呢?
犬是一个接口,缉毒犬多实现即可。
类负责描述的是事物的基本功能,接口负责描述事物的扩展功能。
缉毒犬是犬中的一种。is a 关系。
将犬定义成类,而缉毒是犬的一个扩展功能,这时将缉毒定义成接口。 这时描述就变成了这样。
*/
abstract class 犬
{
public abstract void 吼叫();
public abstract void 吃饭();
}
interface 缉毒able
{
public abstract void 缉毒();
} class 缉毒犬 extends 犬 implements 缉毒able
{
public void 吼叫(){}
public void 吃饭(){}
public void 缉毒(){}
} /*
小节:
1,抽象类是描述事物的基本功能,可以描述非抽象的方法。
接口中定义的只能是抽象的方法。负责事物功能的扩展。
2,类与类之间是继承关系 is a 关系。
类与接口之间是实现关系 like a 关系。 门:
open();
close(); 报警功能的门。 interface 报警
{
public abstract void 报警();
} abstract 门
{
public abstract void open();
public abstract void close();
} class 报警门 extends 门 implements 报警
{
public void open(){code...}
public void close(){code..}
public void 报警(){code...}
} */
//68-面向对象-多态-好处&弊端-前提 //多态技术的引出,解决什么问题?程序扩展性的问题。
//描述Dog
class Dog extends Animal
{
public void eat()
{
System.out.println("骨头");
}
public void lookHome()
{
System.out.println("看家");
}
} //描述猫
class Cat extends Animal
{
public void eat()
{
System.out.println("鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
}
//进行抽取,将共性的功能抽取到父类中Animal中。
abstract class Animal
{
public abstract void eat();
} class DuoTaiDemo
{
public static void main(String[] args)
{
Dog d = new Dog();
// d.eat();
method(d); Cat c = new Cat();
method(c); /*
发现,每多一个动物,都需要为这个动物单独定义一个功能。
让这个动物的对象去做事。
这个程序扩展性很差。
如何提高扩展性呢?
发现既然是让动物去eat,无论是Dog,还是Cat。
eat是它们的共性,干脆,将eat进行抽取。抽取到父类Animal中。 Dog是Animal中的一种。
Dog d = new Dog();
Animal a = new Dog(); Cat是Animal中的一种。
Cat c = new Cat();
Animal aa = new Cat();
*/ //只要去建立Ainmal的引用就可以接受所有的Dog,Cat对象。让它们去eat。
//提高了程序的扩展性。
public static void method(Animal a)
{
a.eat();
} /*
//接收Dog,让dog做事。
public static vodi method(Dog d)
{
d.eat();
} //接收Cat,让Cat做事。
public static void method(Cat c)
{
c.eat();
}
*/
}
}
//68-面向对象-多态-好处&弊端-前提 //多态技术的引出,解决什么问题?程序扩展性的问题。
//描述Dog
class Dog extends Animal
{
public void eat()
{
System.out.println("骨头");
}
public void lookHome()
{
System.out.println("看家");
}
} //描述猫
class Cat extends Animal
{
public void eat()
{
System.out.println("鱼");
}
public void catchMouse()
{
System.out.println("抓老鼠");
}
} //进行抽取,将共性的功能抽取到父类中Animal中。
abstract class Animal
{
public abstract void eat();
} /*
多态:
【体现】
父类的引用或者接口的引用指向了自己的子类对象。
Dog d = new Dog();//Dog 类型是Dog类型。
Animal a = new Dog();//Dog对象的类型右边是Dog类型,左边是Animla类型。
【好处】
提高了程序的扩展性。
【弊端】
通过父类引用操作对象时,只能使用父类中中已有的方法,不能操作子类特有的方法。
【前提】
1,必须有关系,继承,实现。
2,同常都有重写操作。
【子类的特有方法如何调用呢?】
Ainmal a = new Dog();//Animal是父类型,new Dog()是子对像。
但是父类型引用指向子类对象时,这就是让子类对象进行了类型的提升(向上转型)
向上转型的好处:提高了扩展性,隐藏了子类型。弊端,不能使用子类型的特有方法。
如果想使用子类的特有方法,只有子类型可以用。
可以向下转型。(可以用double d = 4 同时也可以把d强转为int型).
Ainmal a = new Dog();
a.eat(); //向下转型
Dog d = (Dog)a;//将a转型为Dog类型。
d.lookHome();
向下转型什么时候用?当需要使用子类型的特有内容时, 注意:无论向上还是向下转型,最终都是子类对象在做着类型的变化。
千万不要把父类型的对象进行强转,因为父类型创建以后还不明确它的
子类型到底有哪些? 【向下转型的注意事项】
Animal a = new Dog();
Cat c = (Cat)a;//向下转型因为不明确具体子类对象类型,
//所以容易引发ClassCastException:
所以为了避免这个问题,需要在向下转型前,做类型判断。
判断类型用关键字。instanceof
if(a instanceof cat)//a指向的对象时Cat类型。
{
//将a转型成Cat类型
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog d = (Dog)a;
d.lookHome();
}
【转型总结】
1,什么时候向上转型呢?
提高程序的扩展性,不关心子类型(子类型被隐藏)。
需要用子类的特有方法吗?不需要,哦了,向上转型。
2,什么时候使用向下转型呢?
需要使用子类型的特有方法时。
但是一定要使用instanceof进行类型的判断。避免发生ClassCastException: */ class DuoTaiDemo2
{
public static void main(String[] args)
{
Dog d = new Dog();
/*
d.eat();
d.lookHome();
Animal a = new Dog();
a.eat();//可以。
a.lookHome();//不可以。
*/
method(d); Cat c = new Cat();
method(c);
} public static void method(Animal a)
{ a.eat();
Dog d = (Dog)a;
//d.lookHome();//Exception in thread "main"
//java.lang.ClassCastException:
//Cat cannot be cast to Dog // a.lookHome();//不可以,因为动物不具备lookHome功能。
}
}
//70-面向对象-多态-举例
class 毕姥爷
{
public void 讲课()
{
System.out.println("讲管理");
}
public void 钓鱼()
{
System.out.println("钓鱼");
}
} class 毕老师 extends 毕姥爷
{
public void 讲课()
{
System.out.println("Java");
}
public void 看电影()
{
System.out.println("看电影");
}
}
class DuoTaiTest
{
public static void main(String[] args)
{
毕姥爷 x = new 毕老师();//多态,向上转型了。
x.讲课();
x.钓鱼();//可以。
// x.看电影();//不行
//想要使用毕老师的特有方法时,需要向下转型。
if(x instanceof 毕老师)
{
毕老师 y = (毕老师)x;
y.看电影();
} //自始至终都是子类对象在做着类型的变化。
}
}
//72-面向对象-多态-练习-笔记本电脑
/*
阶段一需求:笔记本电脑运行。
按照面向对象的思想,用代码体现。
名词提炼法。
笔记本电脑:
行为:运行。 class noteBook
{
//定义一个运行功能。
public void run()
{
System.out.println("notebook run");
}
} 阶段二需求:想要在笔记本上加上一个手提式鼠标。
多了个对象。鼠标。
行为:开启,关闭。
class Mouse
{
public void open()
{
System.out.println("mouse run");
}
public void close()
{
System.out.println("mouse close");
}
} 笔记本怎么用鼠标呢?
笔记本中就多了个使用鼠标的功能。
需要修改原来的笔记本类中的内容,添加一个功能。
class noteBook
{
//定义一个运行功能。
public void run()
{
System.out.println("notebook run");
}
//使用鼠标功能。
public void useMouse(Mouse m)
{
if(m!=null)
{
m.open();
m.close();
}
}
}
//问题:如果想要加入一个键盘呢?
只要描述一个键盘类,并在电脑类中加入一个使用键盘的功能。就可以了。
但是从鼠标开始,这个问题就已经产生了。一旦需要添加新设备的时候,
都需要改变电脑的源码。这个扩展性是非常差的。 设计上该如何改进呢?
之前的问题在于外围设备的增加和笔记本电脑之间的耦合性过高。
如何降低这些外围设备和笔记本电脑的耦合性呢?
外围设备还不确定,我们不要面对外围具体设备。
为了让笔记本可以使用这些设备,可以事先定义好一些规则。
笔记本只要使用这些规则就可以了。
有了这些规则就可以进行功能的扩展。
后期这些外围的设备只要符合这些规则就可以被笔记本使用了。 那么规则在java中该如何体现呢? ./1,描述接口。USB. //2,描述笔记本电脑:运行功能,使用USB接口的功能。 */ //USB接口定义。
interface USB
{
public abstract void open();
public abstract void close();
} //描述笔记本电脑。
class NoteBook
{
public void run()
{
System.out.println("notebook run");
} //使用usb接口的功能。
public void usbUSB(USB usb)//多态!//接口类型的变量。接口类型的变量只能
//只能指向自己的子类对象。
//USB usb = new Mouse();
{
if(usb!=null)
{
usb.open();
usb.close();
}
}
} //需要鼠标。想要被笔记本电脑使用,该鼠标必须要符合规则。
//描述鼠标。
class Mouse implements USB
{
public void open()
{
System.out.println("mouse open");
}
public void close()
{
System.out.println("mouse close");
}
} class KeyBoard implements USB
{
public void open()
{
System.out.println("keyboard open");
}
public void close()
{
System.out.println("keboard close");
}
} /*
发现:接口的出现
1,扩展了笔记本的功能。
2,定义了规则。
3,降低了笔记本电脑和外围设备之间的耦合性。
*/
class DuoTaiTest2
{
public static void main(String[] args)
{
NoteBook book = new NoteBook();
book.run();
book.usbUSB(null);
book.usbUSB(new Mouse());
book.usbUSB(new KeyBoard());
}
}
//73-面向对象-多态-成员变量&成员函数&静态函数的特点
/*
多态中,成员调用的特点。
1,成员变量:
当子父类中出现了同名的成员变量时,
多态调用该变量时,分两个时期:
编译时期参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
运行时期,也是调用引用型变量所属的成员变量。
简单记:编译和运行都参考等号左边。
编译运行看左边。
2,成员函数:
编译:参考左边。如果有,编译通过,如果没有,编译失败。
运行:参考右边。参考右边对象所属的类。
编译看左边,运行看右边。 对于成员函数是动态绑定到对象上。
3,静态函数。
对于静态函数,编译和运行都看左边。
静态函数是静态的绑定到类上的。(因为静态方法加载的时候还没有对象。) 总结:
对于成员变量和静态函数,编译和运行都看左边。
对于成员函数,编译看左边,运行看右边。
*/ class Fu
{
//成员变量。
int num = 3; //成员函数。
void show()
{
System.out.println("fu show run");
} //静态函数。
static void method()
{
System.out.println("fu static method run");
}
}
class Zi extends Fu
{
int num = 5; void show()
{
System.out.println("zi show run");
} //静态函数。
static void method()
{
System.out.println("zi static method run");
}
} class DuoTaiDemo3
{
public static void main(String[] args)
{
/*测试成员变量的多态调用: //Fu f = new Zi();
//System.out.println(f.num);//打印结果:3 //Zi z = new Zi();
//Zi z = (Zi)f;
//System.out.println(z.num);
*/ //测试成员函数的多态调用:
//Fu f = new Zi();
//f.show(); //测试静态成员函数的多态调用:
Fu f = new Zi();
f.method();
//注意:真正开发,静态方法是不会被多态调用的,因为静态方法不所属于对象。
//因为静态方法就是应该被类调用的。Fu.method();
}
}
//76-77-面向对象-Object-概述&toStrng方法。
/*
Object类中的常用方法。 Object是所有类的根类,定义了所有对象都具备的功能。
API(应用程序接口)文档。 */
class Person extends Object
{
private int age;
Person(int age)
{
this.age = age;
}
//判断是否是同龄人。其实这个方法也是在比较Person对象是否相等。
//注意:Person类中是否有比较两个Person对象相等的方法?有的。
//因为继承Object,本身就具备着equals方法。
//既然有,还需要定义compare方法吗?不需要。
//但是equals方法判断的是地址,不是我们所需要的内容。
//咋办?继续使用Object的equals方法,但是建立子类自己的内容。
//这就是传说中的重写。
//重写:
//【记住】以后判断对象是否相同,就需要覆盖equals方法。
public boolean equals(Object obj)
{
//建立Person自己的判断相同的依据。判断年龄是否相同。
// return this.age == obj.age;//obj所属类型Object,Object中没有定义age,所有编译失败。 //如果调用该方法的对象和传递进来的对象是同一个,就不要转型和判断,直接返回true就可以了。
if(this == obj)
return true;//效率高一些。 //age是Person类型的属性,既然要用到子类型的内容,需要向下转型。
if(!(obj instanceof Person))
// return false;
throw new ClassCastException("类型是不对的;请改正。");
Person p = (Person)obj; return this.age == p.age;
} //覆盖toString方法,建立Person对象自己的字符串表现形式。
public String toString()
{
return "Person[age = "+age+"]";
}
/*
public boolean compare(Person p)
{
return this.age == p.age;
}
*/
} class Dog
{ }
class ObjectDemo
{
public static void main(String[] args)
{
Person p1 = new Person(12);
Person p2 = new Person(17);
// p1.equals(p2);
// p1.equals(new Dog());//会抛出异常。
// System.out.println(p1.equals(p1)); System.out.println(p1.toString());//Person@2a139a55
//想要建立自定义对象的字符串表示形式,
//覆盖toString方法。
System.out.println(p2.toString()); // System.out.println(p1.compare(p2));
// System.out.println(p1==p2);
// System.out.println(p1.equals(p2));
}
}