笔记09
课程内容
1、多态
2、抽象
3、接口
一、多态
1、多态:字面意思理解:事物的多种状态,在面向对象编程语言中,接口的多种不同的实现方式即为多态。
2、多态:
事物的多种状态:
对象的多态性:同一个对象,可能具有不同的名称,同一个对象,有不同的类型的引用指向它。
Student stu = new Student();
Person p = new Student();
类型的多态性: 同一个类型,可能具有不同的子类实现。同一个类型引用,有不同的对象实现
本质:同一个名字和描述,可以在不同的场景有不同的真实实现。
Object obj = new Person();
Object obj1 = new Student();
3、多态的前提
(1)要有子父类的继承(实现)关系
(2)体现出多态的特点:方法的重写
(3)父类的引用指向子类的对象
package com. ujiuye. demos;
public class Demo_1 {
public static void main ( String[ ] args) {
Animal an = new Dog ( ) ;
an. eat ( ) ;
}
}
class Animal {
public void eat ( ) {
System. out. println ( "吃东西" ) ;
}
}
class Dog extends Animal {
@Override
public void eat ( ) {
System. out. println ( "狗吃肉" ) ;
}
}
多态中成员方法的访问特点
1、【编译看左边,运行看右边】
2、编译的时候要看【=】左边的引用an所属的类型中,是否有该方法(就是该引用调用的方法)的声明,如果有,编译成功,如果没有,就编译失败
3、运行的时候要看【=】右边对象所属的类型中,是如何实现这个方法的,最终运行的是子类写过的方法实现。
package com. ujiuye. demos;
public class Demo_2 {
public static void main ( String[ ] args) {
Animals an = new Dogs ( ) ;
an. eat ( ) ;
}
}
class Animals {
public void eat ( ) {
System. out. println ( "吃东西" ) ;
}
}
class Dogs extends Animals {
@Override
public void eat ( ) {
System. out. println ( "狗吃肉" ) ;
}
}
多态中成员变量的访问特点
1、编译看左边,运行看左边
2、编译的时候要看【=】左边的引用an所属的类型中,是否有该变量的定义,如果有,编译成功,如果没有,就编译失败
3、运行的时候要看【=】左边引用所属的类型中该变量的赋值。运行的结果就是【=】左边中对变量的额赋值
package com. ujiuye. demos;
public class Demo_3 {
public static void main ( String[ ] args) {
Animalss am = new Dogss ( ) ;
System. out. println ( am. a) ;
}
}
class Animalss {
int a = 20 ;
}
class Dogss extends Animalss {
int a = 30 ;
}
超人案例
1、定义一个人类(Person),要求有姓名,工作的行为
2、定义一个超人(SuperMan),要求重写工作的行为,并增加飞行的行为
向上向下转型
1、向上转型:
使用子类的引用指向子类的对象(正常情况)
多态中:使用父类的引用指向子类的对象(向上转型)
本质:缩小了对象本身的访问范围,减少了访问权限(只能访问父类中的定义的内容)
2、向下转型:
概念:
让指向子类对象的引用,恢复成子类的引用
格式:
子类类型 对象名 = (子类类型)父类类型的引用
本质:恢复子类类型原有的访问范围
3、注意:
只有存在子父类或者实现关系的时候,也就是存在多态的时候,才能进行向上向下转型。
package com. ujiuye. demos;
public class Person {
String name = "Peter" ;
public void work ( ) {
System. out. println ( "卖煎饼果子" ) ;
}
}
package com. ujiuye. demos;
public class SuperMan extends Person {
String name = "zhiZhuXia" ;
public void work ( ) {
System. out. println ( "敲代码" ) ;
}
public void fly ( ) {
System. out. println ( "飞着拯救世界" ) ;
}
}
package com. ujiuye. demos;
public class Demo_4 {
public static void main ( String[ ] args) {
SuperMan superMan = new SuperMan ( ) ;
Person p = new SuperMan ( ) ;
System. out. println ( p. name) ;
p. work ( ) ;
SuperMan sm = ( SuperMan) p;
sm. fly ( ) ;
}
}
多态的好处
1、提高了代码的可扩展性
把不同的子类对象都当做父类来看,可以屏蔽不同子类对象的差异,写出通用的代码,做出通用的编程,以适应需求的不同的变化
2、在方法的参数列表中,定义一个父类类型的引用,将来在调用的时候,所有的子类类型的对象,都可以作为方法的实际参数。
3、不在方法的参数列表中,就在普通的方法体中,使用父类的类型指向子类的对象,也能提高代码的扩展性。对象来源很广泛。不仅仅是new出来的。(还可能是通过反射获取的,通过文件读取的,还可以的网络传递的,在写代码的时候,无法知道对象具体的子类类型的)需要使用父类类型的引用,操作不知道的子类类型的对象。
榨汁机案例
package com. ujiuye. juicedemo;
public class JuiceMachine {
public void makeJuice ( Fruit f) {
f. flow ( ) ;
}
}
package com. ujiuye. juicedemo;
public class Fruit {
public void flow ( ) {
System. out. println ( "果汁" ) ;
}
}
package com. ujiuye. juicedemo;
public class WaterMelon extends Fruit {
public void flow ( ) {
System. out. println ( "流出西瓜汁" ) ;
}
}
package com. ujiuye. juicedemo;
public class Banana extends Fruit {
public void flow ( ) {
System. out. println ( "流出香蕉汁" ) ;
}
}
package com. ujiuye. juicedemo;
public class Apple extends Fruit {
public void flow ( ) {
System. out. println ( "产生苹果汁" ) ;
}
}
package com. ujiuye. demos;
import java. util. Scanner;
import com. ujiuye. juicedemo. Apple;
import com. ujiuye. juicedemo. Banana;
import com. ujiuye. juicedemo. Fruit;
import com. ujiuye. juicedemo. JuiceMachine;
import com. ujiuye. juicedemo. Orange;
import com. ujiuye. juicedemo. WaterMelon;
public class Demo_5 {
public static void main ( String[ ] args) throws Exception {
JuiceMachine jm = new JuiceMachine ( ) ;
Scanner scanner = new Scanner ( System. in) ;
System. out. println ( "请输入你要喝的果汁类型" ) ;
String fruitName = scanner. nextLine ( ) ;
Class clazz = Class. forName ( fruitName) ;
Object newInstance = clazz. newInstance ( ) ;
Fruit f = ( Fruit) newInstance;
jm. makeJuice ( f) ;
}
}
二、抽象类
抽象方法
1、抽象:抽取相同的,相似的得内容出来
2、抽象方法:只有方法的声明,没有方法实现的方法,就是抽象方法。
在各个子类中,对于某个方法都有自己不同的实现,所以实现各不相同,无法抽取,只能把抽取方法声明,在父类中,方法就只有方法声明没有方法体,就是抽象方法。
3、定义的格式:
没有方法的实现,连大括号都没有,直接就在方法的声明后面加上一个分号,表示方法定义结束
为了将方法标记为抽象方法,需要在方法的前面加上一个abstract关键字
抽象类
1、可以定义抽象方法的类,就是抽象类
2、定义格式
abstract class 类名{
}
package com. ujiuye. demos;
public class Demo_6 {
public static void main ( String[ ] args) {
Dogs_1 dogs_1 = new Dogs_1 ( ) ;
dogs_1. eat ( ) ;
}
}
abstract class Animals_1 {
public abstract void eat ( ) ;
}
class Dogs_1 extends Animals_1 {
@Override
public void eat ( ) {
System. out. println ( "狗吃肉" ) ;
}
}
class Cat_1 extends Animals_1 {
public void eat ( ) {
System. out. println ( "猫吃鱼" ) ;
}
}
抽象类的特点
1、抽象类和抽象方法都是需要使用abstract关键字修饰
抽象类: abstract class{}
抽象方法:public abstract void 方法名();
2、抽象类和抽象方法的关系
抽象方法所在的类必须是抽象类
抽象类中未必就一定都是抽象方法,抽象类中可以没有抽象方法
3、抽象类的实例化(抽象类如何创建对象)
抽象类不能实例化(不能new对象)
定义抽象类的子类,由子类创建对象,调用方法
4、抽象类子类的前途
在子类中,将父类中所有的抽象方法都重写了,子类就是一个普通类,就可以创建对象
在子类中,没有将父类中所有的抽象方法都重写,全部实现,子类就还是一个抽象类,还需要使用abstract关键字修饰子类。
package com. ujiuye. demos;
public class Demo_7 {
public static void main ( String[ ] args) {
AbstractClassImpl aci = new AbstractClassImpl ( ) ;
aci. test ( ) ;
aci. show ( ) ;
}
}
abstract class AbstractClass {
public abstract void test ( ) ;
public abstract void test_1 ( ) ;
public void show ( ) {
System. out. println ( "我不是抽象方法" ) ;
}
}
class AbstractClassImpl extends AbstractClass {
@Override
public void test ( ) {
System. out. println ( "重写后的方法" ) ;
}
@Override
public void test_1 ( ) {
System. out. println ( "重写后的方法test_1" ) ;
}
}
abstract class AbClass extends AbstractClass {
@Override
public void test ( ) {
System. out. println ( "test" ) ;
}
}
抽象类的成员特点
1、成员变量:可以定义变量的,也可以定义常量,但是不能被抽象
2、构造方法:有
虽然本类无法创建对象,但是抽象类它是有子类的,子类会访问父类的构造方法
是否有构造方法:不取决于该类是否能够创建对象,而是取决于该类是否可以定义成员变量,如果可以定义成员变量,那么就需要对成员变量进行赋值,就是用构造方法完成的。
3、成员方法:
既可以是抽象方法:子类如果全都实现了,就是普通类,没有全部实现就还是一个抽象类
也可以是非抽象的方法:用于给子类继承,提高代码的复用性。
package com. ujiuye. demos;
public class Demo_8 {
public static void main ( String[ ] args) {
AbsClassSon as = new AbsClassSon ( 12 ) ;
System. out. println ( as. getA ( ) ) ;
}
}
abstract class AbsClass {
final int b = 120 ;
private int a;
public AbsClass ( ) {
}
public AbsClass ( int a) {
this . a = a;
}
public void setA ( int a) {
this . a = a;
}
public int getA ( ) {
return a;
}
}
class AbsClassSon extends AbsClass {
public AbsClassSon ( ) {
}
public AbsClassSon ( int a) {
super ( a) ;
}
}
员工类练习
1、程序员类:属性(姓名,工号,工资,奖金),行为:敲代码
2、项目经理类:属性(姓名,工号,工资):行为:管理项目进度
3、向上抽取一个父类员工类(Employee):将程序员类和项目经理类中的共有的属性和行为,抽取到父类(Employee)中
4、在测试类中进行测试。
package com. ujiuye. practice;
public abstract class Employee {
private String name;
private int id;
private double salary;
public Employee ( ) {
super ( ) ;
}
public Employee ( String name, int id, double salary) {
super ( ) ;
this . name = name;
this . id = id;
this . salary = salary;
}
public String getName ( ) {
return name;
}
public void setName ( String name) {
this . name = name;
}
public int getId ( ) {
return id;
}
public void setId ( int id) {
this . id = id;
}
public double getSalary ( ) {
return salary;
}
public void setSalary ( double salary) {
this . salary = salary;
}
public abstract void work ( ) ;
}
package com. ujiuye. practice;
public class Coder extends Employee {
private double bonus;
public Coder ( ) {
}
public Coder ( String name, int id, double salary , double bonus) {
super ( name, id, salary) ;
this . bonus = bonus;
}
public double getBonus ( ) {
return bonus;
}
public void setBonus ( double bonus) {
this . bonus = bonus;
}
@Override
public void work ( ) {
System. out. println ( "开心的敲代码" ) ;
}
}
package com. ujiuye. practice;
public class Manager extends Employee {
public Manager ( ) {
super ( ) ;
}
public Manager ( String name, int id, double salary) {
super ( name, id, salary) ;
}
@Override
public void work ( ) {
System. out. println ( "指挥程序员写代码,控制项目进度" ) ;
}
}
package com. ujiuye. practice;
public class Test {
public static void main ( String[ ] args) {
Coder c = new Coder ( "李彦宏" , 1 , 8900 , 929292 ) ;
System. out. println ( c. getName ( ) ) ;
System. out. println ( c. getId ( ) ) ;
System. out. println ( c. getSalary ( ) ) ;
System. out. println ( c. getBonus ( ) ) ;
}
}
三、接口
1、广义:一切定义规则的就是接口
2、java语言中接口中,用于定义方法命名的规则的就是接口
3、好处:
一旦将命名规则定义出来,方法的调用和方法的实现进行分离,可以提升开发效率,降低代码的耦合
接口的特点
1、接口的定义:使用interface关键字,编译之后生成一个字节码文件(.class文件)
interface 接口名称{
方法声明的定义;
}
2、接口中,只可以声明抽象方法,(只能定义的给方法起名字的规则)
3、类可以实现接口:使用implements关键字
实现:接口中只有方法的声明,没有方法的实现,一个类实现了一个接口就要对接口中的抽象方法进行重写(实现)
class 类名称 implements 接口名称{
对接口中的实现
}
4、接口的实例化:不能直接进行实例化
定义一个类实现该接口,类创建对象,调用方法
5、接口的实现类前途
是一个抽象类,如果没有将接口中所有的抽象方法都重写,那么这个类就还是一个抽象类
如果一个类将接口中所有的抽象方法都重写了,那么该类就是一个普通类,能创建对象的
package com. ujiuye. demos;
public class Demo_10 {
public static void main ( String[ ] args) {
Inter_1Impl i1Impl = new Inter_1Impl ( ) ;
i1Impl. show ( ) ;
}
}
interface Inter_1 {
public abstract void show ( ) ;
public abstract void test ( ) ;
}
class Inter_1Impl implements Inter_1 {
@Override
public void show ( ) {
System. out. println ( "show" ) ;
}
@Override
public void test ( ) {
System. out. println ( "test" ) ;
}
}
abstract class Inter_1Impl1 implements Inter_1 {
@Override
public void show ( ) {
System. out. println ( "show" ) ;
}
}
接口中的成员特点
1、成员变量:
不可以定义成员变量,只能是常量
默认加上public static final
2、构造方法:
没有构造方法,接口中无法定义成员变量的,所以不需要使用构造方法给成员变量初始化赋值
虽然接口有自己的实现类,但是对于实现类而言不会访问接口中的构造方法。访问的是父类中的构造方法。
继承中访问父类的构造方法,其实是为了准备父类中的成员变量进行分配内存的过程。
实现中,接口中没有成员变量,实现类在创建对象时,也没有用到接口中的成员变量,因此不会访问接口中构造方法,接口中本身也没有构造方法。
3、成员方法:
jdk1.8以前
只能抽象方法,不能是非抽象的方法
默认加上了public abstract
jdk1.8
defualt 对方法可以有实现
static 方法,对方法有实现
package com. ujiuye. demos;
public class Demo_11 {
public static void main ( String[ ] args) {
Inter_2Impl inter_2Impl = new Inter_2Impl ( ) ;
System. out. println ( Inter_2. a) ;
}
}
interface Inter_2 {
int a = 10 ;
void show ( ) ;
}
class Inter_2Impl implements Inter_2 {
@Override
public void show ( ) {
}
}
类与类,类与接口,接口和接口之间的关系
1、类与类
继承的关系,使用extends
可以单继承,多层继承,不能多继承
2、类与接口的关系
实现关系:使用implements
可以单实现,也可以多实现
多实现的格式:
class 实现类类名 implements 接口1,接口2,接口3....{
重写所有接口中的所有的抽象方法;
}
在继承一个类的前提下,还可以实现多个接口
格式:
class 子类类名 extends 父类类名 implements 接口1 ,接口2.{
重写父类和接口中所有的抽象方法
}
3、接口跟接口的关系
继承的关系:使用extends
可以单继承,多继承,可以多层继承
多继承的格式:
interface 接口名 extends 父接口1 ,父接口2.。。{
相当于是继承了所有父接口中的所有的抽象方法
}
4、类与接口的区别
抽象类:定义事物本身固有的属性和行为 继承:是不是
接口:定义物体通过学习,训练扩展出来的行为 实现:有没有
package com. ujiuye. demos;
public class Demo_12 {
public static void main ( String[ ] args) {
}
}
interface Inter_11 {
void show11 ( ) ;
}
interface Inter_22 {
void test22 ( ) ;
}
interface Inter_33 {
void show33 ( ) ;
}
interface Inter_44 {
void test44 ( ) ;
}
interface Inter_66 extends Inter_11 {
void test66 ( ) ;
}
interface Inter_77 extends Inter_66 {
}
interface Inter_55 extends Inter_11 , Inter_22, Inter_33 {
void test55 ( ) ;
}
class Test_1 implements Inter_55 {
@Override
public void show11 ( ) {
}
@Override
public void test55 ( ) {
}
@Override
public void test22 ( ) {
}
@Override
public void show33 ( ) {
}
}
class InterImpl implements Inter_11 , Inter_22 {
@Override
public void test22 ( ) {
}
@Override
public void show11 ( ) {
}
}
class InterImplSon extends Person implements Inter_11 , Inter_22 {
@Override
public void test22 ( ) {
}
@Override
public void show11 ( ) {
}
}
电脑USB案例
1、定义一个电脑类(Computer)类型,要求有开机,关机,打游戏,看电影的一些功能,并且能够使用指定的一些外接设备,例如键盘,鼠标
2、在测试类中,创建电脑对象,调用其功能,之后创建鼠标键盘等外接设备,能够连入电脑
package com.ujiuye.computerinter;
public class Computer {
public void powerOn() {
System.out.println("开机");
}
public void powerOff() {
System.out.println("关机");
}
public void playGame() {
System.out.println("打游戏");
}
public void watchMovie() {
System.out.println("看电影");
}
// 定义一个使用USB的方法
public void useUSB(USB usb) {//USB usb = new Mouse();
usb.use();
}
}
package com.ujiuye.computerinter;
public class KeyBoard implements USB{
@Override
public void use() {
System.out.println("键盘连入电脑");
}
}
package com.ujiuye.computerinter;
public class Mouse implements USB{
public void click() {
System.out.println("点击鼠标,玩消消乐");
}
@Override
public void use() {
System.out.println("连入鼠标");
}
}
package com.ujiuye.computerinter;
public interface USB {
public abstract void use();
}
package com.ujiuye.computerinter;
public class Test {
public static void main(String[] args) {
// 创建电脑对象
Computer com = new Computer();
// 创建鼠标对象
Mouse m = new Mouse();
// 创建键盘对象
KeyBoard kb = new KeyBoard();
com.powerOn();
com.useUSB(m);//传入的是USB的实现类对象
com.useUSB(kb);
com.playGame();
com.watchMovie();
com.powerOff();
}
}
四、匿名内部类
1、没有名字的内部类
2、匿名内部类的前提
匿名类:继承一个类
匿名类:实现一个接口
3、格式:
new 父类类名或者接口名(){
父类方法的重写,或者接口的实现内容
};
4、本质:
创建一个类的子类对象,接口的实现类对象
5、匿名内部类也是有字节码文件的
名字:通过匿名内部类的顺序描述类名
第一个匿名内部类,名字:【外部类名$1】
第二个匿名内部类,名字:【外部类名$2】
package com. ujiuye. demos;
public class Demo_14 {
public static void main ( String[ ] args) {
Teacher teacher = new Teacher ( ) {
@Override
public void teach ( ) {
System. out. println ( "教学" ) ;
}
} ;
Inters i = new Inters ( ) {
@Override
public void show ( ) {
System. out. println ( "hello gril" ) ;
}
} ;
i. show ( ) ;
}
}
interface Inters {
void show ( ) ;
}
class IntersImpl implements Inters {
@Override
public void show ( ) {
System. out. println ( "hello" ) ;
}
}
abstract class Teacher {
public abstract void teach ( ) ;
}
class MathTeacher extends Teacher {
@Override
public void teach ( ) {
}
}
class Car {
int a;
public void show ( ) {
System. out. println ( "car" ) ;
}
}
class Bus extends Car {
int a = 20 ;
}