当前位置: 首页 > news >正文

从0学Java--day7

本期是封装继承多态的一些介绍

Java封装、继承、多态详解

一、封装详解

封装是Java面向对象编程的基石,它把数据(属性)和操作数据的方法捆绑在一起,并隐藏内部细节,只暴露必要的接口。

知识点
  1. 核心思想:把对象的属性设为私有(private),通过公共(public)方法(getter和setter)来访问和修改属性。这就像把贵重物品锁在保险箱里(private字段),只给你钥匙(public方法)来操作。
  2. 访问修饰符
    • private:只能在当前类内部访问,外部无法直接看到或修改。
    • public:任何地方都能访问。
    • protected:同一包内或子类可以访问(但本讲解以基础为主,避免混淆)。
  3. Getter和Setter方法:Getter用于读取属性值,Setter用于设置属性值,并可以在方法中添加验证逻辑。
  4. 好处:提高安全性(防止非法修改)、增强可维护性(内部修改不影响外部代码)、简化使用(用户只需调用方法,无需知道细节)。
易错点
  1. 忘记使用private:直接声明属性为public,导致外部代码随意修改,破坏封装性。
  2. Getter/Setter方法缺失或错误:不提供getter/setter,或方法名不规范(如写成getAge()但属性是age),导致编译错误或运行时问题。
  3. Setter中无验证:在setter方法中不检查输入值(如年龄不能为负数),可能存入无效数据。
  4. 直接访问字段:在类内部方法中,错误地直接使用字段名而不通过getter/setter,这虽然能运行,但破坏了封装原则。
常见坑
  1. 字段暴露风险:如果属性是public,外部代码可以随意修改,比如把年龄设为-10,程序不会报错但逻辑错误。
  2. 方法签名错误:getter/setter方法名必须匹配属性名(如属性name的getter必须是getName()),否则IDE可能不识别,导致使用困难。
  3. 忽略默认值:未在构造器或setter中初始化属性,可能导致null或0值引发异常。
  4. 过度封装:把简单属性也封装得过于复杂,增加代码冗余,降低可读性。

二、继承详解

继承允许一个类(子类)基于另一个类(父类)创建,子类自动获得父类的属性和方法,并可以添加或修改功能。

知识点
  1. 核心思想:使用extends关键字建立继承关系(如class Dog extends Animal)。子类继承父类的非private成员(属性和方法),就像孩子继承父母的基因。
  2. 方法覆盖:子类可以重新定义父类的方法(使用相同方法名和参数),实现特定行为。覆盖时建议添加@Override注解来避免错误。
  3. super关键字:用于在子类中访问父类的成员,如super.methodName()调用父类方法,或super()调用父类构造器。
  4. 构造器链:子类构造器默认调用父类无参构造器(super())。如果父类没有无参构造器,必须在子类构造器中显式调用super(参数)
  5. 单继承限制:Java只支持单继承(一个子类只能有一个父类),不能多继承(如class A extends B, C是错误的)。
  6. 继承层次:所有类都隐式继承Object类(Java根类),提供toString()equals()等方法。
易错点
  1. 忘记super调用:在子类构造器中未显式调用super(),如果父类没有无参构造器,编译报错(说白了就是可以直接跳过子类的直接使用父类)。
  2. 方法覆盖失败:子类方法签名(方法名和参数)必须与父类完全一致,否则不是覆盖而是新方法(容易混淆)。
  3. 字段隐藏:如果子类声明了与父类同名的字段,父类字段会被“隐藏”(不是覆盖),访问时需用super.fieldName
  4. final类或方法:父类方法或类声明为final时,子类不能覆盖或继承。
  5. 访问权限错误:子类不能访问父类的private成员,需通过public/protected方法。
常见坑
  1. 构造器顺序问题:子类构造器必须先调用父类构造器(super()必须是第一行),否则编译错误。
  2. 覆盖与重载混淆:覆盖是相同签名的方法在子类重写,重载是相同方法名但不同参数。新手容易误用。
  3. 静态方法陷阱:静态方法不能被覆盖(只属于类,不属于对象),子类定义同名静态方法是“隐藏”而非覆盖。
  4. 无限递归:在覆盖方法中调用super.method()时,如果方法名写错,可能调用自身导致栈溢出。
  5. 继承滥用:不适当地使用继承(如只为了重用代码),导致类层次复杂,难以维护。

三、多态详解

多态允许同一方法在不同对象中有不同实现。在Java中,主要通过方法覆盖和父类引用指向子类对象实现。

知识点
  1. 核心思想:父类引用可以指向子类对象(如Animal myPet = new Dog()),调用方法时执行子类版本(运行时绑定)。这就像遥控器(父类引用)可以控制不同电器(子类对象),但按钮功能不同。
  2. 运行时多态:方法调用在运行时(非编译时)决定具体执行哪个类的方法,基于对象实际类型。
  3. 方法覆盖要求:多态依赖方法覆盖,子类方法必须与父类方法签名一致。
  4. 向上转型:将子类对象赋给父类引用(如Animal a = new Dog()),这是自动的,安全但丢失子类特有方法。
  5. 向下转型:将父类引用转回子类类型(如Dog d = (Dog) a),需要显式强制转换,如果类型不匹配会抛出ClassCastException
  6. 动态绑定:Java在运行时根据对象类型绑定方法,确保调用正确的覆盖方法。
易错点
  1. 签名不一致:子类覆盖方法时参数或返回类型不同,导致不是覆盖,多态失效。
  2. 忘记@Override:不添加@Override注解,可能因拼写错误误创建新方法而非覆盖。
  3. 静态方法多态失效:静态方法是编译时绑定,不能被覆盖,多态不适用。
  4. private方法问题:private方法不能被覆盖,子类定义同名方法是新方法,不参与多态。
  5. 字段多态无效:字段访问是编译时绑定(基于引用类型),不是运行时多态。
常见坑
  1. 类型转换异常:向下转型时,如果父类引用实际指向其他子类对象(如Animal a = new Cat(); Dog d = (Dog) a),会抛出ClassCastException
  2. 误用父类引用:向上转型后,只能调用父类定义的方法,不能直接调用子类特有方法(需向下转型)。
  3. 覆盖方法访问权限:子类覆盖方法不能比父类方法更严格(如父类方法是public,子类不能改为private)。
  4. 多态与构造器:构造器中调用可覆盖方法,可能因多态导致未初始化子类字段(危险,避免在构造器调用覆盖方法)。
  5. 性能误解:多态增加运行时开销(动态绑定),但现代JVM优化后影响小,新手可能过度担心。

四、5个基础实例详解

以下是5个基础实例,每个都严格使用封装、继承、多态之前的知识点(只涉及类、对象、方法、变量、访问修饰符、继承和方法覆盖)。每个实例包括代码、详细分析(执行过程、易错点避免、通俗解释),确保超级详细和通俗易懂。

实例1:纯封装演示(重点:封装基础)

场景:创建一个Person类,封装姓名和年龄,防止非法值。

public class Person {// 私有字段,外部无法直接访问private String name;private int age;// 构造器初始化public Person(String name, int age) {this.name = name;setAge(age); // 通过setter设置,添加验证}// Getter方法:读取namepublic String getName() {return name;}// Setter方法:设置age,添加验证public void setAge(int age) {if (age >= 0) { // 验证年龄不能为负this.age = age;} else {System.out.println("年龄不能为负数,设置为0");this.age = 0;}}// Getter方法:读取agepublic int getAge() {return age;}
}// 测试类
public class Main {public static void main(String[] args) {Person person = new Person("张三", 25);System.out.println("姓名:" + person.getName() + ", 年龄:" + person.getAge());person.setAge(-5); // 尝试设置非法年龄System.out.println("更新后年龄:" + person.getAge()); // 输出应为0}
}

详细分析

  • 代码解释Person类将nameage声明为private,外部只能通过getName()getAge()setAge()访问。构造器中调用setAge()确保初始化验证。测试代码创建对象并尝试设置非法年龄。
  • 执行过程:运行main方法时,先创建Person对象(年龄25),输出正确。然后调用setAge(-5),由于验证逻辑,年龄被设为0,输出"更新后年龄:0"。
  • 易错点避免
    • 避免直接访问字段:如person.age = -5会报错(编译错误),因为age是private。
    • Setter验证:在setAge()中添加if检查,防止负值,确保数据安全。
    • Getter/Setter命名:方法名getAge()匹配字段age,避免拼写错误。
  • 通俗比喻:这就像银行账户(Person对象),余额(age)被锁在保险箱(private),你只能通过ATM机(public方法)存取,ATM会检查你输入的金额是否合法。
  • 常见坑:如果不加验证,setAge(-5)会让年龄为负,程序逻辑错误。这里通过setter防御,避免此坑。
实例2:纯继承演示(重点:继承基础)

场景:创建一个Animal父类和Dog子类,子类继承并覆盖父类方法。

// 父类
public class Animal {private String name;public Animal(String name) {this.name = name;}public void eat() {System.out.println(name + "正在吃东西");}public String getName() {return name;}
}// 子类继承Animal
public class Dog extends Animal {public Dog(String name) {super(name); // 调用父类构造器}// 覆盖父类eat方法@Overridepublic void eat() {System.out.println(getName() + "(狗)正在啃骨头");}// 子类特有方法public void bark() {System.out.println("汪汪叫!");}
}// 测试类
public class Main {public static void main(String[] args) {Dog myDog = new Dog("小黑");myDog.eat(); // 调用覆盖后的方法myDog.bark(); // 调用子类特有方法}
}

详细分析

  • 代码解释Animal是父类,有name字段和eat()方法。Dog子类用extends Animal继承,覆盖eat()方法(添加@Override),并添加特有方法bark()。测试代码创建Dog对象并调用方法。
  • 执行过程:运行main方法,创建Dog对象时,先调用父类构造器(super(name))初始化name。然后myDog.eat()执行子类覆盖的版本,输出"小黑(狗)正在啃骨头"。myDog.bark()输出"汪汪叫!"。
  • 易错点避免
    • super调用:子类构造器中super(name)显式调用父类构造器,避免父类无默认构造器导致的编译错误。
    • 方法覆盖:@Override注解确保签名正确,如果拼写错误(如eats()),编译器会警告。
    • 字段访问:子类通过getName()访问父类private字段,不能直接访问name
  • 通俗比喻:动物(父类)有吃饭行为,狗(子类)继承了吃饭,但改成啃骨头(覆盖方法),狗还有自己的叫声(特有方法)。
实例3:纯多态演示(重点:多态基础)

场景:使用AnimalDog类,通过父类引用指向子类对象,展示多态。

// 父类(同实例2)
public class Animal {public void eat() {System.out.println("动物吃东西");}
}// 子类(同实例2)
public class Dog extends Animal {@Overridepublic void eat() {System.out.println("狗啃骨头");}
}// 测试类
public class Main {public static void main(String[] args) {Animal myAnimal = new Dog(); // 向上转型:父类引用指向子类对象myAnimal.eat(); // 多态:运行时调用Dog的eat方法// 向下转型示例if (myAnimal instanceof Dog) {Dog myDog = (Dog) myAnimal; // 强制向下转型myDog.eat(); // 安全调用}}
}

详细分析

  • 代码解释Animal父类和Dog子类(覆盖eat())。测试代码中,Animal myAnimal = new Dog()实现向上转型(父类引用指向子类对象)。调用myAnimal.eat()时,执行子类方法。然后演示向下转型((Dog) myAnimal),使用instanceof检查避免异常。
  • 执行过程:运行main方法,myAnimal.eat()输出"狗啃骨头",因为运行时绑定到Dog类的方法。向下转型后,myDog.eat()同样输出"狗啃骨头"。
  • 易错点避免
    • 运行时绑定:myAnimal.eat()在运行时确定对象是Dog,调用子类方法,避免编译时误解。
    • 安全向下转型:先用instanceof检查类型,再强制转换,防止ClassCastException
    • 方法覆盖:确保Dog.eat()签名与父类一致,否则多态失效。
  • 通俗比喻:把狗(子类对象)当作动物(父类引用)来操作,让它“吃饭”时,它实际执行狗的吃饭方式(多态)。这就像用通用遥控器(父类引用)控制电视(子类对象),但按钮功能不同。
  • 常见坑:如果不检查直接向下转型(如Dog d = (Dog) new Animal()),会抛出异常。这里用instanceof 避免此坑
实例4:封装和继承结合演示(重点:封装在继承中的应用)

场景:创建一个Vehicle父类封装速度,Car子类继承并添加功能。

// 父类:封装速度
public class Vehicle {private int speed; // 私有字段public Vehicle(int speed) {setSpeed(speed); // 通过setter初始化}// Setter添加验证public void setSpeed(int speed) {if (speed >= 0) {this.speed = speed;} else {this.speed = 0;}}// Getterpublic int getSpeed() {return speed;}public void move() {System.out.println("交通工具移动,速度:" + speed);}
}// 子类继承Vehicle
public class Car extends Vehicle {public Car(int speed) {super(speed); // 调用父类构造器}// 覆盖父类方法@Overridepublic void move() {System.out.println("汽车行驶,速度:" + getSpeed()); // 通过getter访问父类私有字段}
}// 测试类
public class Main {public static void main(String[] args) {Car myCar = new Car(60);myCar.move(); // 调用覆盖方法myCar.setSpeed(-10); // 通过继承的setter设置速度System.out.println("当前速度:" + myCar.getSpeed()); // 输出应为0}
}

详细分析

  • 代码解释Vehicle父类封装speed(private),提供验证的setter。Car子类继承,覆盖move()方法。测试代码创建Car对象,调用覆盖方法和setter。
  • 执行过程:运行main方法,myCar.move()输出"汽车行驶,速度:60"。然后myCar.setSpeed(-10)触发验证,速度被设为0,输出"当前速度:0"。
  • 易错点避免
    • 封装继承整合:子类通过getSpeed()访问父类private字段,不能直接super.speed(编译错误)。
    • Setter重用:子类继承父类的setter,直接使用myCar.setSpeed(),无需重写。
    • 覆盖方法:@Override确保正确覆盖,避免新方法创建。
  • 通俗比喻:交通工具(父类)有速度表(private字段),汽车(子类)继承了它,但用自己的方式显示速度(覆盖方法)。速度表只能通过特定按钮(setter)修改。
  • 常见坑:如果父类字段不是private,子类可能直接修改导致错误。这里封装确保数据安全。
实例5:多态结合演示(重点:多态在集合中的应用)

场景:使用Animal父类和多个子类(Dog, Cat),通过数组展示多态。

// 父类
public class Animal {public void makeSound() {System.out.println("动物发出声音");}
}// 子类1
public class Dog extends Animal {@Overridepublic void makeSound() {System.out.println("狗:汪汪");}
}// 子类2
public class Cat extends Animal {@Overridepublic void makeSound() {System.out.println("猫:喵喵");}
}// 测试类
public class Main {public static void main(String[] args) {Animal[] animals = new Animal[2]; // 父类数组animals[0] = new Dog(); // 向上转型animals[1] = new Cat(); // 向上转型for (Animal animal : animals) {animal.makeSound(); // 多态:运行时调用不同子类方法}}
}

详细分析

  • 代码解释Animal父类有makeSound()方法。DogCat子类覆盖它。测试代码创建父类类型数组,存储不同子类对象(向上转型),遍历调用makeSound()展示多态。
  • 执行过程:运行main方法,数组animals包含DogCat对象。循环中,animal.makeSound()根据实际对象类型输出"狗:汪汪"和"猫:喵喵"。
  • 易错点避免
    • 数组多态:父类数组存储子类对象是安全的,多态确保正确方法调用。
    • 覆盖一致性:所有子类方法签名相同,避免编译错误。
    • 无向下转型:这里不需要向下转型,因为只调用父类定义的方法。
  • 通俗比喻:动物园笼子(父类数组)里关着狗和猫(子类对象),管理员让每个动物“叫”时(调用方法),狗汪汪叫,猫喵喵叫(多态)。
  • 常见坑:如果子类未覆盖方法(如Cat不写makeSound()),会调用父类默认输出。这里确保所有子类覆盖,避免此坑。

总结

  • 封装:保护数据,通过private字段和public方法控制访问。易错在忘记private或setter验证。
  • 继承:子类复用父类代码,可覆盖方法。易错在super调用或方法签名。
  • 多态:同一方法不同实现,依赖覆盖和向上转型。易错在类型转换或静态方法。

以上是一些基础概念的介绍,真正掌握还需要多在实际敲代码中练习

http://www.dtcms.com/a/555002.html

相关文章:

  • 做ppt医学专业图片网站徐州哪里做网站
  • 容器之间怎么通信?Docker 网络全解析
  • 网站优化平台网站建设 岗位
  • 老干部活动中心网站建设方案wordpress 企业库插件
  • 网站前台和后台轻松seo优化排名
  • 怎样防止网站被黑专业做网站制作自助建站系统
  • 了解学习LVS-DR模式配置
  • 对网站建设安全性的要求网站的建设成本
  • 中国七大城市电动汽车使用与充电分析数据集
  • 博爱网站建设重庆响应式网站方案
  • 微前端乾坤vue3项目使用tinymce,通过npm,yarn,pnpm包安装成功,但是引用报错无法使用
  • 石家庄房产信息网查询系统googleseo优化
  • Spec-kit 入门
  • 做影视网站代理犯法吗外贸做的社交网站
  • 服装工厂做网站的好处电子商务概念
  • 第三篇:不靠毅力靠方法:“小步子原理”启动改变飞轮
  • 网站图片太多做外贸需要浏览外国网站
  • 有什么网站做统计图的win7建网站教程
  • 阿里巴巴指数查询重庆网站营销seo电话
  • 抖音代运营是什么意思长春做网站公司长春seo公司
  • 动易 手机网站云南做网站报价
  • 做网站什么数据库用的多网络营销大师排行榜
  • 基于音乐推荐数据的逻辑回归实验报告:曲风特征与用户收听意愿预测
  • 基于MQTT的智能家居系统的学习
  • 广平企业做网站推广河北软文搜索引擎推广公司
  • 通信的经典知识点和问题(3)
  • 边界扫描测试原理 12 -- BSDL 6 INTEST 描述
  • python图像识别系统 AI多功能图像识别检测系统(11种识别功能)银行卡、植物、动物、通用票据、营业执照、身份证、车牌号、驾驶证、行驶证、车型、Logo✅
  • 数字化转型可以解决传统供应链的哪些问题?
  • 亚马逊海外版网站软文范例500字