多态,内部类,匿名内部类
多态
- 多态概述
多态是继封装、继承之后,面向对象的第三大特性。
生活中,比如跑的动作,小猫、小狗和大象,都有跑的动作,但是跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。
父类的引用指向子类对象。 - 定义
是指同一行为,具有多个不同的表现形式 - 多态前提
- 继承或者实现
- 方法的重写
- 父类引用指向子类对象
- 多态的体现格式:
父类类型 变量名 = new 子类对象;
变量名.方法名();
代码如下
Fu f = new Zi();//父类的引用指向子类对象
f.method();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。
//定义父类
public class Animal {
public void eat(){
System.out.println("吃");
}
}
//定义子类
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
//定义测试类
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Animal a1 = new Cat();
// 调用的是 Cat 的 eat
a1.eat();
// 多态形式,创建对象
Animal a2 = new Dog();
// 调用的是 Dog 的 eat
a2.eat();
}
}
- 多态的好处
实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展 性与便利。 - 引用类型转换-向上转型
多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。当父类引用指向一个子类对象时,便是向上转型. - 引用类型转换-向下转型
父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
//定义父类
public class Animal {
public void eat(){
System.out.println("吃");
}
}
//定义子类
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
//定义测试类
public class Test {
public static void main(String[] args) {
// 向上转型
Animal a = new Cat();
a.eat();// 调用的是 Cat 的 eat
// 向下转型
Cat c = (Cat)a;
c.catchMouse(); // 调用的是 Cat 的 catchMouse
}
}
- instanceof
instanceof关键字:判断变量是否属于某个类,返回值为true/false
//定义父类
public class Animal {
public void eat(){
System.out.println("吃");
}
}
//定义子类
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
}
//定义测试类
public class Test {
public static void main(String[] args) {
//向上转型
Animal a = new Cat();
a.eat();// 调用的是 Cat 的 eat
//向下转型
if(a instanceof Cat){
Cat c = (Cat)a;
c.catchMouse();// 调用的是 Cat 的 catchMouse
}else if(a instanceof Dog){
Dog d = (Dog)a;
d.watchHouse(); // 调用的是 Dog 的 watchHouse
}
}
}
- 在idea中使用Ctrl+O重写方法。
- 要多多研究Code和Refactor菜单
- instanceof 可以来判断是否可以强行转换类型
- instanceof判断一个对象是否是某种类型该对象声明类型和强转的类型有继承关系
- 在使用多态这个特性是,主要看对象是被什么样的类new出来的。
内部类
- 什么是内部类
- 将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类
- 什么是成员内部类
- 定义在类中方法外的类
- 定义格式
class 外部类{
class 内部类{
}
}
内部类使用场景
- 在描述事物时,若一个事物内部还包含其他事物,就可以使用内部类这种结构。比如,汽车类 Car 中包含发动机 类 Engine ,这时, Engine 就可以使用内部类来描述,定义在成员位置。
内部类访问特点
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
- 内部类可以声明为static的,但此时就不能再使用外层封装类的非static的成员变量;
- 非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员;
创建内部类对象格式:
外部类名.内部类名 对象名 = new 外部类型().new 内部类型();
代码演示:
public class Person {
private boolean live = true;
class Heart {
public void jump() {
// 直接访问外部类成员
if (live) {
System.out.println("心脏在跳动");
} else {
System.out.println("心脏不跳了");
}
}
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
}
public class InnerDemo {
public static void main(String[] args) {
// 创建外部类对象
Person p = new Person();
// 创建内部类对象
Heart heart = p.new Heart();
// 调用内部类方法
heart.jump();
// 调用外部类方法
p.setLive(false);
// 调用内部类方法
heart.jump();
}
}
内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名 和$符号 。 比如,Person$Heart.class。
匿名内部类
- 匿名内部类概述
匿名内部类是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作,
1. 定义子类
2. 重写接口中的方法
3. 创建子类对象
4. 调用重写后的方法
我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。 - 匿名内部类前提
匿名内部类必须继承一个父类或者实现一个父接口。
格式
new 父类名或者接口名(){
// 方法重写
@Override
public void method() {
// 执行语句
}
};
- 匿名内部类使用
//定义接口
public interface FlyAble{
void fly();
}
//创建测试类
public class InnerDemo {
public static void main(String[] args) {
/*
1.等号右边:是匿名内部类,定义并创建该接口的子类对象
2.等号左边:是多态赋值,接口类型引用指向子类对象
*/
FlyAble f = new FlyAble(){
public void fly() {
System.out.println("我飞了~~~");
}
};
//调用 fly方法,执行重写后的方法
f.fly();
}
}
笔记
- 内部类
- 有的类只给别的类用,因此可以写为内部类
- 内部类引用外部类的成员用外部类类名.this
- 静态内部类
1. 不能访问外部类的一切非静态变量
2. 静态内部类实例化
例子:new Outer.Iner();
- 局部内部类
* 在方法中定义内部类——局部内部类
- 局部匿名内部类
- 局部匿名内部类的方法