Java——类与对象(继承和多态)

简介: 本文介绍了面向对象编程中的继承概念,包括如何避免重复代码、构造方法的调用规则、成员变量的访问以及权限修饰符的使用。文中详细解释了继承与组合的区别,并探讨了多态的概念,包括向上转型、向下转型和方法的重写。此外,还讨论了静态绑定和动态绑定的区别,以及多态带来的优势和弊端。

继承

当我们去定义一个student类和techer类时会发现里面有重复的属性,那如果我们相要写其他一些工作人员的类时,每一个类都要写这些重复的属性

这时当我们把这些属性抽取出来,定义在一个Person类中,每个类都写其中的特有元素

继承的关系是通过
extends来实现的,也就是Student类继承了Person类的属性和方法
通过继承,提高了代码的复用性,子类可以在父类的基础上添加其他方法,让子类更强大

注意:
Java中不支持多继承,但可以多层继承

继承中成员变量的访问

public class Fu {
    String name = "Fu";
}
public class Zi extends Fu{
    String name = "Zi";
    public void ziShow(){
        String name = "localZi";
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);
    }
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.ziShow();
    }
}

运行结果

可以看出,对于成员变量的访问遵循就近原则,通过关键字this访问本类成员变量,super访问当前类的父类的成员变量

继承中构造方法的访问

首先,我们要明白
父类中的构造方法是不会被子类继承的,可以通过super调用
子类中的所有构造方法默认先访问父类中的无参构造方法,再执行自己

原因:
子类在初始化的时候,有可能会用到父类中的数据,如果父类还没有初始化,那么子类就用不了父类的数据了,子类在初始化之前,一定要调用父类构造方法完成父类数据空间的初始化

public class Text {
    public static void main(String[] args) {
        Dog dog = new Dog();
    }
}
class Animal{
    public String name;
    public Animal(){
        System.out.println("父类构造方法");
    }
}
class Dog extends Animal{
    public Dog(){
        System.out.println("子类构造方法");
    }
}


根据打印结果可以看出,父类初始化,子类再初始化,也就是现有父再有子

子类调用父类构造方法:
子类构造方法第一句默认是super(),不写也存在,而且必须
放在第一行
如果要调用父类的有参构造,就必须手动书写super进行调用

接下来看个例子理解一下:

所以最后输出的结果就是,先打印父类无参构造,再打印子类无参构造


那么子类怎么进行有参构造呢
这时就需要在子类的有参构造中通过super去调用父类的有参构造

还有一种传参方式,可以对比一下

这两种方法一个是在有参构造中调用父类的有参构造,一个是在无参构造中调用
super和this总结

相同点:
1.都是Java中的关键字
2.只能在类的非静态方法中使用,用来访问非静态成员方法和字段
3.在构造方法中调用时,必须是构造方法的第一条语句,并且不能同时存在
不同点:
this是当前对象的引用,super相当于是子类对象从父类成员中继承下来部分成员的引用

继承和组合

继承的关系就是,一个事物是另一个大的事物的一种,例如猫是动物,而组合的关系就是一个事物是另一个事物的一部分,例如轮子是汽车的一部分,学生是学校的一部分这种
组合的实现

public class Car {
    
    //汽车轮胎
    private Tire[] tires;
    //汽车引擎
    private Engine engine;
    //车载系统
    private VehicleSystem vehicleSystem;
}
//轮胎类
class Tire{
    //······
}
//发动机类
class Engine{
    //······
}
//车载系统类
class VehicleSystem{
    
}

初始化执行顺序


先执行静态代码块,因为之前提到过,静态代码块是不依赖于对象的,接着执行父类的实例和构造,再执行子类的实例和构造

那如果再创建一个对象呢

Cat cat2 = new Cat("小白",5);


静态代码块只加载一次,然后随着对象的创建加载父类和子类

权限修饰符的介绍


private
private很好理解,同一个包中的其它类就不能访问了,只能本类中才能访问
空着不写
空着不写也就是不加任何权限修饰符

String s1;
int a;

同一个包中的其他类能访问

也就是上面Textdemo中定义的变量,在Textdemo2中也能访问

protect

下面就是不同包中的子类的例子:


那么能用super去访问吗

很明显,编译器直接报错了,因为main方法也是static修饰的,不能用super
public
public字面意思就是公开的的,谁都能访问

final关键字

final表示最终的,不能被修改。

被final修饰的方法不能被重写:

修饰的类不能被继承:
例如Java中的String类就被final修饰,不能被继承,所以里面的所有方法不能被重写

修饰的变量叫做常量,只能被赋值一次:

多态

什么是多态呢,就是去完成某个行为,当不同的对象去完成时会产生不同的状态
多态实现的条件:

1.必须在继承体系下
2.子类必须对父类中的方法进行重写
3.通过父类的引用调用重写的方法

这些我们在之后慢慢理解

向上转型

向上转型就是创建一个子类对象,把它当成父类对象来使用,也就是父类引用了子类的对象
语法格式: 父类类型 对象名 = new 子类类型(),有以下三种方式可以达到父类引用子类对象的效果

直接赋值

Animal animal = new Dog("二哈",10);

方法传参

返回值


向上转型不能调用子类特有的方法

向下转型

向下转型和向上转型正好相反,也就是把父类的对象转化为子类的引用

public class Text {
    public static void main(String[] args) {
        Animal animal = new Dog("大黄",3);
        // 向下转型
        Dog dog = (Dog) animal;
        dog.eat();
    }
}

向下转型涉及到强制类型转换,所以存在风险,并不常用
还有一个注意点,强制转换并不是万能的

public static void main(String[] args) {
        Animal animal = new Dog("大黄", 3);
        // 向下转型
        Dog dog = (Dog) animal;
        dog.eat();
        Animal animal1 = new Cat("Tom", 2);
        Dog dog1 = (Dog) animal1; // 报错 ClassCastException
        dog1.eat();
    }

上面的代码会报错,这是因为转型前后的对象类型并不匹配
为了避免这种错误,通常会在进行向下转型之前使用
instanceof关键字来检查对象是否是目标类的实例:

public static void main(String[] args) {  
    Animal animal = new Dog("大黄", 3);  
    // 向下转型,之前已经知道animal实际上是Dog类型  
    Dog dog = (Dog) animal;  
    dog.eat();  
    Animal animal1 = new Cat("Tom", 2);  
    // 检查animal1是否是Dog的实例  
    if (animal1 instanceof Dog) {  
        Dog dog1 = (Dog) animal1; // 如果animal1实际上是Dog,这行代码不会执行  
        dog1.eat();  
    } else {  
        System.out.println("animal1 不是一个 Dog 对象");  
    }   
}

方法的重写

父类子类中的两个方法如果满足:
1.方法名相同
2.参数列表相同
3.返回值相同
就构成了方法的重写

重写的注意事项:
1.不能是静态方法,构造方法
2.不能被final,private修饰
3.子类重写父类的方法,子类的权限要大于等于父类
4.被重写的方法返回值类型可以不同,但必须是具有父子关系的

静态绑定:在编译时,根据用户所传入参数的类型就知道具体调用哪个方法,也就是重载的例子。

动态绑定:
当运行代码的时候,通过父类的引用,调用了父类和子类重写的那个方法,结果实际调用了子类的方法,叫做动态绑定,也就是在编译时,不能确定方法的行为,等到程序运行时才能够具体确定调用哪个类,

例如我们在测试类中通过向上转型的方式进行调用,虽然我们使用父类调用的方法,但运行结果是根据子类的方法运行的

public class Text {
    public static void main(String[] args) {
        Animal animal = new Dog("大黄",3);
        animal.eat();
    }
}

再看下面的代码,就对多态理解的更深了:

public class Text {
    public static void main(String[] args) {
        Dog dog = new Dog("大黄",3);
        func(dog);
        Cat cat = new Cat("小白",2);
        func(cat);
    }
    public static void func(Animal animal){
        animal.eat();
    }
}

也就是不同的对象去调用同一个方法,有了不同的状态,这就叫做多态,但是编译还是按照父类animal的eat编译的,运行则是按照子类的eat方法运行

多态的优势:
方法中,可以使用父类型作为参数,可以接收所有的子类对象
弊端:
不能使用子类特有的方法

相关文章
|
6天前
|
Java
课时14:Java数据类型划分(初见String类)
课时14介绍Java数据类型,重点初见String类。通过三个范例讲解:观察String型变量、"+"操作符的使用问题及转义字符的应用。String不是基本数据类型而是引用类型,但使用方式类似基本类型。课程涵盖字符串连接、数学运算与字符串混合使用时的注意事项以及常用转义字符的用法。
|
6天前
|
存储 Java 编译器
课时11:综合实战:简单Java类
本次分享的主题是综合实战:简单 Java 类。主要分为两个部分: 1.简单 Java 类的含义 2.简单 Java 类的开发
|
7天前
|
传感器 监控 Java
Java代码结构解析:类、方法、主函数(1分钟解剖室)
### Java代码结构简介 掌握Java代码结构如同拥有程序世界的建筑蓝图,类、方法和主函数构成“黄金三角”。类是独立的容器,承载成员变量和方法;方法实现特定功能,参数控制输入环境;主函数是程序入口。常见错误包括类名与文件名不匹配、忘记static修饰符和花括号未闭合。通过实战案例学习电商系统、游戏角色控制和物联网设备监控,理解类的作用、方法类型和主函数任务,避免典型错误,逐步提升编程能力。 **脑图速记法**:类如太空站,方法即舱段;main是发射台,static不能换;文件名对仗,括号要成双;参数是坐标,void不返航。
28 5
|
6天前
|
Oracle Java 关系型数据库
课时37:综合实战:数据表与简单Java类映射转换
今天我分享的是数据表与简单 Java 类映射转换,主要分为以下四部分。 1. 映射关系基础 2. 映射步骤方法 3. 项目对象配置 4. 数据获取与调试
|
1月前
|
存储 Java
Java中判断一个对象是否是空内容
在 Java 中,不同类型的对象其“空内容”的定义和判断方式各异。对于基本数据类型的包装类,空指对象引用为 null;字符串的空包括 null、长度为 0 或仅含空白字符,可通过 length() 和 trim() 判断;集合类通过 isEmpty() 方法检查是否无元素;数组的空则指引用为 null 或长度为 0。
|
1月前
|
安全 Java 编译器
JAVA泛型类的使用(二)
接上一篇继续介绍Java泛型的高级特性。3. **编译时类型检查**:尽管运行时发生类型擦除,编译器会在编译阶段进行严格类型检查,并允许通过`extends`关键字对类型参数进行约束,确保类型安全。4. **桥方法**:为保证多态性,编译器会生成桥方法以处理类型擦除带来的问题。5. **运行时获取泛型信息**:虽然泛型信息在运行时被擦除,但可通过反射机制部分恢复这些信息,例如使用`ParameterizedType`来获取泛型参数的实际类型。
|
1月前
|
安全 Java 编译器
JAVA泛型类的使用(一)
Java 泛型类是 JDK 5.0 引入的重要特性,提供编译时类型安全检测,增强代码可读性和可维护性。通过定义泛型类如 `Box<T>`,允许使用类型参数。其核心原理是类型擦除,即编译时将泛型类型替换为边界类型(通常是 Object),确保与旧版本兼容并优化性能。例如,`Box<T>` 编译后变为 `Box<Object>`,从而实现无缝交互和减少内存开销。
|
2月前
|
Java
Java 面向对象编程的三大法宝:封装、继承与多态
本文介绍了Java面向对象编程中的三大核心概念:封装、继承和多态。
159 15
|
7月前
|
Java 程序员
Java中的继承和多态:理解面向对象编程的核心概念
【8月更文挑战第22天】在Java的世界中,继承和多态不仅仅是编程技巧,它们是构建可维护、可扩展软件架构的基石。通过本文,我们将深入探讨这两个概念,并揭示它们如何共同作用于面向对象编程(OOP)的实践之中。你将了解继承如何简化代码重用,以及多态如何为程序提供灵活性和扩展性。让我们启程,探索Java语言中这些强大特性的秘密。
|
5月前
|
Java
java继承和多态详解
java继承和多态详解
74 5

热门文章

最新文章