面向对象第四天(Java)
抽象类的特征及应用
接口的特征及应用
面向对象的三大特征之多态性(polymorphism)的特征及应用
向上转型与向下转型
1、抽象类的定义:在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类的特点:
(1)它可以有默认的方法实现。
(2)子类使用extends来继承抽象类,如果子类不是抽象类的话,则子类需要将抽象父类的所有抽象方法全部实现。
(3)抽象类可以有构造方法。
(4)不能直接实例化,但可通过实现子类来间接实例化。
(5)抽象类中可以有0~n个抽象方法,且抽象方法的访问修饰符不能为private,因为抽象方法必须交给子类去实现,如果为private则子类根本无法访问到。
(6)抽象类可以有main方法。
(7)抽象类可以继承一个类和实现多个接口。
(8)它比接口的速度快。
(9)抽象类也可用于多态。
2、final和abstract(抽象类),private和abstract,static和abstract,这些是不能放在一起的修饰符。
为长方形和圆的长度和面积提供统一的计算方式:
package com.hwadee;
public class Calculate {
public static void main(String[] args) {
Rect rect=new Rect(3,5);
double area1 = rect.getArea();
System.out.println("长方形面积="+area1);
double len1=rect.getLen();
System.out.println("长方形周长="+len1);
Circle circle=new Circle(3);
double area2 = circle.getArea();
System.out.println("圆的面积="+area2);
double len2 = circle.getLen();
System.out.println("圆的周长="+len2);
}
}
/**
* 利用关键字abstract定义一个抽象类
* 1 抽象类不能被实例化(面试经常问)
* 2 抽象类是可以被继承的
* 3 抽象类不能直接实例化,但可通过非抽象的子类来间接实例化;说白了,如果子类是抽象的依然不能实例化
* 4 在方法名字前加一个关键字abstract叫做抽象方法。
* 5 抽象方法的特性是:没有方法体!
*/
abstract class MyShape{
abstract double getArea();
abstract double getLen();
}
class Rect extends MyShape{
double length=0.0;
double width=0.0;
Rect(){
}
Rect(double length,double width){
this.length=length;
this.width=width;
}
@Override
double getArea() {
return length*width;
}
@Override
double getLen() {
return (length+width)*2;
}
// public double getLength() {
// return length;
// }
//
// public void setLength(double length) {
// this.length = length;
// }
//
// public double getWidth() {
// return width;
// }
//
// public void setWidth(double width) {
// this.width = width;
// }
}
class Circle extends MyShape{
public static final double pi=3.14;
double r=0.0;
Circle(){
}
Circle(double r){
this.r=r;
}
@Override
double getArea() {
// TODO Auto-generated method stub
return 2*pi*r;
}
@Override
double getLen() {
// TODO Auto-generated method stub
return pi*r*r;
}
}
3、Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。接口就是抽象方法和常量值定义的集合。
接口的特点:
(1)接口完全是抽象的,接口不存在方法的实现。
(2)子类使用关键字implements来实现接口,如果该实现类不是抽象类,那么该类必须实现接口中的所有抽象方法。
(3)接口不能有构造方法。
(4)接口不是类,是完全不同的类型。
(5)接口中抽象方法的访问修饰符只能是public。
(6)接口中的成员变量只能是public static final修饰。
(7)接口没有main方法。
(8)接口可以继承一个或多个接口。
(9)接口的速度稍慢,因为需要寻找实现类中的实现方法。
(10)接口也可用于多态。
PencilWithEraser继承了Pen的write方法具备了写功能,现在希望具备擦功能,但Java只支持单继承,只能通过接口实现:
package com.hwadee;
public class SuperInterfaceList {
public static void main(String[] args) {
Pen p=new Pen("晨光");
p.write();
PencilWithEraser ps=new PencilWithEraser("中华");
ps.write();
ps.clean();
ps.shine();
System.out.println(PencilWithEraser.color);
}
}
class Pen{//普通笔类
String name;
Pen(){
}
Pen(String name){
this.name=name;
}
public void write() {
System.out.println("会写字!"+name);
}
}
interface Eraser{
public static final String color="纯黑色";
abstract void clean();
}
interface Light{
abstract void shine();
}
class PencilWithEraser extends Pen implements Eraser,Light{
PencilWithEraser(){
}
PencilWithEraser(String name){
super(name);
}
@Override
public void write() {
System.out.println("用铅笔写字!!!"+name);
}
@Override
public void clean() {
System.out.println(super.name + ":有橡皮擦的铅笔");
}
@Override
public void shine() {
System.out.println("会发光的铅笔!!!!");
}
}
4、类与类的关系:继承关系,使用关键字extends,只能是单根继承,可以多层继承,只有一个直接父类,可以有多个间接父类。
类与接口的关系:实现关系,使用关键字implements,类可以实现一个或多个接口,一个类可以在继承一个类的同时实现多个接口。
接口与接口的关系:继承关系,使用关键字extends,可以继承一个或多个接口。
5、多态性概述:事物存在的多重形态,即同一种事物由于条件不同,产生的结果也不同。在代码中,则是同一个引用类型,使用不同的实例而执行不同的操作。
实现多态的技术:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
多态的作用:消除类型之间的耦合关系。
6、多态存在的三个必要条件:要有继承关系、要有方法重写、要有父类引用指向子类对象(格式:Father fa = new Son())
多态的好处 :
(1)可替换性(substitutability):多态对已存在代码具有可替换性。
(2)可扩充性(extensibility):多态对代码具有可扩充性,新增子类不影响已存在类的多态性、继承性等,能够获得更多多态功能。
(3)接口性(interface-ability):多态是超类通过方法签名,向子类提供一个共同接口,由子类来完善或者覆盖而实现的。
(4)灵活性(flexibility):它在应用中体现了灵活多样的操作,提高了效率。
(5)简化性(simplicity):多态简化对应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个特点尤为突出和重要。
多态中访问成员变量的特点:编译时看父类,运行时看父类。
多态中访问成员方法的特点:编译时看父类,运行时看子类。
多态其实仅限于类的非静态成员方法,只有在运行时才能决定具体调用谁。
通过酒的例子运用继承来对多态进行展示:
package com.hwadee;
public class Polymorphism2 {
public static void main(String[] args) {
TwoDragonM t=new TwoDragonM();
t.trueWords();
System.out.println("--------");
//灵活
Wine w1=new TwoDragonM();
w1.trueWords();
int num = w1.number;
System.out.println("num="+num);
Wine w2=new FenWine();
w2.trueWords();
int num2=w2.number;
System.out.println("num2="+num2);
}
// public static void printMessage(TwoDragonM t) {
// System.out.println("---> "+t.trueWords());
// }
// public static void printMessage(FenWine t) {
// System.out.println("---> "+t.trueWords());
// }
public static void printMessage(Wine t) {
System.out.println("---> "+t.trueWords());
}
}
class Wine{
String brand;
int grade;
double price;
int number=111;
public String trueWords() {
System.out.println("酒后吐真言");
return "酒后吐真言";
}
}
class TwoDragonM extends Wine{
int number=222;
@Override
public String trueWords() {
System.out.println("二龙山,真难喝");
return "二龙山,真难喝";
}
}
class FenWine extends Wine{
int number=666;
@Override
public String trueWords() {
System.out.println("汾酒,真棒!!!不愧是酒中之王");
return "汾酒,真棒!!!不愧是酒中之王";
}
}
通过酒的例子运用接口来对多态进行展示:
package com.hwadee;
public class Polymorphism1 {
public static void main(String[] args) {
TrueWords t1=new JiangXiaoBaiWine();
t1.say("好酒江小白");
TrueWords t2=new MaoTaiWine();
t2.say("老字号茅台酒");
}
}
interface TrueWords{
public String say(String words);
}
class JiangXiaoBaiWine implements TrueWords{
@Override
public String say(String words) {
System.out.println("江小白不错,"+words);
return "zzz";
}
}
class MaoTaiWine implements TrueWords{
@Override
public String say(String words) {
System.out.println("贵州老茅台,"+words);
return "xixi";
}
}
7、向上转型与向下转型的特点:
(1)父类引用可以直接指向子类对象,子类引用不能直接指向父类对象。
(2)把子类对象直接赋给父类引用叫upcasting向上转型,向上转型不用强制转型。如Father father = new Son();
(3)把指向子类对象的父类引用赋给子类引用叫向下转型(downcasting),要强制转型。如father就是一个指向子类对象的父类引用,把father赋给子类引用son 即Son son =(Son)father;其中father前面的(Son)必须添加,进行强制转换。
(4)upcasting 会丢失子类特有的方法,但是子类overriding 父类的方法,子类方法有效
(5)向上转型的作用,减少重复代码,父类为参数,调有时用子类作为参数,就是利用了向上转型。这样使代码变得简洁。体现了JAVA的抽象编程思想。
多态的好处:
提高了代码的维护性(继承保证)
提高了代码的扩展性(多态保证)
可以用父类类型做形式参数或者方法返回值类型,用来接收任意子类对象
多态的弊端:不能直接使用子类的特有属性和方法。可以使用instanceof运算符来进行一个判断,采用向下转型的方式,来调用子类所独有的属性和方法。
实现多态的两种方式:使用父类作为方法形参实现多态、使用父类作为方法返回值实现多态。
对向上转型和向下转型的代码展示:
package com.hwadee;
public class Master {
//程序的入口 main
public static void main(String[] args) {
// Pet pet=new Dog();
// pet.eat();
//instanceof
String s="山西大学的同学表现很好";
boolean b=s instanceof String;
System.out.println(b);
Dog dog=new Dog();
boolean isDog=dog instanceof Dog;
System.out.println("isDog="+isDog);
boolean isPet=dog instanceof Pet;
System.out.println("isPet="+isPet);
Master m=new Master();
m.printInformation(dog);
m.printInformation(new Cat());
}
//普通方法
public void printInformation(Pet p) {
if(p instanceof Dog) {
System.out.println("这个宠物是狗,给它洗澡!");
}
if(p instanceof Cat) {
System.out.println("猫不洗澡,给它一条鱼");
}
}
}
//宠物类(父类)
class Pet {
public void eat() {
System.out.println("宠物在进食!");
}
}
//狗类(子类)
class Dog extends Pet {
public String name = "旺财";
@Override
public void eat() {
System.out.println("狗在吃狗粮!");
}
public void catchMouse() {
System.out.println("狗在抓老鼠!");
}
}
class Cat extends Pet{
public String name = "大脸猫";
@Override
public void eat() {
System.out.println("猫在吃小鱼!");
}
public void catchMouse() {
System.out.println("猫在抓耗子!");
}
}