1. 多态
指的是一种事物在不同时刻,所表现出的不同状态
1.1 多态的前提:
a. 要有继承,没有继承,多态就无从谈起
b. 要有方法重写(当然不重写也可以 ,但是会失去意义)
c. 父类引用指向子类对象 — 父 f = new 子();
public class MyTest2 {
public static void main(String[] args) {
Cat cat = new Cat();
cat.eat();
//采用多态的形式来表示,父类引用指向子类对象
Animal an=new Cat();//父类引用指向子类对象,父 f = new 子();
//采用多态的形式,去调用eat()方法
an.eat(); // 猫吃鱼
/* Dog dog = new Dog();
Animal animal=new Dog();*/
}
}
class Animal {
public void eat(){
System.out.println("吃饭");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
class Dog extends Animal {
}
1.2 多态中的成员访问特点:
a. 多态的形式来访问成员变量,编译看左边,运行也看左边(用的都是父类的,跟子类没有关系)。
b. 多态的形式来访问构造方法,创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
c. 多态的形式来访问成员方法,编译看左边,运行看右边(用的都是父类的 跟子类没有关系)。
(左右以‘=’来分)编译看父类中有没有这个方法,有就不报错,实际调用时,会以子类重写过后为准;如果确实没有重写,那就以父类的为准。
d. 多态的形式来访问静态方法,编译看左边,运行看左边。(静态和类相关,算不上重写,所以,访问还是左边的)。
public class MyTest {
public static void main(String[] args) {
Fu fu = new Zi();
int n=fu.num;
System.out.println(n); //100 多态的形式来访问成员变量,编译看左边,运行也看左边。多态的形式访问成员变量,访问的都是父类的变量。
//多态的形式,来访问成员方法 编译看左边,运行看右边
fu.show();// zi show
fu.jing();// fu jing
Fu.jing();// fu jing 推荐使用这种方式调用静态方法 类名.方法名 而不是 对象名.方法名
Zi.jing();// zi jing
Zi zi = new Zi();
}
}
class Fu{
public Fu() {
System.out.println("父类 构造调用了");
}// 每一次new对象就会执行
int num=100;
public void show(){
System.out.println("fu show");
}
public static void jing(){
System.out.println("fu jing");
}
}
class Zi extends Fu{
int num=10;
public Zi() {
System.out.println("子类构造执行了");
}// 每一次new对象就会执行
@Override
public void show() {
System.out.println("zi show");
}
public static void jing() {
System.out.println("zi jing");
}
}
1.3 多态的好处:
1.提高代码复用性和维护性(靠继承保证)
2.提高代码的扩展性
方法形参的设计,用成父类型,那么就可以接收其他
1.4 多态的弊端:
不能直接调用子类特有的功能。(我们可以采用向下转型来调用子类特有的功能)
Fu fu=new Zi();
Zi zi=(Zi)fu;// 向下转型:把父类的引用强制转换为子类的引用
public class MyTest {
public static void main(String[] args) {
//多态的弊端:不能调用子类特有的功能
Fu fu = new Zi(); //向上转型:多态就是向上转型。
fu.show();
//多态,不能直接调用,子类特有的功能。
//fu.hehe(); 报错。
/*Zi zi = new Zi();
zi.show();
zi.hehe();*/
//我们可以采用向下转型,那调用子类特有的功能
System.out.println(fu.num); //200
Zi zi= (Zi) fu; //把父类引用,向下转型为子类型。
zi.hehe();
System.out.println(zi.num); //10
}
}
class Fu {
int num=200;
public void show() {
System.out.println("fu Show");
}
}
class Zi extends Fu {
int num=10;
@Override
public void show() {
System.out.println("zi Show");
}
public void hehe() {
System.out.println("子类特有的方法");
}
}
类型转换异常ClassCastException: org.westos.demo4.Cat cannot be cast to org.westos.demo4.Dog
// 例题:“爱你”
// B:看下面程序是否有问题,如果没有,说出结果
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
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();// 1.父类引用a指向子类对象B
a.show(); // 爱 调用A.class show()方法,调用show2()方法,而B重写了,所以打印“爱”
B b = new C();// 2.父类引用b指向子类对象C
b.show();// 你 调用B.class show()方法,而其中没有show但是他的父类A中有,所以调用调用A.class show()方法,调用show2()方法,而C重写了,所以打印“你”
}
}
2. 抽象类
2.1 概念和引出
abstract–抽象的
父类也不知道子类对某个共性功能的具体实现,所以没有必要给出具体方法实现
抽象类:抽取所有子类的共性功能,但是不给出共性功能的具体实现,而是交由子类根据自身特性,做以具体实现,抽象类和抽象方法必须用abstract关键字修饰
2.2 语法:
抽象类格式: abstract class 类名 {}
抽象方法格式: public abstract void eat();
public class MyTest {
public static void main(String[] args) {
//Animal animal = new Animal();
Cat cat = new Cat();
Dog dog = new Dog();
}
}
abstract class Animal {
//父类,他也不知道,子类对这个共性功能的具体实现,所以也没有必要给出共性功能的具体实现
//抽象类,抽取所有子类的共性功能,但是不给出,共性功能的具体实现,而是交由子类根据自身的特性做以具体的实现。
public abstract void eat();
public abstract void sleep();
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫白天睡觉");
}
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗晚上睡觉");
}
}
2.3 抽象类特点:
a.抽象类中可以没有抽象方法,也可以有抽象方法
b.一个类中一旦有了抽象方法,此类就必须定义为抽象类
c.抽象类 不能直接实例化(new 对象),但是可以采用多态的形式来间接实例化,用于子类访问父类数据时的初始化
d.抽象类中的所有抽象方法强制子类必须重写
e.抽象类的子类,有两种选择,选择一:重写抽象类中的所有抽象方法;选择二:自己也是个抽象类
public class MyTest {
public static void main(String[] args) {
Person p = new Teacher();
p.sleep();
p.eat();
// p.teacher; 报错 不能调特有
Teacher teacher= (Teacher) p ;
// ((Teacher) p).teach();
teacher.teach();
p=new Student();
p.sleep();
p.eat();
Student s= (Student) p;
s.playGame();
}
}
public abstract class Person {
public abstract void eat();
public abstract void sleep();
}
public class Student extends Person{
//alt+enter ctrl+O
@Override
public void eat() {
System.out.println("学生爱吃麻辣烫");
}
@Override
public void sleep() {
System.out.println("学生晚上熬夜");
}
// 学生特性
public void playGame(){
System.out.println("学生玩游戏");
}
}
public class Teacher extends Person {
@Override
public void eat() {
System.out.println("老师爱吃燃面");
}
@Override
public void sleep() {
System.out.println("老师早早就上床歇息了");
}
// 老师特性
public void teach() {
System.out.println("老师教书");
}
}
2.4 抽象类的成员特点
a:成员变量:既可以是变量,也可以是常量。
b:构造方法:有,用于子类访问父类数据的初始化。
c:成员方法:既可以是抽象的,也可以是非抽象的。
抽象类的成员方法特性:
a:抽象方法:强制要求子类做的事情。
b:非抽象方法:子类继承的事情,提高代码复用性。
2.5 abstract不能和哪些关键字共存:(abstract强制子类必须重写 )
private 私有的不能继承,重写不了;
final 方法子类不能重写 ;
static 静态方法不参与重写。
3. 接口:
为了定义一些额外、扩展的功能,哪些事物想要具备这些功能,可以对该接口进行实现
interface–定义一个接口 implements+某个接口
在接口中提供扩展功能,也不提供具体实现,父接口指向子类对象
3.1 接口中的成员特点:
a.成员变量:全部都是公共的静态常量,前面存在默认修饰符;接口直接调用
b.接口中不允许存在方法的具体是实现 JDK1.7之前,全部是抽象方法,不存在非抽象方法
c.构造方法:接口中没有构造方法
d.接口不能直接new对象
e.接口的子类:可以是抽象类,但是意义不大。也可以是具体类,要重写接口中的所有抽象方法。
public class MyTest {
public static void main(String[] args) {
System.out.println(A.NUM); //100 接口名直接调用
}
}
interface A{
public static final int NUM=100;
int N=20;
public abstract void a();
public abstract void aa();
int sum(int a,int b);
}
class B implements A{
@Override
public void a() {
}
@Override
public void aa() {
}
@Override
public int sum(int a, int b) {
return 0;
}
}
3.2 类与类,类与接口,接口与接口的关系关系区别:
类和类之间的关系:继承 extends,并且是单继承,可以多层继承
类和接口之间的关系:implements–实现关系,并且可以多实现,一个类可以实现多个接口,这个类要把他所实现的抽象方法都都重写
接口和接口之间的关系:继承关系–多继承,一个接口可以
package org.westos.demo2;
public class MyTest2 {
public static void main(String[] args) {
}
}
interface AA{
void aa();
}
interface BB{
void bb();
}
interface CC{
void cc();
}
interface DD extends AA,BB,CC{
void dd();
}
class MyDD implements DD{
@Override
public void aa() {
}
@Override
public void bb() {
}
@Override
public void cc() {
}
@Override
public void dd() {
}
}
//一个类 可以实现多个接口。这个类,要把他所有实现的接口中的所有抽象方法都要重写。
class MyClss implements AA,BB,CC{
@Override
public void aa() {
}
@Override
public void bb() {
}
@Override
public void cc() {
}
}
3.3 抽象类和接口的区别
抽象类 | 接口 |
---|---|
中可以定义抽象方法 也可以定义非抽象方法 | 里面定义的是抽象方法,JDK1.8可以定义default修饰方法和静态方法 |
有构造方法的 | 没有构造方法 |
是抽象所有子类的共性功能,并不给出共性功能的具体实现,而是交由子类根据自身的差异性,去做具体实现 | 中全是公共的静态常量,体现一种扩展的思想,通常用来定义一些规范和规则,哪些事物想要具备这些扩展功能,可以实现具体的接口 |
可以定义成员变量也可以定义常量 | 只可以常量 |
接口他只需要维护一套规范或者说规则,那么具体对规范的实现,是由子类来具体实现的。
注:JDk1.8针对接口,做了一些新的定义
a.JDk1.8之后 允许给出方法的具体实现,但是这个方法得用default来修饰
b.JDk1.8之后 接口中可以定义静态方法
public class MyTest {
public static void main(String[] args) {
Zi zi = new Zi();
zi.aa();
zi.bb();
AA.test();
}
}
interface AA{
// void ccc();
public default void aa(){ // 给出方法的具体实现,这个方法用default来修饰
System.out.println("aaa");
}
public static void test(){ // 可以定义静态方法
System.out.println("abc");
}
}
interface BB {
default void bb(){
System.out.println("bbb");
}
}
class Fu1{
public void show(){
System.out.println("fu1 show");
}
}
class Fu2 {
public void show2() {
System.out.println("fu2 show");
}
}
class Zi implements AA,BB{
}