Java语言基础 10:final 关键字、多态、多态的好处和弊端、对象间的转型问题(向下转型和向上转型)、多态中内存结构图解、多态的代码练习、
1、final 关键字
(1)final 关键字是“最终的意思”,可以修饰类、修饰成员变量、修饰成员方法。
final 修饰类:最终类,该类不能被继承。
final 修饰成员方法:最终成员方法,该成员方法不能被子类重写。
final 修饰成员变量:该成员变量不能被重新赋值。它就变成了常量,只能被赋值一次。
A:字面值常量 String str="abc" ; B:自定义常量 final int num=100 ;
(2)final 关键字修饰局部变量。
final 修饰基本数据类型的变量,基本类型的值不能改变。
final 修饰引用数据类型的变量,引用类型的地址值不能改变,但是,该对象 堆内存的值 是可以改变的。
(3)final 关键字修饰变量的初始化时机。
1)被final 修饰的变量只能被赋值一次。
2)在构造方法完毕前被初始化(这是针对非静态的常量)。
2、多态的概念
(1)多态:同一个对象在不同时刻体现出来的不同状态。
(2)多态的前提:
A:要有继承关系。
其实没有也是可以的,但是没有这个就没有意义了。
C:要有父类引用指向子类对象。父类名 f = new 子类名();
(3)多态中的成员访问特点
A:成员变量:编译看左边,运行看左边。
B:构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
C:成员方法:编译看左边,运行看右边。(由于成员方法存在重写,所以它运行看右边)
D:静态方法:编译看左边,运行看左边。(静态和类相关,算不上重写,所以访问的还是父类的)
3、多态的好处和弊端
(1)提高了代码的维护性(继承来保证)。
(2)提高了代码的扩展性。
多态的弊端:只能使用父类的功能,不能使用子类的特有功能。
如果就想使用,该怎么办呢?解决办法如下:
A:创建子类对象去调用方法即可。可以,但是不合理,太占用内存。
B:把父类的引用强制转换为子类的引用(向下转型)。
对象间的转型问题:
A:向上转型:子类对象赋值给父类引用。Fu f = new Zi ( ) ;
B:向下转型:父类引用赋值给子类对象。Zi z = (Zi)f ; 前提:要求该f 必须能够转换为Zi 的。
4、多态继承中的内存图解
5、多态中的对象变化内存图解
ClassCastException:类的转换异常,通常在类的向下转型中出现!
6、多态练习
/*
多态练习:猫狗案例
*/
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; //运行时错误
}
}
/*
不同地方饮食文化不同的案例
*/
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();
}
}
/*
看程序写结果:先判断有没有问题,如果没有,写出结果
多态的成员访问特点:
方法:编译看左边,运行看右边。
继承的时候:
子类中有和父类中一样的方法,叫重写。
子类中没有父亲中出现过的方法,方法就被继承过来了。
*/
// 爱你
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();
}
}
7、抽象类:abstract class Animal { }
(1)一个没有方法体的方法 应该定义为 抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
抽象类中可以没有抽象方法。
空方法体:写了空的大括号 { } public abstract void eat() { } //报错
没有方法体:不写大括号 { } public abstract void eat() ;
(2)抽象类的特点:
关键字 修饰。
2)抽象类中不一定有抽象方法,但是有抽象方法的类 必须定义为抽象类。
另:抽象类的实例化其实是靠具体的子类实现的,是多态的方式!
4)抽象类有构造方法,但是不能实例化,构造方法用于子类访问父类数据的初始化。
(3)抽象类的子类:
1)如果不想重写抽象父类的抽象方法,这时,抽象类的子类是一个抽象类。
2)重写了抽象父类的所有抽象方法,这时,子类是一个具体的类。
(4)抽象类的成员特点:
1)成员变量:可以是变量,也可以是常量。
2)构造方法:有,用于子类访问父类数据的初始化。
3)成员方法:可以是抽象方法,也可以是非抽象方法。
抽象类的成员方法特性:
1)抽象方法:强制要求子类要做的事情。
2)非抽象方法:子类继承的事情,提高代码复用性。
8、抽象类和多态的举例
//定义抽象的动物类
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();
//练习:测试猫类
}
}
/*
学生案例
具体事务:基础班学员,就业班学员
共性:姓名,年龄,班级,学习,吃饭
分析:
基础班学员
成员变量:姓名,年龄,班级
成员方法:学习,吃饭
就业班学员
成员变量:姓名,年龄,班级
成员方法:学习,吃饭
得到一个学员类。
成员变量:姓名,年龄,班级
成员方法:学习,吃饭
实现:
学员类
基础班学员
就业班学员
*/
//定义抽象学员类
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();
//就业班测试留给自己玩
}
}
9、抽象类的小问题:
(1)一个类如果没有抽象方法,可以被定义为抽象类吗?
答:可以。这样做的意义是:不让去创建对象,只能使用它的子类去访问。
(2)abstract 关键字不能和哪些关键字共存?
1)private :私有的是不能被继承的,更别提被子类重写了,而抽象是要求必须被子类重写的,所以出现了冲突。
2)final :final 是最终的,不能被子类重写,而抽象是要求必须被子类重写的,所以出现了冲突。
3)static :无意义:abstract 方法是没有方法体的,而static 方法是可以直接被类名调用的,通过类名去调用一个没有方法体的方法意义何在,所以无意义。