活动地址:CSDN21天学习挑战赛
面向对象
1.多态
-
多态
-
宏观角度(现实生活中): 一个事物在不同时刻体现的不同形态
-
微观角度(内存中变化): 具体对象在内存中的变化(对象在不同时刻的类型)
-
-
多态的前提条件
- 必须有继承关系(类与类)
- 必须存在方法重写,子类部分功能要将父类的功能进行覆盖,重写,子类使用自己的功能体现
- 必须存在父类引用指向类对象:
- 固定格式: 父类名 对象名 = new 子类名() ; //向上转型:使用的父类的东西
-
多态的成员访问特点: 父类名 对象名 = new 子类名() ;
-
成员变量:
-
编译看左,运行看左 ;
-
-
成员方法 (非静态):
-
编译看左,运行看后(子类重写了父类的功能)
-
-
静态方法:
-
即使子类出现了和父类一模一样静态方法,不算重写,因为静态方法都是自己类相关的,类成员
-
编译看左,运行看左;
class Animal{ //父类的静态方法 public static void show(){ System.out.println("show Animal"); } } class Cat extends Animal{ public static void show(){ System.out.println("show Cat"); } } public class DuoTaiDemo { public static void main(String[] args) { Animal.show(); Cat.show(); } }
-
-
构造方法:
-
多态的前提条件,有继承关系,跟继承一样,分层初始化
-
先执行父类的构造方法,然后再是子类的构造方法
-
class Animal{ int age = 40 ; public Animal(){ System.out.println("Animal的无参构造方法"); } public void eat(){ System.out.println("动物饿了要吃饭"); } public void sleep(){ System.out.println("动物困了要休息"); } //父类的静态方法 public static void show(){ System.out.println("show Animal"); } } //猫类 class Cat extends Animal{ int age = 25 ; public Cat(){ System.out.println("Cat的无参构造方法"); } //将eat和sleep()具体体现,应该重写父类的方法 public static void show(){ System.out.println("show Cat"); } @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("狗趴着睡"); } } //测试类 public class DuoTaiDemo { public static void main(String[] args) { Animal a = new Cat() ; //堆内存存储的猫 猫是动物 System.out.println(a.age) ;// 编译看左,运行看左 ; a.eat(); //编译看左,运行看右 (前提存在重写) a.sleep();编译看左,运行看右 (前提存在重写) } }
-
-
多态的弊端:
- 无法调用子类的特有功能
- 解决方法
- 方法1:创建自己的子类对象
- 子类名 对象名 = new 子类名() ;
- 缺点:
- 本身Fu fu = new Zi() ;已经开辟堆内存空间了,Zi zi = new Zi();又要在堆内存开辟空间,消耗内存空间比较大 ;
- 方法2: 向下转型
- 前提必须向上转型Fu fu = new Zi() ;
- Zi z = (Zi)fu ; //强转的语法
- 优点:节省内存空间
- 方法1:创建自己的子类对象
//父类 class Person{ int age = 20; } //子类 class Man extends Person{ int age = 40; } public class Test{ public static void main(String[] args){ Person person = new Man(); //向上转型 System.out.println(person.age); //20 Man man = (Man) person; //向下转型 System.out.println(man.age); //40 } }
注意事项:
针对多态的向下转型,前提必须有向上转型(父类引用指向子类对象)
但是,写代码的时候,应当注意内存中的变化,否则会出现一种 “异常”
运行时期异常 ---- >java.lang.ClassCastException:类转换异常
一般都出现多态里面向下转型使用不当就会造成这个异常出现
//向上转型 Animal animal = new Cat() ; //堆内存是猫 //向下转型 Dog dog = (Dog) animal; //格式正确:符号强转语法 但是运行会报错: //将猫转成狗,所以要注意内存中的变化,避免类转换异常
- 好处
-
提高代码的复用性,由继承保证的
-
提高代码的扩展性,由多态保证 : 父类引用指向子类对象
-
2.抽象类
- 抽象类: 在一个类中,如果有抽象方法,这个类必须为抽象类(前面要加abstract关键字)
- 抽象类的特点:
-
不能实例化 (不能创建对象)
-
必须强制子类完成事情:必须将抽象方法重写
-
- 抽象方法: 某个事物的一些行为,不给出具体体现,在Java编程中,应该加入一个关键字abstract,这些行为 ---- > “抽象方法”
注意:
- 有抽象方法的类一定是抽象类,否则编译就会报错
- 抽象类中不一定都是抽象方法,也可以用非抽象方法
- 抽象类中可以没有抽象方法
-
抽象的方法的格式:
-
根据写方法的格式一样,加入一个关键字abstract,而且没有方法体{} * public abstract 返回值类型 方法名(空参/带参) ;
-
-
抽象类的子类:
- 通过具体类才能创建对象
- 抽象的父类名 对象名 = new 具体的子类名() ; //抽象类多态
- 通过具体类才能创建对象
-
抽象类的成员特点:
-
成员变量 * 抽象类的成员变量既可以有变量,也可以是自定义常量被final修饰
-
成员方法 * 抽象类中既可以有抽象方法,也可也有非抽象方法
-
构造方法 * 既可以定义无参/有参构造方法...
-
存在抽象类多态,有继承关系,初始化的时候 * 构造方法----分层初始化 ---- > 先父类初始化 ---- > 再子类初始化
-
补充:
子类继承父类,子类重写父类的抽象方法时
- 必须保证访问权限足够大,要么加public要么跟父类的方法保持一致,否则会报错
如果有一个类没有任何的抽象方法,还要将这个类定义为抽象类的意义?
- 意义就是不能让它new,它如何实例化呢?肯定有具体的子类,进行抽象类多态来操作.
注意事项:
abstract关键字应用范围:
- 定义在类上—抽象类
- abstract 返回值类型 方法/名(空参带参…)
- 定义在方法上----抽象方法
- public abstract 返回值类型 方法名(空参/带参…)
和关键字abstract冲突的关键字
- private关键字冲突
- 因为被private私有的成员方法只能在本类访问,而abstract修饰的成员方法必须强制子类重写,已经超出来的当前类的范围
- final关键字冲突
- 被final修的成员方法,不能被重写,而抽象方法强制子类必须重写
- static关键字冲突
- abstract修饰的方法必须被子类重写,而static修饰的方法,算不上抽象,直接跟类相关的
3.接口
-
接口: 接口体现的是事物的一种额外功能,需要事物要对接口的功能要进行实现,才具备
-
Java编码中,体现这些事物本身所不具备的功能,要经过一些特殊的实现才能具备功能-----称为 “接口” ---- > 关键字 interface
-
格式的写法
interface 接口名{ //命名规范和类名命名一样,见名知意 "大驼峰命名法" 只能为抽象方法 }
-
注意:
接口比抽象类还抽象 ---- > 特点:不能实例化
接口通过它的子实现类进行实例化(前提,这个类实现 implements 接口)
class 子实现类名 implements 接口名{//实现 }
- 实际开发中:接口的子实现类名的命名—> 接口名的后面+Impl:表示是接口的实现类
- 设计理念:
- 体现的是一种 "like a"的关系
- 继承的设计理念体现的是一种"is a"的关系 :什么是什么的一种
//接口
interface Fly {
void fly(); //需要注意,这里有默认修饰符 public abstract ,要注意后面的权限问题
}
//滑翔松鼠
class Squirrel implements Fly{
@Override
public void fly() {
System.out.println("松鼠学会了短距离滑翔");
}
}
//测试类
public class InterfaceDemo {
public static void main(String[] args) {
//接口不能实例化,需要通过子实现类实例化(必须为具体类)
//测试:接口多态---接口名 对象名 = new 子实现类名();
Fly Squirrel = new Squirrel() ;
Squirrel.fly();
}
}