09_面向对象(final关键字、多态的概述和讲解、抽象类的概述和讲解、接口的概述和讲解)
1:final关键字(掌握)
(1)是最终的意思,可以修饰类,方法,变量。
(2)特点:
A:它修饰的类,不能被继承。
B:它修饰的方法,不能被重写。
C:它修饰的变量,是一个常量。
(3)面试相关:
A:局部变量
a:基本类型 值不能发生改变
b:引用类型 地址值不能发生改变,但是对象的内容是可以改变的
B:初始化时机
a:只能初始化一次。
b:常见的给值
定义的时候。(推荐)
构造方法中。
FinalDemo.java
/* final可以修饰类,方法,变量 特点: final可以修饰类,该类不能被继承。 final可以修饰方法,该方法不能被重写。(覆盖,复写) final可以修饰变量,该变量不能被重新赋值。因为这个变量其实常量。 常量: A:字面值常量 "hello",10,true B:自定义常量 final int x = 10; */ //final class Fu //无法从最终Fu进行继承 class Fu { public int num = 10; public final int num2 = 20; /* public final void show() { } */ } class Zi extends Fu { // Zi中的show()无法覆盖Fu中的show() public void show() { num = 100; System.out.println(num); //无法为最终变量num2分配值 //num2 = 200; System.out.println(num2); } } class FinalDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
FinalTest.java
/* 面试题:final修饰局部变量的问题 基本类型:基本类型的值不能发生改变。 引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。 */ class Student { int age = 10; } class FinalTest { public static void main(String[] args) { //局部变量是基本数据类型 int x = 10; x = 100; System.out.println(x); final int y = 10; //无法为最终变量y分配值 //y = 100; System.out.println(y); System.out.println("--------------"); //局部变量是引用数据类型 Student s = new Student(); System.out.println(s.age); s.age = 100; System.out.println(s.age); System.out.println("--------------"); final Student ss = new Student(); System.out.println(ss.age); ss.age = 100; System.out.println(ss.age); //重新分配内存空间 //无法为最终变量ss分配值 ss = new Student(); } }
FinalTest2.java
/* final修饰变量的初始化时机 A:被final修饰的变量只能赋值一次。 B:在构造方法完毕前。(非静态的常量) */ class Demo { //int num = 10; //final int num2 = 20; int num; final int num2; { //num2 = 10; } public Demo() { num = 100; //无法为最终变量num2分配值 num2 = 200; } } class FinalTest2 { public static void main(String[] args) { Demo d = new Demo(); System.out.println(d.num); System.out.println(d.num2); } }
ZiDemo.java
/* 继承的代码体现 由于继承中方法有一个现象:方法重写。 所以,父类的功能,就会被子类给覆盖调。 有些时候,我们不想让子类去覆盖掉父类的功能,只能让他使用。 这个时候,针对这种情况,Java就提供了一个关键字:final final:最终的意思。常见的是它可以修饰类,方法,变量。 */ class Fu { public final void show() { System.out.println("这里是绝密资源,任何人都不能修改"); } } class Zi extends Fu { // Zi中的show()无法覆盖Fu中的show() public void show() { System.out.println("这是一堆垃圾"); } } class ZiDemo { public static void main(String[] args) { Zi z = new Zi(); z.show(); } }
2:多态(掌握)
(1)同一个对象在不同时刻体现出来的不同状态。
(2)多态的前提:
A:有继承或者实现关系。
B:有方法重写。
C:有父类或者父接口引用指向子类对象。
多态的分类:
a:具体类多态
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
b:抽象类多态
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
c:接口多态
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
(3)多态中的成员访问特点
A:成员变量
编译看左边,运行看左边
B:构造方法
子类的构造都会默认访问父类构造
C:成员方法
编译看左边,运行看右边
D:静态方法
编译看左边,运行看左边
为什么?
因为成员方法有重写。
(4)多态的好处:
A:提高代码的维护性(继承体现)
B:提高代码的扩展性(多态体现)
(5)多态的弊端:
父不能使用子的特有功能。
现象:
子可以当作父使用,父不能当作子使用。
(6)多态中的转型
A:向上转型
从子到父
B:向下转型
从父到子
(7)孔子装爹的案例帮助大家理解多态
(8)多态的练习
A:猫狗案例
B:老师和学生案例
DuoTaiDemo.java
/* 多态:同一个对象(事物),在不同时刻体现出来的不同状态。 举例: 猫是猫,猫是动物。 水(液体,固体,气态)。 多态的前提: A:要有继承关系。 B:要有方法重写。 其实没有也是可以的,但是如果没有这个就没有意义。 动物 d = new 猫(); d.show(); 动物 d = new 狗(); d.show(); C:要有父类引用指向子类对象。 父 f = new 子(); 用代码体现一下多态。 多态中的成员访问特点: A:成员变量 编译看左边,运行看左边。 B:构造方法 创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。 C:成员方法 编译看左边,运行看右边。 D:静态方法 编译看左边,运行看左边。 (静态和类相关,算不上重写,所以,访问还是左边的) 由于成员方法存在方法重写,所以它运行看右边。 */ class Fu { public int num = 100; public void show() { System.out.println("show Fu"); } public static void function() { System.out.println("function Fu"); } } class Zi extends Fu { public int num = 1000; public int num2 = 200; public void show() { System.out.println("show Zi"); } public void method() { System.out.println("method zi"); } public static void function() { System.out.println("function Zi"); } } class DuoTaiDemo { public static void main(String[] args) { //要有父类引用指向子类对象。 //父 f = new 子(); Fu f = new Zi(); System.out.println(f.num); //找不到符号 //System.out.println(f.num2); f.show(); //找不到符号 //f.method(); f.function(); } }
DuoTaiDemo2.java
/* 多态的好处: A:提高了代码的维护性(继承保证) B:提高了代码的扩展性(由多态保证) 猫狗案例代码 */ class Animal { public void eat(){ System.out.println("eat"); } public void sleep(){ System.out.println("sleep"); } } class Dog extends Animal { public void eat(){ System.out.println("狗吃肉"); } public void sleep(){ System.out.println("狗站着睡觉"); } } class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } public void sleep() { System.out.println("猫趴着睡觉"); } } class Pig extends Animal { public void eat() { System.out.println("猪吃白菜"); } public void sleep() { System.out.println("猪侧着睡"); } } //针对动物操作的工具类 class AnimalTool { private AnimalTool(){} /* //调用猫的功能 public static void useCat(Cat c) { c.eat(); c.sleep(); } //调用狗的功能 public static void useDog(Dog d) { d.eat(); d.sleep(); } //调用猪的功能 public static void usePig(Pig p) { p.eat(); p.sleep(); } */ public static void useAnimal(Animal a) { a.eat(); a.sleep(); } } class DuoTaiDemo2 { public static void main(String[] args) { //我喜欢猫,就养了一只 Cat c = new Cat(); c.eat(); c.sleep(); //我很喜欢猫,所以,又养了一只 Cat c2 = new Cat(); c2.eat(); c2.sleep(); //我特别喜欢猫,又养了一只 Cat c3 = new Cat(); c3.eat(); c3.sleep(); //... System.out.println("--------------"); //问题来了,我养了很多只猫,每次创建对象是可以接受的 //但是呢?调用方法,你不觉得很相似吗?仅仅是对象名不一样。 //我们准备用方法改进 //调用方式改进版本 //useCat(c); //useCat(c2); //useCat(c3); //AnimalTool.useCat(c); //AnimalTool.useCat(c2); //AnimalTool.useCat(c3); AnimalTool.useAnimal(c); AnimalTool.useAnimal(c2); AnimalTool.useAnimal(c3); System.out.println("--------------"); //我喜欢狗 Dog d = new Dog(); Dog d2 = new Dog(); Dog d3 = new Dog(); //AnimalTool.useDog(d); //AnimalTool.useDog(d2); //AnimalTool.useDog(d3); AnimalTool.useAnimal(d); AnimalTool.useAnimal(d2); AnimalTool.useAnimal(d3); System.out.println("--------------"); //我喜欢宠物猪 //定义一个猪类,它要继承自动物,提供两个方法,并且还得在工具类中添加该类方法调用 Pig p = new Pig(); Pig p2 = new Pig(); Pig p3 = new Pig(); //AnimalTool.usePig(p); //AnimalTool.usePig(p2); //AnimalTool.usePig(p3); AnimalTool.useAnimal(p); AnimalTool.useAnimal(p2); AnimalTool.useAnimal(p3); System.out.println("--------------"); //我喜欢宠物狼,老虎,豹子... //定义对应的类,继承自动物,提供对应的方法重写,并在工具类添加方法调用 //前面几个必须写,我是没有意见的 //但是,工具类每次都改,麻烦不 //我就想,你能不能不改了 //太简单:把所有的动物都写上。问题是名字是什么呢?到底哪些需要被加入呢? //改用另一种解决方案。 } /* //调用猫的功能 public static void useCat(Cat c) { c.eat(); c.sleep(); } //调用狗的功能 public static void useDog(Dog d) { d.eat(); d.sleep(); } */ }
DuoTaiDemo3.java
/* 多态的弊端: 不能使用子类的特有功能。 */ class Fu { public void show() { System.out.println("show fu"); } } class Zi extends Fu { public void show() { System.out.println("show zi"); } public void method() { System.out.println("method zi"); } } class DuoTaiDemo3 { public static void main(String[] args) { //测试 Fu f = new Zi(); f.show(); f.method(); } }
DuoTaiDemo4.java
/* 多态的弊端: 不能使用子类的特有功能。 我就想使用子类的特有功能?行不行? 行。 怎么用呢? A:创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了) B:把父类的引用强制转换为子类的引用。(向下转型) 对象间的转型问题: 向上转型: Fu f = new Zi(); 向下转型: Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。 */ class Fu { public void show() { System.out.println("show fu"); } } class Zi extends Fu { public void show() { System.out.println("show zi"); } public void method() { System.out.println("method zi"); } } class DuoTaiDemo4 { public static void main(String[] args) { //测试 Fu f = new Zi(); f.show(); //f.method(); //创建子类对象 //Zi z = new Zi(); //z.show(); //z.method(); //你能够把子的对象赋值给父亲,那么我能不能把父的引用赋值给子的引用呢? //如果可以,但是如下 Zi z = (Zi)f; z.show(); z.method(); } }
DuoTaiDemo5.java
/* ClassCastException:类型转换异常 一般在多态的向下转型中容易出现 */ class Animal { public void eat(){} } class Dog extends Animal { public void eat() {} public void lookDoor() { } } class Cat extends Animal { public void eat() { } public void playGame() { } } class DuoTaiDemo5 { public static void main(String[] args) { //内存中的是狗 Animal a = new Dog(); Dog d = (Dog)a; //内存中是猫 a = new Cat(); Cat c = (Cat)a; //内存中是猫 Dog dd = (Dog)a; //ClassCastException } }
DuoTaiTest.java
/* 多态练习:猫狗案例 */ class Animal { public void eat(){ System.out.println("吃饭"); } } class Dog extends Animal { public void eat() { System.out.println("狗吃肉"); } public void lookDoor() { System.out.println("狗看门"); } } class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } public void playGame() { System.out.println("猫捉迷藏"); } } class DuoTaiTest { public static void main(String[] args) { //定义为狗 Animal a = new Dog(); a.eat(); System.out.println("--------------"); //还原成狗 Dog d = (Dog)a; d.eat(); d.lookDoor(); System.out.println("--------------"); //变成猫 a = new Cat(); a.eat(); System.out.println("--------------"); //还原成猫 Cat c = (Cat)a; c.eat(); c.playGame(); System.out.println("--------------"); //演示错误的内容 //Dog dd = new Animal(); //Dog ddd = new Cat(); //ClassCastException //Dog dd = (Dog)a; } }
DuoTaiTest2.java
/* 不同地方饮食文化不同的案例 */ class Person { public void eat() { System.out.println("吃饭"); } } class SouthPerson extends Person { public void eat() { System.out.println("炒菜,吃米饭"); } public void jingShang() { System.out.println("经商"); } } class NorthPerson extends Person { public void eat() { System.out.println("炖菜,吃馒头"); } public void yanJiu() { System.out.println("研究"); } } class DuoTaiTest2 { public static void main(String[] args) { //测试 //南方人 Person p = new SouthPerson(); p.eat(); System.out.println("-------------"); SouthPerson sp = (SouthPerson)p; sp.eat(); sp.jingShang(); System.out.println("-------------"); //北方人 p = new NorthPerson(); p.eat(); System.out.println("-------------"); NorthPerson np = (NorthPerson)p; np.eat(); np.yanJiu(); } }
DuoTaiTest3.java
/* 看程序写结果:先判断有没有问题,如果没有,写出结果 */ class Fu { public void show() { System.out.println("fu show"); } } class Zi extends Fu { public void show() { System.out.println("zi show"); } public void method() { System.out.println("zi method"); } } class DuoTaiTest3 { public static void main(String[] args) { Fu f = new Zi(); //找不到符号 //f.method(); f.show(); } }
DuoTaiTest4.java
/* 看程序写结果:先判断有没有问题,如果没有,写出结果 多态的成员访问特点: 方法:编译看左边,运行看右边。 继承的时候: 子类中有和父类中一样的方法,叫重写。 子类中没有父亲中出现过的方法,方法就被继承过来了。 */ class A { public void show() { show2(); } public void show2() { System.out.println("我"); } } class B extends A { /* public void show() { show2(); } */ public void show2() { System.out.println("爱"); } } class C extends B { public void show() { super.show(); } public void show2() { System.out.println("你"); } } public class DuoTaiTest4 { public static void main(String[] args) { A a = new B(); a.show(); B b = new C(); b.show(); } }
3:抽象类(掌握)
(1)把多个共性的东西提取到一个类中,这是继承的做法。
但是呢,这多个共性的东西,在有些时候,方法声明一样,但是方法体。
也就是说,方法声明一样,但是每个具体的对象在具体实现的时候内容不一样。
所以,我们在定义这些共性的方法的时候,就不能给出具体的方法体。
而一个没有具体的方法体的方法是抽象的方法。
在一个类中如果有抽象方法,该类必须定义为抽象类。
(2)抽象类的特点
A:抽象类和抽象方法必须用关键字abstract修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
C:抽象类不能实例化
D:抽象类的子类
a:是一个抽象类。
b:是一个具体类。这个类必须重写抽象类中的所有抽象方法。
(3)抽象类的成员特点:
A:成员变量
有变量,有常量
B:构造方法
有构造方法
C:成员方法
有抽象,有非抽象
(4)抽象类的练习
A:猫狗案例练习
B:老师案例练习
C:学生案例练习
D:员工案例练习
(5)抽象类的几个小问题
A:抽象类有构造方法,不能实例化,那么构造方法有什么用?
用于子类访问父类数据的初始化
B:一个类如果没有抽象方法,却定义为了抽象类,有什么用?
为了不让创建对象
C:abstract不能和哪些关键字共存
a:final 冲突
b:private 冲突
c:static 无意义
AbstractDemo.java
/* 抽象类的概述: 动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的。 我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类。 抽象类的特点: A:抽象类和抽象方法必须用abstract关键字修饰 B:抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类 C:抽象类不能实例化 因为它不是具体的。 抽象类有构造方法,但是不能实例化?构造方法的作用是什么呢? 用于子类访问父类数据的初始化 D:抽象的子类 a:如果不想重写抽象方法,该子类是一个抽象类。 b:重写所有的抽象方法,这个时候子类是一个具体的类。 抽象类的实例化其实是靠具体的子类实现的。是多态的方式。 Animal a = new Cat(); */ //abstract class Animal //抽象类的声明格式 abstract class Animal { //抽象方法 //public abstract void eat(){} //空方法体,这个会报错。抽象方法不能有主体 public abstract void eat(); public Animal(){} } //子类是抽象类 abstract class Dog extends Animal {} //子类是具体类,重写抽象方法 class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } } class AbstractDemo { public static void main(String[] args) { //创建对象 //Animal是抽象的; 无法实例化 //Animal a = new Animal(); //通过多态的方式 Animal a = new Cat(); a.eat(); } }
AbstractDemo2.java
/* 抽象类的成员特点: 成员变量:既可以是变量,也可以是常量。 构造方法:有。 用于子类访问父类数据的初始化。 成员方法:既可以是抽象的,也可以是非抽象的。 抽象类的成员方法特性: A:抽象方法 强制要求子类做的事情。 B:非抽象方法 子类继承的事情,提高代码复用性。 */ abstract class Animal { public int num = 10; public final int num2 = 20; public Animal() {} public Animal(String name,int age){} public abstract void show(); public void method() { System.out.println("method"); } } class Dog extends Animal { public void show() { System.out.println("show Dog"); } } class AbstractDemo2 { public static void main(String[] args) { //创建对象 Animal a = new Dog(); a.num = 100; System.out.println(a.num); //a.num2 = 200; System.out.println(a.num2); System.out.println("--------------"); a.show(); a.method(); } }
AbstractDemo3.java
/* 一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义? A:可以。 B:不让创建对象。 abstract不能和哪些关键字共存? private 冲突 final 冲突 static 无意义 */ abstract class Fu { //public abstract void show(); //非法的修饰符组合: abstract和private //private abstract void show(); //非法的修饰符组合 //final abstract void show(); //非法的修饰符组合 static abstract void show(); public static void method() { System.out.println("method"); } } class Zi extends Fu { public void show() {} } class AbstractDemo3 { public static void main(String[] args) { Fu.method(); } }
AbstractTest.java
/* 猫狗案例 具体事物:猫,狗 共性:姓名,年龄,吃饭 分析:从具体到抽象 猫: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(猫吃鱼) 狗: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(狗吃肉) 因为有共性的内容,所以就提取了一个父类。动物。 但是又由于吃饭的内容不一样,所以吃饭的方法是抽象的, 而方法是抽象的类,类就必须定义为抽象类。 抽象动物类: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(); 实现:从抽象到具体 动物类: 成员变量:姓名,年龄 构造方法:无参,带参 成员方法:吃饭(); 狗类: 继承自动物类 重写吃饭(); 猫类: 继承自动物类 重写吃饭(); */ //定义抽象的动物类 abstract class Animal { //姓名 private String name; //年龄 private int age; public Animal() {} public Animal(String name,int age) { this.name = name; this.age = age; } 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; } //定义一个抽象方法 public abstract void eat(); } //定义具体的狗类 class Dog extends Animal { public Dog() {} public Dog(String name,int age) { super(name,age); } public void eat() { System.out.println("狗吃肉"); } } //定义具体的猫类 class Cat extends Animal { public Cat() {} public Cat(String name,int age) { super(name,age); } public void eat() { System.out.println("猫吃鱼"); } } //测试类 class AbstractTest { public static void main(String[] args) { //测试狗类 //具体类用法 //方式1: Dog d = new Dog(); d.setName("旺财"); d.setAge(3); System.out.println(d.getName()+"---"+d.getAge()); d.eat(); //方式2: Dog d2 = new Dog("旺财",3); System.out.println(d2.getName()+"---"+d2.getAge()); d2.eat(); System.out.println("---------------------------"); Animal a = new Dog(); a.setName("旺财"); a.setAge(3); System.out.println(a.getName()+"---"+a.getAge()); a.eat(); Animal a2 = new Dog("旺财",3); System.out.println(a2.getName()+"---"+a2.getAge()); a2.eat(); //练习:测试猫类 } }
AbstractTest2.java
/* 老师案例 具体事物:基础班老师,就业班老师 共性:姓名,年龄,讲课。 分析: 基础班老师 姓名,年龄 讲课。 就业班老师 姓名,年龄 讲课。 实现: 老师类 基础班老师 就业班老师 */ //定义抽象的老师类 abstract class Teacher { //姓名 private String name; //年龄 private int age; public Teacher() {} public Teacher(String name,int age) { this.name = name; this.age = age; } 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; } //抽象方法 public abstract void teach(); } //基础班老师类 class BasicTeacher extends Teacher { public BasicTeacher(){} public BasicTeacher(String name,int age) { super(name,age); } public void teach() { System.out.println("基础班老师讲解JavaSE"); } } //就业班老师类 class WorkTeacher extends Teacher { public WorkTeacher(){} public WorkTeacher(String name,int age) { super(name,age); } public void teach() { System.out.println("就业班老师讲解JavaEE"); } } class AbstractTest2 { public static void main(String[] args) { //具体的类测试,自己玩 //测试(多态) //基础班老师 Teacher t = new BasicTeacher(); t.setName("刘意"); t.setAge(30); System.out.println(t.getName()+"---"+t.getAge()); t.teach(); System.out.println("--------------"); t = new BasicTeacher("刘意",30); System.out.println(t.getName()+"---"+t.getAge()); t.teach(); System.out.println("--------------"); //就业班老师 t = new WorkTeacher(); t.setName("林青霞"); t.setAge(27); System.out.println(t.getName()+"---"+t.getAge()); t.teach(); System.out.println("--------------"); t = new WorkTeacher("林青霞",27); System.out.println(t.getName()+"---"+t.getAge()); t.teach(); } }
AbstractTest3.java
/* 学生案例 具体事务:基础班学员,就业班学员 共性:姓名,年龄,班级,学习,吃饭 分析: 基础班学员 成员变量:姓名,年龄,班级 成员方法:学习,吃饭 就业班学员 成员变量:姓名,年龄,班级 成员方法:学习,吃饭 得到一个学员类。 成员变量:姓名,年龄,班级 成员方法:学习,吃饭 实现: 学员类 基础班学员 就业班学员 */ //定义抽象学员类 abstract class Student { //姓名 private String name; //年龄 private int age; //班级 private String grand; public Student() {} public Student(String name,int age,String grand) { this.name = name; this.age = age; this.grand = grand; } 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; } public String getGrand() { return grand; } public void setGrand(String grand) { this.grand = grand; } //学习 public abstract void study(); //吃饭 public void eat() { System.out.println("学习累了,就该吃饭"); } } //具体基础班学员类 class BasicStudent extends Student { public BasicStudent() {} public BasicStudent(String name,int age,String grand) { super(name,age,grand); } public void study() { System.out.println("基础班学员学习的是JavaSE"); } } //具体就业班学员类 class WorkStudent extends Student { public WorkStudent() {} public WorkStudent(String name,int age,String grand) { super(name,age,grand); } public void study() { System.out.println("就业班学员学习的是JavaEE"); } } class AbstractTest3 { public static void main(String[] args) { //我仅仅测试基础班学员 //按照多态的方式测试 Student s = new BasicStudent(); s.setName("林青霞"); s.setAge(27); s.setGrand("1111"); System.out.println(s.getName()+"---"+s.getAge()+"---"+s.getGrand()); s.study(); s.eat(); System.out.println("--------------"); s = new BasicStudent("武鑫",48,"1111"); System.out.println(s.getName()+"---"+s.getAge()+"---"+s.getGrand()); s.study(); s.eat(); //就业班测试留给自己玩 } }
AbstractTest4.java
/* 假如我们在开发一个系统时需要对员工类进行设计,员工包含3个属性:姓名、工号以及工资。 经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。 请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。 分析: 普通员工类 成员变量:姓名、工号以及工资。 成员方法:工作 经理类: 成员变量:姓名、工号以及工资,奖金属性 成员方法:工作 实现: 员工类: 普通员工类: 经理类: */ //定义员工类 abstract class Employee { //姓名、工号以及工资 private String name; private String id; private int salary; public Employee() {} public Employee(String name,String id,int salary) { this.name = name; this.id = id; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } //工作 public abstract void work(); } //普通员工类 class Programmer extends Employee { public Programmer(){} public Programmer(String name,String id,int salary) { super(name,id,salary); } public void work() { System.out.println("按照需求写代码"); } } //经理类 class Manager extends Employee { //奖金 private int money; //bonus 奖金 public Manager(){} public Manager(String name,String id,int salary,int money) { super(name,id,salary); this.money = money; } public void work() { System.out.println("跟客户谈需求"); } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } } class AbstractTest4 { public static void main(String[] args) { //测试普通员工 Employee emp = new Programmer(); emp.setName("林青霞"); emp.setId("czbk001"); emp.setSalary(18000); System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary()); emp.work(); System.out.println("-------------"); emp = new Programmer("林青霞","czbk001",18000); System.out.println(emp.getName()+"---"+emp.getId()+"---"+emp.getSalary()); emp.work(); System.out.println("-------------"); /* emp = new Manager(); emp.setName("刘意"); emp.setId("czbk002"); emp.setSalary(8000); emp.setMoney(2000); */ //由于子类有特有的内容,所以我们用子类来测试 Manager m = new Manager(); m.setName("刘意"); m.setId("czbk002"); m.setSalary(8000); m.setMoney(2000); System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney()); m.work(); System.out.println("-------------"); //通过构造方法赋值 m = new Manager("刘意","czbk002",8000,2000); System.out.println(m.getName()+"---"+m.getId()+"---"+m.getSalary()+"---"+m.getMoney()); m.work(); } }
多态的成员访问特点及转型的理解
多态的问题理解: class 孔子爹 { public int age = 40; public void teach() { System.out.println("讲解JavaSE"); } } class 孔子 extends 孔子爹 { public int age = 20; public void teach() { System.out.println("讲解论语"); } public void playGame() { System.out.println("英雄联盟"); } } //Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了 //但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢? //然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹 //向上转型 孔子爹 k爹 = new 孔子(); //到人家那里去了 System.out.println(k爹.age); //40 k爹.teach(); //讲解论语 //k爹.playGame(); //这是儿子才能做的 //讲完了,下班回家了 //脱下爹的装备,换上自己的装备 //向下转型 孔子 k = (孔子) k爹; System.out.println(k.age); //20 k.teach(); //讲解论语 k.playGame(); //英雄联盟
多态继承中的内存图解
多态中的对象变化内存图解
4:接口(掌握)
(1)回顾猫狗案例,它们仅仅提供一些基本功能。
比如:猫钻火圈,狗跳高等功能,不是动物本身就具备的,
是在后面的培养中训练出来的,这种额外的功能,java提供了接口表示。
(2)接口的特点:
A:接口用关键字interface修饰
interface 接口名 {}
B:类实现接口用implements修饰
class 类名 implements 接口名 {}
C:接口不能实例化
D:接口的实现类
a:是一个抽象类。
b:是一个具体类,这个类必须重写接口中的所有抽象方法。
(3)接口的成员特点:
A:成员变量
只能是常量
默认修饰符:public static final
B:构造方法
没有构造方法
C:成员方法
只能是抽象的
默认修饰符:public abstract
(4)类与类,类与接口,接口与接口
A:类与类
继承关系,只能单继承,可以多层继承
B:类与接口
实现关系,可以单实现,也可以多实现。
还可以在继承一个类的同时,实现多个接口
C:接口与接口
继承关系,可以单继承,也可以多继承
(5)抽象类和接口的区别(自己补齐)?
A:成员区别
抽象类:
接口:
B:关系区别:
类与类:
类与接口:
接口与接口:
C:设计理念不同
抽象类:is a,抽象类中定义的是共性功能。
接口:like a,接口中定义的是扩展功能。
(6)练习:
A:猫狗案例,加入跳高功能
B:老师和学生案例,加入抽烟功能0
InterfaceDemo.java
/* 接口的特点: A:接口用关键字interface表示 interface 接口名 {} B:类实现接口用implements表示 class 类名 implements 接口名 {} C:接口不能实例化 那么,接口如何实例化呢? 按照多态的方式来实例化。 D:接口的子类 a:可以是抽象类。但是意义不大。 b:可以是具体类。要重写接口中的所有抽象方法。(推荐方案) 由此可见: A:具体类多态(几乎没有) B:抽象类多态(常用) C:接口多态(最常用) */ //定义动物培训接口 interface AnimalTrain { public abstract void jump(); } //抽象类实现接口 abstract class Dog implements AnimalTrain { } //具体类实现接口 class Cat implements AnimalTrain { public void jump() { System.out.println("猫可以跳高了"); } } class InterfaceDemo { public static void main(String[] args) { //AnimalTrain是抽象的; 无法实例化 //AnimalTrain at = new AnimalTrain(); //at.jump(); AnimalTrain at = new Cat(); at.jump(); } }
InterfaceDemo2.java
/* 接口成员特点 成员变量;只能是常量,并且是静态的。 默认修饰符:public static final 建议:自己手动给出。 构造方法:接口没有构造方法。 成员方法:只能是抽象方法。 默认修饰符:public abstract 建议:自己手动给出。 所有的类都默认继承自一个类:Object。 类 Object 是类层次结构的根类。每个类都使用 Object 作为超类。 */ interface Inter { public int num = 10; public final int num2 = 20; public static final int num3 = 30; //错误: 需要<标识符> //public Inter() {} //接口方法不能带有主体 //public void show() {} //abstract void show(); //默认public public void show(); //默认abstract } //接口名+Impl这种格式是接口的实现类格式 /* class InterImpl implements Inter { public InterImpl() { super(); } } */ class Father { public int num = 100; } class InterImpl extends Father implements Inter { public InterImpl() { super(); } public void show() {} } //测试类 class InterfaceDemo2 { public static void main(String[] args) { //创建对象 Inter i = new InterImpl(); System.out.println(i.num); System.out.println(i.num2); //i.num = 100; //i.num2 = 200; //System.out.println(i.num); //无法为最终变量num分配值 //System.out.println(i.num2);//无法为最终变量num2分配值 System.out.println(Inter.num); System.out.println(Inter.num2); System.out.println("--------------"); InterImpl ii = new InterImpl(); //System.out.println(ii.num); //InterfaceDemo2.java:68: 错误: 对num的引用不明确, Father中的变量 num和Inter中的变量 num都匹配 } }
InterfaceDemo3.java
/* 类与类: 继承关系,只能单继承,可以多层继承。 类与接口: 实现关系,可以单实现,也可以多实现。 并且还可以在继承一个类的同时实现多个接口。 接口与接口: 继承关系,可以单继承,也可以多继承。 */ interface Father { public abstract void show(); } interface Mother { public abstract void show2(); } interface Sister extends Father,Mother { } //class Son implements Father,Mother //多实现 class Son extends Object implements Father,Mother { public void show() { System.out.println("show son"); } public void show2() { System.out.println("show2 son"); } } class InterfaceDemo3 { public static void main(String[] args) { //创建对象 Father f = new Son(); f.show(); //f.show2(); //报错 Mother m = new Son(); //m.show(); //报错 m.show2(); } }
InterfaceTest.java
/* 猫狗案例,加入跳高的额外功能 分析:从具体到抽象 猫: 姓名,年龄 吃饭,睡觉 狗: 姓名,年龄 吃饭,睡觉 由于有共性功能,所以,我们抽取出一个父类: 动物: 姓名,年龄 吃饭(); 睡觉(){} 猫:继承自动物 狗:继承自动物 跳高的额外功能是一个新的扩展功能,所以我们要定义一个接口 接口: 跳高 部分猫:实现跳高 部分狗:实现跳高 实现; 从抽象到具体 使用: 使用具体类 */ //定义跳高接口 interface Jumpping { //跳高功能 public abstract void jump(); } //定义抽象类 abstract class Animal { //姓名 private String name; //年龄 private int age; public Animal() {} public Animal(String name,int age) { this.name = name; this.age = age; } 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; } //吃饭(); public abstract void eat(); //睡觉(){} public void sleep() { System.out.println("睡觉觉了"); } } //具体猫类 class Cat extends Animal { public Cat(){} public Cat(String name,int age) { super(name,age); } public void eat() { System.out.println("猫吃鱼"); } } //具体狗类 class Dog extends Animal { public Dog(){} public Dog(String name,int age) { super(name,age); } public void eat() { System.out.println("狗吃肉"); } } //有跳高功能的猫 class JumpCat extends Cat implements Jumpping { public JumpCat() {} public JumpCat(String name,int age) { super(name,age); } public void jump() { System.out.println("跳高猫"); } } //有跳高功能的狗 class JumpDog extends Dog implements Jumpping { public JumpDog() {} public JumpDog(String name,int age) { super(name,age); } public void jump() { System.out.println("跳高狗"); } } class InterfaceTest { public static void main(String[] args) { //定义跳高猫并测试 JumpCat jc = new JumpCat(); jc.setName("哆啦A梦"); jc.setAge(3); System.out.println(jc.getName()+"---"+jc.getAge()); jc.eat(); jc.sleep(); jc.jump(); System.out.println("-----------------"); JumpCat jc2 = new JumpCat("加菲猫",2); System.out.println(jc2.getName()+"---"+jc2.getAge()); jc2.eat(); jc2.sleep(); jc2.jump(); //定义跳高狗并进行测试的事情自己完成。 } }
InterfaceTest2.java
/* 老师和学生案例,加入抽烟的额外功能 分析:从具体到抽象 老师:姓名,年龄,吃饭,睡觉 学生:姓名,年龄,吃饭,睡觉 由于有共性功能,我们提取出一个父类,人类。 人类: 姓名,年龄 吃饭(); 睡觉(){} 抽烟的额外功能不是人或者老师,或者学生一开始就应该具备的,所以,我们把它定义为接口 抽烟接口。 部分老师抽烟:实现抽烟接口 部分学生抽烟:实现抽烟接口 实现:从抽象到具体 使用:具体 */ //定义抽烟接口 interface Smoking { //抽烟的抽象方法 public abstract void smoke(); } //定义抽象人类 abstract class Person { //姓名 private String name; //年龄 private int age; public Person() {} public Person(String name,int age) { this.name = name; this.age = age; } 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; } //吃饭(); public abstract void eat(); //睡觉(){} public void sleep() { System.out.println("睡觉觉了"); } } //具体老师类 class Teacher extends Person { public Teacher() {} public Teacher(String name,int age) { super(name,age); } public void eat() { System.out.println("吃大白菜"); } } //具体学生类 class Student extends Person { public Student() {} public Student(String name,int age) { super(name,age); } public void eat() { System.out.println("吃红烧肉"); } } //抽烟的老师 class SmokingTeacher extends Teacher implements Smoking { public SmokingTeacher() {} public SmokingTeacher(String name,int age) { super(name,age); } public void smoke() { System.out.println("抽烟的老师"); } } //抽烟的学生 class SmokingStudent extends Student implements Smoking { public SmokingStudent() {} public SmokingStudent(String name,int age) { super(name,age); } public void smoke() { System.out.println("抽烟的学生"); } } class InterfaceTest2 { public static void main(String[] args) { //测试学生 SmokingStudent ss = new SmokingStudent(); ss.setName("林青霞"); ss.setAge(27); System.out.println(ss.getName()+"---"+ss.getAge()); ss.eat(); ss.sleep(); ss.smoke(); System.out.println("-------------------"); SmokingStudent ss2 = new SmokingStudent("刘意",30); System.out.println(ss2.getName()+"---"+ss2.getAge()); ss2.eat(); ss2.sleep(); ss2.smoke(); //测试老师留给自己练习 } }
抽象类和接口的区别
抽象类和接口的区别:
A:成员区别
抽象类:
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象
接口:
成员变量:只可以常量
成员方法:只可以抽象
B:关系区别
类与类
继承,单继承
类与接口
实现,单实现,多实现
接口与接口
继承,单继承,多继承
C:设计理念区别
抽象类 被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能。
接口 被实现体现的是:”like a”的关系。接口中定义的是该继承体系的扩展功能。