封装,继承,多态
① 封装
封装是面向对象编程中最基本的特征之一,它将数据和操作数据的方法封装在一个单独的类中。通过封装,可以隐藏对象的内部细节,只暴露出必要的接口供其他对象进行交互,从而实现了信息的隐藏和保护。
简单的说,就是将对象的属性Private私有化,提供对应的getter和setter方法,方便操控对象的属性,然后暴露出需要交互的接口。
为什么使用封装?
封装的特点:
- 对成员变量实行更准确的控制
- 封装可以隐藏内部程序实现的细节
- 良好的封装能够减少代码之间的耦合度
- 外部成员无法修改已封装好的程序代码
- 方便数据检查,有利于保护对象信息的完整性,同时也提高程序的安全性。
- 便于修改,提高代码的的可维护性。
public class Student {
private String name;
private String sid;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSid() {
return sid;
}
public void setSid(String sid) {
this.sid = sid;
}
}
② 继承
继承是面向对象编程中的另一个重要特征,它允许一个类继承另一个类的属性和方法,从而实现代码的重用和扩展性。被继承的类称为父类(或超类),继承这个类的类称为子类。子类可以继承父类的所有非私有属性和方法,并可以在其基础上添加新的属性和方法。
继承的注意事项:
- 只支持单继承,但可以多级继承,子类的父类可以再继承其他的类
- 子类可以拥有父类的非私有的属性和方法
- 子类可以拥有自己的属性和方法
- 子类可以重写覆盖父类的方法
public class DemoInherit {
public static void main(String[] args) {
Fu fu = new Fu("张三");
fu.showMoney();
Zi zi = new Zi("张小明");
zi.showMoney();
}
}
class Fu{
public Double money = 11000.1;
private String name;
private void showFuMoney(){
System.out.println(money);
}
public void showMoney(){
System.out.println("Fu:"+this.money);
}
public Fu() {
}
public Fu( String name) {
this.name = name;
}
}
class Zi extends Fu{
private String name;
public Double money = 100.1;
@Override
public void showMoney() {
super.showMoney();
System.out.println("Zi:总金额"+this.money);
}
public Zi() {
}
public Zi(String name) {
this.name = name;
this.money += super.money;
}
}
重写 override
重写是子类对父类的允许访问方法的实现过程进行重新编写,方法名,返回值和形参都不能改变。
class People{
public void run(){
System.out.println("人在奔跑");
}
}
class Student extends People{
@Override
public void run() {
// super.run(); super关键字指向父类的引用
System.out.println("学生在奔跑");
}
}
重写的规则:
- 参数列表必须与被重写方法一致
- 访问权限不能比父类中被重写的方法的访问权限更低(public>protected>default>private)。
- 父类成员的方法只能被其子类重写
- 被final修饰的方法不能被重写
- 构造方法不能被重写
重载 overload
重载是指,在同一个类中,方法名字相同,而参数不同。返回类型可以相同也可以不同。每个重载的方法的参数列表必须不同。
重载规则:
- 被重载的方法必须改变参数列表(参数个数或者类型不一样或者参数列表的顺序不一致)
- 被重载的方法可以改变返回值类型
- 被重载的方法可以改变修饰符
public class Dog {
public void run(){
System.out.println("小狗在慢悠悠的run");
};
protected void run(String toy){
System.out.println("小狗在run的过程中,捡到了你扔出的"+toy);
}
private String run(String toy,int size){
System.out.println("小狗在run的过程中,捡到了你扔出的"+toy+",并摇了"+size+"次尾巴");
return toy+","+size;
}
// 参数列表顺序不一致 若是同种数据类型的话无法完成重载
private String run(int size,String toy){
System.out.println("小狗在run的过程中,捡到了你扔出的"+toy+",并摇了"+size+"次尾巴");
return toy+","+size;
}
public static void main(String[] args) {
Dog dog = new Dog();
dog.run();
dog.run("飞盘");
String rs1 = dog.run("皮球", 3);
String rs2 = dog.run( 3,"皮球");
}
}
super this 关键字
super()关键字的用法:
- 子类的成员方法中,访问父类的成员变量。
- 子类的成员方法中,访问父类的成员方法。
- 子类的构造方法中,访问父类的构造方法。
this关键字用法:
- 本类成员方法中,访问本类的成员变量。
- 本类成员方法中,访问本类的另一个成员方法。
- 本类的构造方法中,访问本类的另一个构造方法。
注意:
- this关键字同super一样,必须在构造方法的第一个语句,且是唯一的。
- this与super不能同时存在。
③ 多态
多态是面向对象的第三个特征,它允许一个对象在不同的情况下表现出不同的行为。
多态分为编译时多态和运行时多态。编译时多态是通过方法重载来实现的,而运行时多态是通过方法重写和向上转型来实现的。
多态的特点:
- 消除类型之间的耦合关系,实现低耦合
- 灵活性
- 可扩充性
- 可替换性
向上转型
格式: 父类名称 对象名 = new 子类名称(); 含义:右侧创建一个子类对象,将它当作父类使用
缺点:一旦向上转型,子类中原本特有的方法就不能再被调用了。
public class MultiDemo {
public static void main(String[] args) {
// 向上转型
Animal dog = new Dog();
dog.eat(); // 小狗吃。。。。
// dog.run(); 向上转型后,Dog类对象无法再调用其特与的方法( run() 方法)
Animal cat = new Cat();
cat.eat();
// cat.sound(); 同理向上转型后,cat无法再调用自己特有的方法
// 向下转型
Cat catDown = (Cat) cat;
catDown.sound(); // 小猫 喵喵喵
catDown.eat(); // 小猫吃。。。。
// 下面是错误的操作,将向上转型的dog再向下转型为cat,编译时是无法发现错误的,运行时才会出现错误
// 向下转型 一定要记得该对象的初始值类型是啥,否则会抛异常 ClassCastException
Cat catDownError = (Cat) dog;
catDownError.sound();
}
}
// 动物类-父类
class Animal{
public void eat(){
System.out.println("动物吃。。。。");
}
}
// Dog类
class Dog extends Animal{
@Override
public void eat() {
// super.eat();
System.out.println("小狗吃。。。。");
}
public void run(){
System.out.println("小狗跑........");
}
}
// Cat类
class Cat extends Animal{
@Override
public void eat() {
// super.eat();
System.out.println("小猫吃。。。。");
}
public void sound(){
System.out.println("小猫 喵喵喵");
}
}
多态中,编译看左边,运行看右边,解释如下.
- 编译看左边:
- 在编译时,编译器主要关注的是代码的静态结构。
- 编译器会检查类型,以确保在编译期间类型是正确的。
- 例如,当你在代码中调用一个方法时,编译器会检查该方法是否真的存在于你正在调用的对象的类或其父类中。如果存在,那么这个方法可以被调用。如果不存在,编译器将报错。
- 运行看右边:
- 在运行时,实际的对象实例决定了实际的行为。
- 这是多态的核心:一个接口可以有多种实现,而实际的行为在运行时由对象的实际类型决定。
- 例如,如果你有一个父类和两个子类,都实现了同一个方法。当你通过父类引用调用这个方法时,实际执行的是哪个子类的实现,取决于引用所指向的实际对象。
小结
封装:隐藏对象内部的细节,只暴露出必要的接口去交互,实现了信息的隐藏与保护。(简单的说,就是将对象独有的数据private掉,将公共的方法接口public出去,然后提供getter和setter方法)
继承:允许一个类继承另一个类的方法和属性,实现代码的复用性和扩展。子类只能继承父类非private的成员方法和成员属性。子类可以重写父类允许子类方法的方法,重写的注意点,即结构不变,内核变(方法体根据自己的业务去更改,方法的返回值,方法名参数值列表均不可以变)。和继承相关的两个关键字:super和this,分别是指向父类的引用和本类的引用。
多态:多态分为编译时多态和运行时多态,编译时多态即方法的重载,运行时多态是指方法的重写和**向上转型。多态提高了程序的扩展性和灵活性。**需要注意的是,向上转型后,子类无法再使用内部特有的方法,如果想使用的话,再向下转型,向下转型时,需要注意实际类型是否匹配,不匹配会抛出 ClassCastException 异常。