多态
概述:某一个事物,在不同时刻表现出来的不同状态。
我们来举例说明:
- 猫是猫,狗是狗,猫和狗都是动物。
- 水在不同环境下的状态不同(液体,固体,气态)
那么使用多态的前提是什么呢?
- 要有继承关系。
- 要有方法重写。
//其实没有也是可以的,但是如果没有这个就没有意义。
Animal c = new Cat();
c.show();
Animal d = new Dog();
d.show();
- 要有父类引用指向子类对象
父 f = new 子();
下面我们用代码来体现
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();
}
}
下面我们用代码来体现
- 成员变量
- 编译看左边,运行看左边
- 构造方法
- 子类的构造都会默认访问父类构造
- 成员方法
- 编译看左边,运行看右边
- 静态方法
- 编译看左边,运行看左边
- 所以静态方法不能算方法的重写
学了这么多我们应该了解下多态的好处:
- 提高了代码的维护性(继承保证)
- 提高了代码的扩展性(由多态保证)
多态有好处,当然也有弊端了不能使用子类的特有功能。 那么我们如何才能访问子类的特有功能呢?多态中的转型 怎么用呢?
- 创建子类对象调用方法即可。(可以,但是很多时候不合理。而且,太占内存了)
- 把父类的引用强制转换为子类的引用。(向下转型)
关于对象间的转型问题:
- 向上转型
- 从子到父
- 父类引用指向子类对象
- 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 DuoTaiDemo3 {
public static void main(String[] args) {
//测试
Fu f = new Zi();
f.show();
f.method();
//多态的弊端不能使用子类的特有功能。
}
}
//所以输出结果是:show zi
//关于向下转型,我们能够把子类的对象赋值给父类,
//所以我们也可以把父类的引用赋值给子类的引用
//怎么使用呢,只要在上面例子的基础上稍做修改
Son z = (Son) f;
z.show();
z.method();
//输出结果就变了:show zi //method zi
内部类
- 概述:把类定义在其他类的内部,这个类就被称为内部类。
举例:在类A中定义了一个类B,类B就是内部类。
-
内部的访问特点:
- 内部类可以直接访问外部类的成员,包括私有。
- 外部类要访问内部类的成员,必须创建对象。
-
内部类位置
- 成员位置:在成员位置定义的类,被称为成员内部类。
- 局部位置:在局部位置定义的类,被称为局部内部类。
class Outer {
private int num = 10;
//成员位置,成员内部类
class Inner {
}
public void method() {
//局部位置,局部内部类
class Inner { }
}
}
成员内部类
我们了解了成员内部类,那么如何直接访问内部类的成员。外部类名.内部类名 对象名 = 外部类对象.内部类对象;
class Outer {
private int num = 10;
class Inner {
public void show() {
System.out.println(num);
}
}
}
class InnerClassDemo {
public static void main(String[] args) {
//需求:我要访问Inner类的show()方法
//Inner i = new Inner();
//i.show(); 这样访问不到
//格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
上面学习了成员内部类的使用,但是一般来说,在实际开发中是不会这样使用的。因为一般内部类就是不让外界直接访问的。
- 成员内部的常见修饰符
- private 为了保证数据的安全性
- static 为了让数据访问更方便
- 被静态修饰的成员内部类只能访问外部类的静态成员
- 内部类被静态修饰后的方法
- 静态方法
- 非静态方法
class Outer { private static int num = 100; //内部类用静态修饰是因为内部类可以看出是外部类的成员 public static class Inner { public void show() { System.out.println(num); } public static void show2() { System.out.println(num); } }}class InnerClassDemo { public static void main(String[] args) { //成员内部类被静态修饰后的访问方式是: Outer.Inner.show2(); }}
局部内部类
- 可以直接访问外部类的成员
- 在局部位置,可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
class Outer {
private int num = 10;
public void method() {
//int num2 = 20;
final int num2 = 20;
class Inner {
public void show() {
System.out.println(num);
//从内部类中访问本地变量num2; 需要被声明为最终类型
System.out.println(num2);//20
}
}
//System.out.println(num2);
Inner i = new Inner(); i.show();
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //结果是:10 20
}
}
局部内部类访问局部变量的注意事项:
- 局部内部类访问局部变量必须用final修饰
- 原因:局部变量是随着方法的调用而调用,随着调用完毕而消失。而堆内存的内容并不会立即消失。所以,我们加final修饰。加入final修饰后,这个变量就成了常量。既然是常量。你消失了。在内存中存储的是数据20,所以,还是有数据在使用。
匿名内部类
- 匿名内部类就是内部类的简化写法。
- 前提:存在一个类或者接口
- 这里的类可以是具体类也可以是抽象类。 - 格式:
- new 类名或者接口名() {重写方法;} - 本质:
- 是一个继承了类或者实现了接口的子类匿名对象
interface Inter {
public abstract void show();
public abstract void show2();
}
class Outer {
public void method() {
//一个方法的时候 /*
new Inter() { public void show() { System.out.println("show"); }
}.show(); */
//二个方法的时候 /* new Inter() { public void show()
{ System.out.println("show"); }
public void show2() { System.out.println("show2"); } }.show(); new Inter() { public void show() { System.out.println("show"); } public void show2() { System.out.println("show2"); } }.show2(); */
//如果我是很多个方法,就很麻烦了
//那么,我们有没有改进的方案呢?
Inter i = new Inter() { //多态
public void show() { System.out.println("show"); }
public void show2() { System.out.println("show2");}
};
i.show();
i.show2();
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
//输出结果:show show2 }
}