🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎大家关注&&收藏!持续更新中,up!up!up!!
文章目录
前言
在上一节中,我们学习了Java中的基本数据类型和运算符。在本节中,我们将深入了解Java面向对象编程的两个核心概念:方法和继承。方法和继承是Java编程中非常重要的概念,掌握它们可以让我们编写出更加清晰、可维护的代码。
摘要
本节将介绍Java中的方法和继承的概念,以及如何在代码中使用它们。我们将深入了解方法的定义、参数和返回值,以及继承的概念和使用。我们还将讨论如何编写可维护的代码库,以充分利用方法和继承的优势。
正文
方法
如何定义方法?
方法是指一组语句的有序集合,它们使用一些输入(参数)来执行一些操作,并产生一个输出(返回值)。在Java中,方法可以用来实现某些特定的任务或计算。
定义一个方法需要使用关键字public
、private
或protected
,它们表示方法的可见性。通常,我们使用public
来定义方法,以便其他类可以使用它们。
下面是一个例子:
public int add(int a, int b) {
int result = a + b;
return result;
}
这个方法名为add
,有两个参数a
和b
,返回类型为int
。在方法体中,我们定义了一个变量result
,并将a
和b
相加,最后返回结果。
方法的定义与作用
在Java中,方法(Method)是执行特定任务的代码块的集合,它们是面向对象编程中实现封装和抽象的关键。方法允许我们将复杂的逻辑分解成更小、更易于管理的部分。
基本组成部分
-
访问修饰符:如
public
、private
、protected
,它们定义了方法的可见性。public
:方法可以被任何其他类访问。private
:方法只能在其所在的类内部访问。protected
:方法可以被同一个包中的类或其子类访问。
-
返回类型:指明方法执行完毕后返回的数据类型。可以是基本数据类型(如
int
、double
等)或对象类型。 -
方法名:方法的标识符,遵循Java的命名规范。
-
参数列表:方法可以有零个或多个参数,参数是传递给方法的输入值,用于方法内部的计算或操作。
-
方法体:包含实际执行的代码,是方法的主要逻辑部分。
-
返回语句:对于有返回类型的方法是必需的,用于返回方法的执行结果。
作用
- 代码复用:通过将功能封装在方法中,可以在不同的地方重复调用,避免代码重复。
- 逻辑抽象:方法提供了一种将复杂逻辑抽象化的方式,使得代码更加清晰易懂。
- 模块化:方法的使用增强了程序的模块化,有助于维护和扩展。
分类
- 无参方法:不接收任何参数的方法。
- 有参方法:接收一个或多个参数的方法。
- 构造方法:特殊类型的方法,用于初始化新对象的状态,与类名相同,无返回类型。
- 静态方法:属于类的而不是单个对象的方法,可以通过类名直接调用。
重载(Overloading)
Java允许在一个类中定义多个同名方法,只要它们的参数列表不同(参数的数量或类型不同)。这被称为方法的重载。
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
// 这是方法的重载
}
在这个例子中,Calculator
类有两个add
方法,一个接受两个int
类型的参数,另一个接受两个double
类型的参数。Java编译器会根据调用时提供的参数类型来确定使用哪个方法。
这段Java代码展示了一个名为Calculator
的简单类,它演示了方法重载(Overloading)的概念。方法重载是Java中的一个特性,允许一个类中存在多个同名方法,只要它们的参数列表不同。在这个例子中,Calculator
类有两个名为add
的方法,但它们接受不同类型的参数:
- 第一个
add
方法接受两个int
类型的参数,并返回它们的和,也是int
类型。 - 第二个
add
方法接受两个double
类型的参数,并返回它们的和,是double
类型。
方法重载的好处:
- 提高代码的可读性:通过使用相同的名字但不同参数类型的方法,可以使代码更容易理解和维护。
- 增强类的功能性:允许类提供多种操作相同数据类型但行为略有不同的方法。
- 类型安全:编译器会根据方法调用时提供的参数自动选择合适的重载方法,这减少了类型转换的错误。
方法重载的规则:
- 参数的数量不同:可以定义接受不同数量参数的同名方法。
- 参数的类型不同:可以定义接受相同数量但不同类型的参数的同名方法。
- 返回类型的不同不是决定因素:仅有不同的返回类型不足以构成方法重载,因为Java编译器在方法调用时会根据参数确定使用哪个方法,而不是返回类型。
示例说明:
当创建Calculator
类的实例并调用add
方法时,如果传入的是整数,编译器会选择第一个add
方法;如果传入的是浮点数,编译器会选择第二个add
方法。例如:
Calculator calc = new Calculator();
int sumInt = calc.add(5, 10); // 调用 int add(int a, int b)
double sumDouble = calc.add(5.0, 10.5); // 调用 double add(double a, double b)
在这个示例中,sumInt
将存储整数和的结果,类型为int
;而sumDouble
将存储浮点数和的结果,类型为double
。这展示了方法重载如何使代码更加灵活和表达性强。
覆盖(Overriding)
当子类继承父类时,它可以提供自己的实现来覆盖父类中的方法。这要求方法名、返回类型和参数列表与父类中的方法完全一致。
详解
覆盖是面向对象编程中的一个重要概念,它允许子类改变从父类继承来的方法的行为。这是多态性的一种表现,多态性是指允许不同类的对象对同一消息做出响应,但响应的方式不同,取决于对象的实际类型。
覆盖的条件:
- 方法名、返回类型和参数列表必须完全一致:子类覆盖的方法必须具有与父类中被覆盖方法相同的名称、返回类型和参数列表。
- 访问权限不能更严格:子类不能缩小父类方法的访问范围。例如,如果父类中的方法是
public
,则子类覆盖的方法不能声明为private
或protected
。 - 异常声明:如果父类方法声明了异常,子类覆盖的方法可以声明相同的异常或其子集,但不能声明新的检查型异常或更广泛的异常。
@Override
注解:虽然不是覆盖的必要条件,但使用@Override
注解可以明确表示方法意图覆盖父类中的方法,如果不符合覆盖条件,编译器将报错。
覆盖的目的:
- 改变行为:子类可以根据需要改变继承来的方法的行为。
- 扩展功能:在不修改原有代码的基础上,通过覆盖方法来扩展或改进功能。
- 实现多态性:通过覆盖方法,子类可以提供特定于其类型的对象行为。
覆盖与重载的区别:
- 重载(Overloading)发生在同一个类中,涉及多个同名方法,但参数列表不同。
- 覆盖(Overriding)发生在父子类之间,涉及子类提供与父类中具有相同名称和参数列表的方法的不同实现。
示例:
class Animal {
public void sound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks");
}
}
public class TestOverriding {
public static void main(String[] args) {
Animal myAnimal = new Animal();
Animal myDog = new Dog();
myAnimal.sound(); // 输出 Animal makes a sound
myDog.sound(); // 输出 Dog barks
}
}
在这个示例中,Dog
类继承自Animal
类,并覆盖了sound
方法。当我们创建Dog
类的实例并调用sound
方法时,将执行Dog
类中提供的实现,输出"Dog barks"。这展示了多态性,即使myDog
被声明为Animal
类型,由于覆盖,调用的仍然是Dog
类的sound
方法。
结论:
覆盖是实现多态性的强大工具,它允许子类根据其特定需求调整或改变继承的方法行为。正确使用覆盖可以提高代码的灵活性和可维护性。
小结:
方法在Java编程中扮演着至关重要的角色。它们不仅帮助我们组织和重用代码,还提高了代码的可读性和可维护性。理解方法的基本概念和使用方式对于成为一名优秀的Java程序员至关重要。
参数和返回值
方法可以使用参数来获取输入,使用返回值来输出结果。参数和返回值都可以是Java中的任何数据类型,包括基本数据类型和自定义类型。
下面是一个例子:
public Student findStudentById(int id) {
// 在数据库中查找id对应的学生记录
// 如果找到,返回学生对象;否则,返回null
}
这个方法名为findStudentById
,有一个参数id
,其类型为int
。方法返回类型为Student
,即返回一个学生对象。在方法体中,我们可以使用输入的id
在数据库中查找对应的学生记录,并返回相应的学生对象。
方法重载
在Java中,方法重载(Method Overloading)指定义两个或多个相同名字但不同参数的方法。方法重载可以使程序更加灵活,可以根据不同的情况选择不同的方法。
下面是一个例子:
public int add(int a, int b) {
int result = a + b;
return result;
}
public double add(double a, double b) {
double result = a + b;
return result;
}
这里定义了两个名字相同但参数类型不同的方法add
。第一个方法接受两个整数作为参数,返回一个整数;第二个方法接受两个浮点数作为参数,返回一个浮点数。在调用方法add
时,编译器会自动根据传入的参数类型选择正确的方法。
继承
定义继承
在面向对象编程中,继承是指一个类可以继承另一个类的属性和方法。继承可以使代码更加简洁、可读性更强,同时也可以提高代码的重用性。
在Java中,可以使用关键字extends
来实现继承。下面是一个例子:
public class Animal {
public void eat() {
System.out.println("Animal eat something");
}
}
public class Cat extends Animal {
public void meow() {
System.out.println("Cat meow");
}
}
在这个例子中,类Cat
继承了类Animal
的属性和方法。类Cat
可以访问Animal
中的所有public
方法,包括方法eat
。类Cat
还定义了一个自己的方法meow
,它可以在类中使用。
继承的优点
继承的主要优点之一是代码重用性。当两个类具有相似的属性和方法时,可以使用继承来避免代码重复。另一个优点是更好的可读性和可维护性。通过继承,可以更清晰地组织代码,使之易于理解和修改。
子类和父类
在继承关系中,继承属性和方法的类称为子类,被继承属性和方法的类称为父类。子类可以重写父类的方法,也可以定义自己的属性和方法。
下面是一个例子:
public class Animal {
public void eat() {
System.out.println("Animal eat something");
}
}
public class Cat extends Animal {
public void eat() {
System.out.println("Cat eat fish");
}
public void meow() {
System.out.println("Cat meow");
}
}
在这个例子中,类Cat
重写了父类Animal
中的方法eat
。在调用Cat
对象的eat
方法时,将输出Cat eat fish
。
代码解析:
这段Java代码演示了面向对象编程中的继承和方法覆盖(Overriding)的概念。代码中定义了两个类:Animal
和Cat
,其中Cat
是Animal
的子类。
代码解析:
-
Animal 类:
Animal
类代表了一个动物的通用概念。- 它有一个名为
eat
的方法,当调用时,会打印出"Animal eat something"
。这表示所有动物都会吃东西,但具体吃什么在这个类中没有具体定义。
-
Cat 类:
Cat
类继承自Animal
类,表示猫是动物的一种。Cat
类覆盖了eat
方法,提供了具体的实现:当调用Cat
对象的eat
方法时,会打印出"Cat eat fish"
。这展示了多态性,即使Cat
对象被声明为Animal
类型,调用的也是Cat
类中覆盖的eat
方法。Cat
类还添加了一个新的方法meow
,用来表示猫的叫声,打印出"Cat meow"
。
继承的特点:
- 继承属性:
Cat
类继承了Animal
类的所有属性和方法,包括eat
方法。 - 方法覆盖:
Cat
类提供了eat
方法的新实现,覆盖了父类Animal
的eat
方法。 - 新增方法:
Cat
类可以添加自己特有的方法,如meow
,这些方法在父类中不存在。
多态性:
- 多态性允许我们使用父类类型的引用来调用子类覆盖的方法。在上面的代码中,如果有一个
Animal
类型的引用指向一个Cat
对象,调用eat
方法将执行Cat
类的实现。
示例用法:
public class TestAnimal {
public static void main(String[] args) {
Animal myAnimal = new Animal(); // Animal 类型的对象
Animal myCat = new Cat(); // Cat 类型的对象,但声明为 Animal 类型
myAnimal.eat(); // 输出 Animal eat something
myCat.eat(); // 输出 Cat eat fish,展示了多态性
Cat myCatRef = (Cat) myAnimal; // 向下转型,实际类型是 Animal,这里会抛出 ClassCastException
myCatRef.meow(); // 输出 Cat meow
}
}
在这个示例中,我们创建了Animal
和Cat
类型的对象,并调用了它们的eat
方法。myCat
对象虽然声明为Animal
类型,但由于多态性,调用的eat
方法是Cat
类中覆盖的方法。此外,尝试将Animal
类型的对象向下转型为Cat
类型并调用meow
方法会导致ClassCastException
,因为Animal
类中没有meow
方法。
代码解析:
这段Java代码演示了面向对象编程中的一些基本概念,包括类继承、多态性以及类型转换时可能遇到的问题。下面是代码的逐行解析:
-
public class TestAnimal {
:定义了一个名为TestAnimal
的公共类。 -
public static void main(String[] args) {
:定义了main
方法,这是Java程序的入口点,args
是一个字符串数组,用于传递命令行参数。 -
Animal myAnimal = new Animal();
:创建了一个Animal
类的对象myAnimal
。这里使用了Animal
作为引用类型,但实际创建的是Animal
类的一个实例。 -
Animal myCat = new Cat();
:创建了一个Cat
类的对象myCat
,但声明为Animal
类型。这里演示了多态性,Cat
类可能是Animal
类的子类,因此可以向上转型为Animal
类型。 -
myAnimal.eat();
:调用myAnimal
对象的eat
方法。由于myAnimal
是Animal
类型,所以调用的是Animal
类中的eat
方法,输出"Animal eat something"。 -
myCat.eat();
:调用myCat
对象的eat
方法。尽管myCat
被声明为Animal
类型,但实际类型是Cat
,所以这里展示了多态性,调用的是Cat
类中的eat
方法,输出"Cat eat fish"。 -
Cat myCatRef = (Cat) myAnimal;
:尝试将myAnimal
向下转型为Cat
类型,并赋值给myCatRef
。这里会抛出ClassCastException
,因为myAnimal
的实际类型是Animal
,而不是Cat
。 -
myCatRef.meow();
:这行代码永远不会执行,因为上一行代码已经抛出了异常。
总结来说,这段代码演示了多态性,即同一个方法调用可以有不同的行为,取决于对象的实际类型。同时,它也展示了类型转换时可能遇到的问题,即向下转型时需要确保对象的实际类型与目标类型兼容,否则会抛出异常。
编写可维护的代码库
编写可维护的代码库是Java编程中非常重要的一部分。下面我们将介绍五个原则,以帮助我们编写清晰、健壮、可维护的代码库。
单一职责原则
每个类都应该有自己的职责,即只做一件事情。这样可以使代码更加清晰,易于理解和修改。如果一个类承担了太多的职责,那么它就会变得复杂、难以维护。
开闭原则
开闭原则指一个类应该对扩展开放,对修改关闭。这意味着我们应该尽可能避免修改现有的代码,而是通过增加新的代码来扩展功能。
依赖倒置原则
依赖倒置原则指高层模块不应该依赖低层模块,两个都应该依赖其抽象。这意味着我们应该尽可能使用接口或抽象类来定义类之间的依赖关系,从而使得系统更加灵活、可扩展。
接口隔离原则
接口隔离原则指一个类不应该依赖它不需要的接口。这意味着我们应该尽可能将接口细化,从而避免类对不必要的接口产生依赖。
迪米特法则
迪米特法则(也称为最小知识原则)指一个类不应该知道太多关于其他类的信息。这意味着一个类应该只与直接相邻的类进行交互,而不应该与其它间接的类进行交互。
迪米特法则强调了类之间的松耦合(Loose Coupling),即类应该尽量减少对其他类的依赖,减少类之间的相互影响,从而提高代码的可维护性、可扩展性和可复用性。
迪米特法则可以帮助我们设计更加灵活、可维护的系统,同时也可以提高系统的性能和可靠性。在实际开发中,我们应该尽可能地遵守迪米特法则,减少类之间的耦合度,提高系统的可维护性和可扩展性。
总结
本文深入探讨了Java面向对象编程的核心概念:方法和继承。面向对象编程是一种编程范式,它将现实世界中的实体抽象为对象,通过对象之间的交互来实现程序的功能。Java作为一种面向对象的编程语言,提供了丰富的特性来支持这种编程方式。
方法
方法在Java中扮演着至关重要的角色。它是一组执行特定任务的语句集合,可以通过参数接收输入,并可通过返回值输出结果。方法的定义包括访问修饰符、返回类型、方法名、参数列表和方法体。方法的重载允许我们根据参数的不同来定义同名的方法,增强了代码的灵活性和可读性。
继承
继承是面向对象编程的另一个基石,它允许新创建的类(子类)继承现有类(父类)的属性和方法。这不仅提高了代码的重用性,还增强了代码的组织性和可维护性。子类可以覆盖父类的方法,以提供特定的行为,这是多态性的一种表现。
多态性
多态性是面向对象编程的一个重要特性,它允许同一个接口接受不同的数据类型。在Java中,这通常通过方法重载和方法覆盖来实现。多态性使得代码更加灵活,能够以统一的方式处理不同类型的对象。
编写可维护的代码库
文章还介绍了如何编写可维护的代码库,包括单一职责原则、开闭原则、依赖倒置原则、接口隔离原则和迪米特法则。这些原则和法则帮助开发者设计出结构清晰、易于扩展和维护的系统。
小结
通过本文的学习,我们不仅掌握了Java中方法和继承的基本概念和用法,还理解了如何通过面向对象的原则来提高代码的质量和可维护性。面向对象编程不仅仅是一种编程技术,更是一种思考问题和解决问题的方式。通过将现实世界的问题分解为对象和方法,我们可以更加系统和高效地开发软件。
Java作为一门成熟的面向对象编程语言,提供了丰富的特性来支持面向对象的设计和开发。掌握这些特性和原则,将有助于我们编写出更加优雅、健壮和可维护的代码。随着技术的不断进步和编程语言的不断发展,面向对象编程的概念和实践将继续演进,但其核心理念——将复杂问题分解为更小、更易于管理的部分——将始终是软件开发中的宝贵财富。
最后,bug菌的专栏「滚雪球学Java」为Java学习者提供了一个系统化的学习路径,通过学习这个专栏,可以快速掌握Java编程的基础知识和高级特性,为成为一名优秀的Java程序员打下坚实的基础。同时,bug菌提供的丰富学习资源,如面试题、电子书籍和简历模板,也为学习者提供了额外的帮助和支持。
附录源码
如上涉及所有源码均已上传同步在「Gitee」,提供给同学们一对一参考学习,辅助你更迅速的掌握。
☀️建议/推荐你
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学Java」,bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门Java编程,就像滚雪球一样,越滚越大,指数级提升。
📣关于我
我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。