你所谓的迷茫,不过是清醒的看着自己沉沦
- 多态
- 抽象类
- 接口
一、多态
1、静态绑定与动态绑定
1.1、静态绑定
在编译期间完成,可以提交代码的执行效率,静态绑定的方法包括:
- 静态方法
final
修饰的方法- 构造器
private
修饰方法- 用关键字
super
调用的方法
1.2、动态绑定(动态联编)
在执行期间判断所引用对象的实际类型,根据其类型调用其相应的方法。可以让编程更灵活,凡是降低了代码的执行效率。
重写是动态绑定的最佳实例,因为父类和子类都有相同的方法,编译时不确定要调用哪个,只有在执行是会确定。
2、多态
多态是同一个行为具有多个不同表现形式或形态的能力。
2.1、多态的三要素
- 继承
- 重写
- 父类引用指向子类对象
必须同时满足这三个条件才能形成多态。
2.2、例子
public class Animal {
public void shout(){
System.out.println("动物叫");
}
}
public class Dog extends Animal{
@Override
public void shout() {
System.out.println("汪汪汪!!!");
}
}
public class Cat extends Animal {
@Override
public void shout() {
System.out.println("喵喵喵...");
}
}
public class Test {
public static void main(String[] args) {
animalCry(new Animal());
animalCry(new Cat());
animalCry(new Dog());
}
static void animalCry(Animal animal){
animal.shout();
}
}
运行结果 |
---|
动物叫 喵喵喵… 汪汪汪!!! |
2.3、多态只能调用子类重写的父类的方法
多态只能调用子类重写的父类的方法,不能调用子类新增的方法
public class Dog extends Animal{
@Override
public void shout() {
System.out.println("汪汪汪!!!");
}
public void function(){
System.out.println("狗会看门");
}
}
public class Cat extends Animal {
@Override
public void shout() {
System.out.println("喵喵喵...");
}
public void function(){
System.out.println("猫会爬树");
}
}
public class Test {
public static void main(String[] args) {
animalCry(new Animal());
animalCry(new Cat());
animalCry(new Dog());
}
static void animalCry(Animal animal){
animal.shout();
animal.function();
}
}
运行结果 |
---|
编译出错,找不到方法
2.4、类型转化
多态现象中,子类可以自动转为父类类型,父类不能自动转换为子类类型
如果要把子类转换为父类,需要强制转换
public class Test {
public static void main(String[] args) {
Animal animal = new Cat(); // 子类自动转换为父类(父类引用指向子类对象)
Cat cat = (Cat) new Animal(); // 强制父类转换为子类(有异常)
}
static void animalCry(Animal animal){
animal.shout();
}
}
运行结果 |
---|
父类强制转换为子类,虽然编译的时候不报错,但是运行的时候会有异常。
也就是说在继承链上的可以互相转换,可以编译通过,但是有可能发生异常。
还有一种情况,把不是继承链上的强制转换
public class Test {
public static void main(String[] args) {
Animal animal = new Cat(); // 子类自动转换为父类(父类引用指向子类对象)
Cat cat = (Cat) new Animal(); // 强制父类转换为子类(有异常)
cat = (Cat)new String();
}
static void animalCry(Animal animal){
animal.shout();
}
}
运行结果 |
---|
非继承链上的强制转换则编译不通过。
2.5instanceof运算符
可以通过instanceof
来判断一个对象是否是一个类的实例或者其子类的实例,只能用在同一条继承链上,结果为boolean类型
public class Test {
public static void main(String[] args) {
System.out.println(new Animal() instanceof Cat); // false
System.out.println(new Cat() instanceof Animal); // true
}
}
运行结果 |
---|
false true |
可以通过这个运算符判断是否可以进行类型转换
只可以用在同一条的继承链上,非继承链上的则无法编译通过
二、抽象类
有时候一个父类的方法永远满足不了子类的需求,那么可以把父类设置为抽象类。
被abstract
修饰的类为抽象类,被abstract
修饰的方法叫抽象方法
- 抽象类
- 抽象类不能实例化,只能被用来继承
- 抽象方法
- 没有具体方法,用来重写
抽象类除了有抽象方法外,还有成员属性以及普通方法,即使抽象类没有抽象方法也可以被声明为抽象类,防止被实例化。
1、语法格式
1.1、抽象类语法格式
[权限修饰符] abstract class 类名{
}
1.2、抽象方法语法格式
[权限修饰符] abstract 返回值类型 方法名([参数]);
2、例子
public abstract class A {
void a1(){
System.out.println("抽象类内的普通方法");
}
abstract void a2(); // 抽象类的抽象方法
}
public class B extends A {
@Override
void a2() {
System.out.println("重写抽象类内的抽象方法");
}
}
public class Test{
public static void main(String[] args) {
A a = new B();
a.a1();
a.a2();
}
}
运行结果 |
---|
抽象类内的普通方法 重写抽象类内的抽象方法 |
三、接口
接口就是纯的抽象类,没有了普通方法和成员变量
接口内的所有方法都是抽象方法
接口不在使用class
关键字,而是使用interface
关键字定义接口
接口不在使用extends
关键字继承,而是使用imlements
关键字实现
一个类可以实现多个接口
1、语法格式
1.1、接口的语法格式
[权限修饰符] interface 接口名{
}
1.2、接口内方法的语法格式
返回值类型 方法名([参数]);
2、例子
public interface Person {
void sleep();
void eating();
}
public class Student implements Person {
@Override
public void sleep() {
System.out.println("学生要睡觉");
}
@Override
public void eating() {
System.out.println("饿了要吃饭");
}
}
public class Test {
public static void main(String[] args) {
Person p = new Student();
p.eating();
p.sleep();
}
}
运行结果 |
---|
饿了要吃饭 学生要睡觉 |
接口内定义的方法必须实现
3、接口的特征
-
接口中声明的属性默认为public static fina 的也只能时pub static final的
public interface Person { int a = 0; void sleep(); void eating(); }
public class Test { public static void main(String[] args) { Person p = new Student(); p.eating(); p.sleep(); System.out.println(Person.a); } }
运行结果 饿了要吃饭
学生要睡觉
0 -
接口中只能定义抽象方法,而这些方法默认也是public的,也只能时public的
-
接口可以继承其它的接口,并添加新的属性和抽象方法
-
接口不能实现另一个接口,凡是可以继承多个其它的接口
public interface A { void a1(); void a2(); }
public interface B { void b1(); void b2(); }
public interface Person extends A,B{ int a = 0; void sleep(); void eating(); }
public class Student implements Person { @Override public void sleep() { System.out.println("学生要睡觉"); } @Override public void eating() { System.out.println("饿了要吃饭"); } @Override public void a1() { System.out.println("a1"); } @Override public void a2() { System.out.println("a2"); } @Override public void b1() { System.out.println("b1"); } @Override public void b2() { System.out.println("b2"); } }
public class Test { public static void main(String[] args) { Person p = new Student(); p.eating(); p.sleep(); p.a1(); p.a2(); p.b1(); p.b2(); } }
运行结果 饿了要吃饭
学生要睡觉
a1
a2
b1
b2