6.7 抽象类
6.8 接口
6.7 抽象类
6.7.1 抽象类概述
(1)抽象定义:
•抽象就是从多个事物中将共性的,本质的内容抽取出来。
•例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。
(2)抽象类:
•Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。
(3)抽象方法的由来:
•多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。
•例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。
abstract class Demo //抽象类 { //从多个事物中将共性的,本质的内容抽取出来。 abstract void show(); //没有方法体,方法体由继承的子类实现,即:只有功能声明,没有功能主体的方法 } class DemoA extends Demo { void show() { System.out.println("demoa showA"); } } class DemoB extends Demo { void show() { System.out.println("demoa showB"); } } class AbstractDemo { public static void main(String[] args) { System.out.println("Hello World!"); } }
6.7.2 抽象类的特点
(1)抽象类和抽象方法必须用abstract关键字来修饰。
(2)抽象方法只有方法声明,没有方法体,定义在抽象类中。
•格式:修饰符 abstract 返回值类型 函数名(参数列表) ;
(3)抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:
•抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。
•而且抽象类即使创建了对象,调用抽象方法也没有意义。
(4)抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。
6.7.3 抽象类相关问题
(1)抽象类一定是个父类吗?
class A { } abstract class B extends A //是C的父类,所以是父类! { abstract void show(); } class C extends B { }
(2)抽象类中是否有构造方法?
有的,用于给子类对象初始化.
抽象类和一般类:
相同点:都是在描述事物,里面都可以定义属性和行为。
不同点: 抽象类里面可以定义抽象方法,一般类不可以。
抽象类不能被实例化,一般类可以。
abstract class Demo //抽象类 { abstract void show(); } class DemoA extends Demo { DemoA() { super();//隐式的存在构造方法 } void show() { System.out.println("demoa showA"); } } class DemoB extends Demo { void show() { System.out.println("demoa showB"); } }
(3)抽象关键字abstract不可以和哪些关键字共存?
final 、private 、static
(4)抽象类中可不可以不定义抽象方法?
可以。存在的意义:不让该类实例化。
6.7.4 抽象类举例代码讲解
(1)雇员示例:
•需求:公司中程序员有姓名,工号,薪水,工作内容。
•项目经理除了有姓名,工号,薪水,还有奖金,工作内容。
•对给出需求进行数据建模。
abstract class Employee //抽象类 { private String name; private String id; private double pay; public Programmer(String name,String id,double pay) { this.name = name; this.id = id; this.pay = pay; } public abstract void work(); } class Programmer extends Employee { public Programmer(String name,String id,double pay) { //super();//error,父类中没有空参数的构造函数。 super(name,id,pay);//传入参数初始化 } public void work() { System.out.println("code..."); } } class Manager extends Employee { private double bonus; public Programmer(String name,String id,double pay,double bonus) { super(name,id,pay);//共性 this.bonus = bonus; //个性 } public void work() { System.out.println("code..."); } } class AbstractDemo { public static void main(String[] args) { System.out.println("Hello World!"); } }
6.8 接口
(1)格式: interface 接口名{}
(2)接口中的成员修饰符是固定的。
•成员常量:public static final
•成员函数:public abstract
•发现接口中的成员都是public的。
/* abstract class Demo { abstract void show(); abstract void show2(); }*/ /*1. 当抽象类中的抽象方法都是抽象时,这时候可以用另一种表现形式:接口。其实:接口就是一个特殊的抽象类。 2. 接口中最常见成员:全局常量、抽象方法。 3. 接口中的成员都是公共的。 4. 如何使用接口? 需要子类覆盖接口中的抽象方法,该类才可以实例化,否则该类还是一个抽象类。 5. 类与类是继承关系、类与接口是实现关系。
6. 接口中没有构造函数 */ interface Demo { //接口中最常见成员 public static final int NUM =3; //全局常量 public abstract void show(); //抽象方法 //接口中的成员都是公共的。 } class SubDemo implements Demo { public void show(){} } class InterfaceDemo { public static void main(String[] args) { Subdemo d = new SubDemo(); System.out.println(d.NUM); System.out.println(SubDemo.NUM); System.out.println(Demo.NUM); //都可以访问 } }
(3)接口的出现将“多继承”通过另一种形式体现出来,即“多实现”。
/* 接口的好处:它可以解决多继承的问题,它将多继承改良成了多实现. 因为父类中的方法有主体,接口中的方法没有主体,不会发生调用不确定性的情况。 一个类可以实现多个接口 */ interface A { //void show1(); void show(); } interface B { //void show2(); void show(); } class C implements A,B //多实现,扩展了C类的功能 { //public void show1(){} //public void show2(){} public void show(){} } /* 一个类在继承一个类的同时可以实现多个接口 接口的出现避免了单继承的局限性。 */ class Fu { public void show(){} } interface Inter { public void method(); } class Zi extends Fu implements Inter//在继承的基础上,扩展子类功能 { public void method(){}//实现接口 } class InterfaceDemo { public static void main(String[] args) { System.out.println("Hello word"); } } /* 1. 接口与接口的关系是继承 2. 接口之间存在着多继承 */ interface A { } interface B extends A { } interface c extends A, B //多继承 { }
6.8.1 接口的思想(特点)
(1)接口是对外暴露的规则。
(2)接口是程序的功能扩展。
(3)接口的出现降低耦合性。
(4)接口可以用来多实现。
(5)类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。
(6)接口与接口之间可以有继承关系。
6.8.2 接口与抽象类
|
共 性: |
都是不断抽取出来的抽象的概念 |
|
区别 1: |
抽象类体现继承关系,一个类只能单继承 接口体现实现关系,一个类可以多实现 |
|
区别 2: |
抽象类是继承,是 "is a "关系 接口是实现,是 "like a"关系 |
|
区别 3: |
抽象类中可以定义非抽象方法,供子类直接使用 接口的方法都是抽象,接口中的成员都有固定修饰符 |
开发时,是定义抽象类好呢?还是定义接口好呢!?
要根据不同的问题领域进行分析。
//犬按功能分类:导盲犬、搜爆犬 //抽象类:定义了一类事物的基本功能 //接口:定义了事物的扩展功能 abstract class 犬 { abstract void 训练(); } interface class 搜爆able { abstract void 搜爆(); } class 搜爆犬 extends 犬 implements 搜爆able { public void 训练() { } public void 搜爆() { } }
6.9 多态
(1)定义:某一类事物的多种存在形态。
•例:动物中猫,狗。
(2)猫这个对象对应的类型是猫类型
•猫 x = new 猫();
(3)同时猫也是动物中的一种,也可以把猫称为动物。
•动物 y = new 猫();
•动物是猫和狗具体事物中抽取出来的父类型。
•父类型引用指向了子类对象。
6.9.1 程序中体现:
父类或者接口的引用指向或者接收自己的子类对象。
(1)好处和作用: 多态的存在提高了程序的扩展性和后期可维护性
(2)前提: •需要存在继承或者实现关系
•要有覆盖操作
/* 对象的多态性 class 动物 { } class 猫 { } class 狗 { } 猫 X = new 猫(); 动物 X = new 猫();对象多态性 猫这类事物具备猫的形态,又具备动物的形态,这就是对象的多态性。 在代码中的体现:父类或者接口的引用指向其子类的对象。 多态的好处;多态的存在提高了程序的扩展性和后期可维护性,前期定义的代码可以使用后期的内容 多态的弊端:前期定义的内容不能使用(调用)后期子类的特有内容 多态的前提:1.必须有关系:继承、实现。 2.要有覆盖 */ abstract class Animal { abstract void eat(); } class Dog extends Animal { void eat() { System.out.println("啃骨头"); } void lookHome() { System.out.println("看家"); } } class Cat extends Animal { void eat() { System.out.println("吃鱼"); } void CatchMouse() { System.out.println("抓老鼠"); } } class DouTaiDemo { public static void main(String[] args) { //Cat c = new Cat(); //method(c); method(new Cat());//统一调用 method(new Dog()); } public static void method(Animal a) //多态,提高代码复用性。Animal父类作为引用 { if(a instanceof Cat)//instanceof 用于判断对象的类型
{ a.CatchMouse(); } a.eat();
}
}
//转型 class 毕姥爷 { void 讲课() { System.out.println("管理"); } void 钓鱼() { System.out.println("钓鱼"); } } class 毕老师 { void 讲课() { System.out.println("Java"); } void 看电影() { System.out.println("看电影"); } } class DuoTaiDemo { public static void main(String[] args) { //毕老师 X= new 毕老师(); //x.讲课(); //x.看电影(); //向上转型,限制对特有功能的访问 毕姥爷 x= new 毕老师(); x.讲课();// JAVA,重载了父类 x.钓鱼();// 继承了父类 x.看电影;//不可以 //向下转型,目的是为了使用子类中的特有方法。 毕老师 a = (毕老师)x; a.看电影;//可以 //注意:对于转型,自始至终都是子类对象在做着类型的变化 //Animal al = new Dog(); 错误 //Cat cl = (Cat)al; } }
6.9.2 多态的特点
(1)成员函数:
•编译时:要查看引用变量所属的类中是否有所调用的成员。
•在运行时:要查看对象所属的类中是否有所调用的成员。
(2)成员变量:
•只看引用变量所属的类。
Java中的上帝:Object
开发中经常需要重写的有:equals()、getClass()、hashCode()、toString()
/* JAVA 中的上帝:Object类 1. Object 初始化 2. Object 比较 equals() 3. getClass(); 获取类文件,返回Class对象 4. hashCode() 5. toString() 既然Object中有提供对象转成字符串的方式, 直接沿用使用即可,但是Person类中想定义自己对应的字符串内容 使用覆盖。 */ class Person // extends Object { //1. Object 初始化 Person()//隐式存在 { super(); } //2. Object 比较 equals() private int age; Person(int age) { this.age = age; } //比较同龄人的方法 //比较对象是否相同的功能父类中已经定义 //子类中要使用,但是想要按照自己的内容来完成判断是否相同的依据。就可以使用覆盖操作 //覆盖父类中的equals方法。建立Person类自己的比较多些是否相同的依据。 public boolean equals(Object obj) { return this.age = p.age //直接这样比较,错误,p已经向上转型,p已经为Object类型 if(!(obj instanceof Person)) { return false;//太菜鸟 throw new ClassCastException("类型错误");//专业的写法 }else{ Person p = (Person)obj; return this.age = obj.age; } } /*5. 既然Object中有提供对象转成字符串的方式, 直接沿用使用即可,但是Person类中想定义自己对应的字符串内容 使用覆盖。*/ public String toString(){ return "Persong[age="+age+"]"; } } class ObjectDemo { public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person(); System.out.println(p1==p2);//false System.out.println(p1.equals(p2));//false Person p3=p1; System.out.println(p1==p3);//true System.out.println(p1.equals(p3));//true Person p4 = new Person(21); Person p5 = new Person(23); System.out.println(p4==p5);//false System.out.println(p4.equals(p5));//true //3. getClass(); 获取类文件,返回Class对象 Class c1 = p4.getClass();//获取p4对象所属的字节码文件对象 Class c2 = p5.getClass();//在内存中,字节码只有一份,对象有多个 System.out.println(c1.equals(c2));//true System.out.println(c1.getName());//Person //4. hashCode() System.out.println(p1.hashCode());//3753023 //toString(); 将对象转成字符串 //toString()实现方式:getClass().getName() + '@' + Integer.toHexString(hashCode()) System.out.println(p1.toString());//Person@39443f; 在println内自动加上toString() System.out.println(p1);//Person@39443f System.out.println(p1.getClass().getName()+"#"+Integer.toHexString(p1.hashCode()));//Person@39443f Person p = p1.toString();//类型不匹配 } }
6.9.3 内部类
(1)将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。
(2)访问特点:
•内部类可以直接访问外部类中的成员,包括私有成员。
•而外部类要访问内部类中的成员必须要建立内部类的对象。
/* 内部类。 定义在类的内部,也叫内置类,嵌套类。 访问方式: 内部类可以直接访问外部类中的成员。 外部类需要创建内部类的对象访问内部类中的成员。 在描述事物时,内部还有具体的事物需要被描述。这时就可以用内部类来描述。 因为该内部事物访问到了外部事物的内容。 */ class Outer { static int num = 4; /*static*/ class Inner//内部类 { //static final int x= 4; /*static*/ void show()//静态方法只能定义在静态的内部类中。 { System.out.println("Inner show run..."+num); } } public void method() { //创建内部类的对象。访问内部类中的成员。 Inner in = new Inner(); in.show(); } } class InnerClassDemo { public static void main(String[] args) { // Outer out = new Outer(); //直接创建内部类对象。 // Outer.Inner in = new Outer().new Inner(); // in.show(); //当内部类是静态时。 // Outer.Inner in = new Outer.Inner(); // in.show(); //当内部类静态,访问其中的静态方法时。 // Outer.Inner.show(); } }
/* 内部类为什么就可以直接访问外部类中的成员呢? 内部类持有了一个外部类的引用 外部类名.this */ class Outer { private int num = 7; class Inner { //int num = 8; void show() { //int num = 9; System.out.println(num); } } public void method() { new Inner().show(); } } class InnerClassDemo2 { public static void main(String[] args) { // new Outer().method(); InnerClassDemo2.Inner in = new InnerClassDemo2().new Inner(); in.function(); } class Inner { void function() { System.out.println("function run"); } } }
6.9.4 内部类的位置
(1)内部类定义在成员位置上
•可以被private static成员修饰符修饰。
•被static修饰的内部类只能访问外部类中的静态成员。
(2)内部类定义在局部位置上
•也可以直接访问外部类中的成员。
•同时可以访问所在局部中的局部变量,但必须是被final修饰的。
class Outer { private int num = 5; private Object obj; public void method(int x) { final int y = 4; class Inner extends Object//内部类定义在了局部位置上。只能访问局部中被final修饰的局部变量。 { void show() { System.out.println("Inner show .."+y); } public String toString() { return "inner..."+y; } } // Inner in = new Inner(); // in.show(); obj = new Inner(); } public void func() { System.out.println(obj.toString()); } } class InnerClassDemo3 { public static void main(String[] args) { Outer out = new Outer(); out.method(2); out.func(); } }
6.9.5 匿名内部类
(1)就是内部类的简化写法。
(2)前提: •内部类可以继承或实现一个外部类或者接口。
(3)格式为: •new 外部类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}
(4)简单理解: •就是建立一个带内容的外部类或者接口的子类匿名对象。
/* 匿名内部类:内部类简化形式。 前提:内部类必须继承类或者实现接口。 格式; new 父类或者接口() */ abstract class Demo { abstract void show(); abstract void show2(); } class Outer { int num =9; /* class Inner extends Demo { void show() { System.out.println("inner show .."+num); } } */ public void function() { //new Inner().show(); Demo d = new Demo()//匿名内部类:就是一个Demo类的匿名子类对象。 { void show() { System.out.println("inner show .."+num); } void show2() { System.out.println("inner show2 .."+num); } }; d.show(); d.show2(); } } class InnerClassDemo4 { public static void main(String[] args) { Outer out = new Outer(); out.function(); } }
class Outer { void method() { new Object() { void show() { System.out.println("show "); } }.show(); Object obj = new Object() { void show() { System.out.println("show "); } }; // obj.show();//error. } } interface Inter { void show(); } class Test { //中的代码补足,使用匿名内部类的方式。 static Inter method() { return new Inter() { public void show(){} }; } } class InnerClassDemo5 { public static void main(String[] args) { // Outer out = new Outer(); // out.method(); Test.method().show(); /* Test.method():Test类中有一个名为method的方法,而且是静态的。 Test.method().show():调用了method()方法后,还能调用show,说明method()方法运行完返回一个对象。 而且该对象是Inter类型。 */ } }

浙公网安备 33010602011771号