Java面向对象—封装、继承、多态
在对面向对象的特征进行分析之前,先让我们来了解一下什么是面向对象。
面向对象与面向过程:
面向过程:是一种以过程为中心的编程思想,面向过程的编程语言包括:C、Fortran、Pascal等。
面向过程,就是将要解决的问题按照步骤一步一步的进行执行,举个简单的例子,如果我们现在要完成一个银行取钱的操作,那么利用面向过程的设计思想,解决这个问题分为以下几步:
(1)把银行卡插入ATM机
(2)输入密码
(3)查询余额
(4)输入取钱金额
(5)取钱
(6)把卡拔出来
如此可见,面向过程就是将解决问题的方法按照步骤一步一步完成。而生活中绝大多数的事情并不是那么的简单,当问题规模变大的时候,面向过程这种思想就不够用了,这是后就需要使用面向对象的思想。所谓万物皆对象,对大多数的事物都可以看作是一个对象,而每个对象都有自己的属性和行为,以对象为中心,就是将对象的属性和行为通过代码表达出来,进而解决问题。
同样是上面那个例子,这里可以将ATM机作为对象,它有自己的属性:ATM机内的钞票数、它所属的银行等。它也有自己的方法:余额查询、存钱、取钱等。同样,取钱的人也有自己的属性和方法。
面向对象有的三大特征:封装、继承、多态。
封装:
所谓封装,就是把对象的属性和操作结合为一个独立的整体,并尽可能隐藏对象的内部实现细节 。要访问该类的代码和数据,必须通过特定的接口控制。
让我们看看具体的代码:这里结合菜鸟教材:
class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
上面的例子中Person类有两个私有的属性name和age,要想访问这两个属性,则需要调用Person提供的public方法getName()和getAge(),setName()和setAge(),通常情况下,这些方法被称为getter和setter方法。
封装的优点有:
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员变量进行更精确的控制。隐藏信息,实现细节。
继承
百度百科对继承的解释为:继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸引已有的类的数据属性和行为,并能扩展新的能力。
举个例子:动物拥有眼睛、鼻子、嘴巴等属性,还有基本的走、跑。而狗作为动物这个类的派生类,在继承了动物这个类之后,还可以拥有自己的叫的方法。这个过程就可以视为继承。子类在实现时只需要关系自己新增的成员和自己拥有的方法即可。
继承的好处:提高代码的复用性、让类与类之间产生了联系,是多态的前提。
class animal {
private String name;
private int age;
public void walk(){
System.out.println("动物的走");
}
}
class person extends animal {
@Override
public void walk() {
super.walk();
System.out.println("人类的走");
}
}
上面是一个简单的例子,人类继承了动物的属性和walk()方法,同时它也可以重写父类的方法。
这里super和this:
super:是一个关键字,代表父类的存储空间标识(可以理解为父类的引用)
this:代表对象的引用(谁调用就代表谁)
使用场景:当子类想要调用父类的方法时,可以使用super。
final关键字:用来修饰变量,成员方法以及类。
> 修饰变量或字段,表示常量(不能被修改)
>
> 修饰类,表示该类不能被继承
>
> 修饰方法,表示方法不能被重写
public static void main(String[] args) {
animal a = new animal();
a.walk();
person p = new person();
p.walk();
}
执行以上代码可以得到:
> 动物的走
> 动物的走
> 人类的走
子类父类元素的访问规则:
子类访问父类成员:优先访问子类自身成员,若子类无此成员则访问父类。如果两者同名,则优先访问子类成员,即将父类的同名变量隐藏。(注意访问权限修饰符)
子类父类方法访问规则:
通过子类访问成员方法,优先看子类是否有该方法,如果有则访问自己的方法,没有则访问父类方法。
通过子类访问与父类同名方法时,如果子类和父类方法的参数列表不同则构成重写,根据调用方法传递的参数选择合适的方法访问
如果子类和父类同名方法的原型一致,则只能访问到子类的
构造方法及顺序
构造哪个类,就调用哪个类的构造方法。构造时先调用基类的构造方法,再调用子类的
public class Demo1 {
public static void main(String[] args) {
person p = new person();
}
}
class animal {
private String name;
private int age;
public void walk(){
System.out.println("动物的走");
}
public animal() {
System.out.println("animal构造函数");
}
}
class person extends animal {
public person() {
System.out.println("person构造函数");
}
@Override
public void walk() {
System.out.println("人类的走");
}
}
执行结果为
> animal构造函数
> person构造函数
在子类构造方法中,并没有写任何关于基类构造的代码,但是在构造子类对象时,先执行基类的构造方法,然后执行子类的构造方法。
此时要注意:
> 若父类显示定义无参或者默认的构造方法,在子类构造方法的第一行默认有隐含的super调用,即调用基类的构造方法。
>
> 如果父类的构造方法是带有参数的,此时编译器不会给子类生成默认的构造方法,此时需要用户在子类中显示定义构造方法,并在子类构造方法中选取合适的父类构造方法调用
>
> 在子类构造方法中,super(...)调用父类构造时,必须是子类构造方法中的第一条语句
>
> super(...)只能在子类的构造方法中出现一次,并不能和this同时出现
>
>
public class Demo1 {
public static void main(String[] args) {
person p = new person();
}
}
class animal {
private String name;
private int age;
public void walk(){
System.out.println("动物的走");
}
public animal() {
System.out.println("animal构造函数");
}
{
System.out.println("animal的实例代码块");
}
static {
System.out.println("父类静态代码块");
}
}
class person extends animal {
public person() {
System.out.println("person构造函数");
}
@Override
public void walk() {
System.out.println("人类的走");
}
{
System.out.println("person的实例代码块");
}
static{
System.out.println("子类静态代码块");
}
}
> 父类静态代码块
> 子类静态代码块
> animal的实例代码块
> animal构造函数
> person的实例代码块
> person构造函数
父类和子类的静态代码块最早执行,且成先后顺序。
父类的实例化代码块和构造函数接着执行。
最后是子类的实例化代码块和构造函数的执行。
Java继承方式
Java不支持多继承(支持实现多个接口)
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/java/281024.html