【Java面试题】JavaSE基础之Java面向对象

1、Java面向对象

1.1、什么是面向对象?

面向对象简称OO(Object Oriented),20世纪80年代有了面向对象分析(OOA)、面向对象设计(OOD)、面向对象程序设计(OOP)等新的系统开发方式模型的研究。

对于语言来说,一切皆是对象。把现实世界中的对象抽象地体现在编程世界中。一个对象代表了某个具体的操作。一个个对象最终组成了一个完整的设计,这些对象可以是独立的存在,也可以是从别的对象继承过来的,对象之间相互作用传递信息,共同实现程序开发。

1.2、对象的概念

Java是面向对象的编程语言,对象就是面向对象程序设计的核心。所谓对象就是现实世界中的实体,对象与实体是一一对应的,也就是说显示世界中每一个实体都是一个对象,它是一种具体的概念。对象的特点:

  • 对象具有属性和行为
  • 对象具有变化的状态
  • 对象具有唯一性
  • 对象都是某个类别的实例
  • 一切皆为对象,现实世界中所有事务都可以视为对象

1.3、面向对象和面向过程的关系和区别

面向对象面向过程
概念一种基于面向过程的新编程思想,顾名思义该思想就是站在对象的角度思考问题的,我们把多个功能合理放到不同的对象里,强调的是具备某些功能的对象。具备某些功能的实体,称为对象。面向对象最小的程序单元是:。面向对象更加符合常规的思维方式,稳定性好,可重用性强,易于开发大型软件产品,有良好的可维护性。一种较早的编程思想,顾名思义该思想是站在过程的角度思考问题的,强调的是功能的行为,功能的执行过程,即先后顺序,而每一个功能我们都使用函数(类似于方法)把这些步骤一步一步的实现,使用的时候依次调用函数即可。
  • 面向过程的设计:

    最小的程序单元是函数,每个函数负责完成某一个功能,用于接收输入数据,函数对输入的数据进行处理,然后输出结果数据,整个软件系统由一个个的函数组成,其中作为程序入口的函数称之为主函数,主函数依次调用其他函数,普通函数之间可以相互调用,从而实现整个系统功能。

  • 面向过程的缺陷:

    是采用自上而下的设计模式,在设计阶段就需要考虑每一个模块应该分解成哪些子模块,每一个子模块又细分为更小的子模块,如此类推,直到将模块细化为一个个函数。

  • 面向过程存在的问题:

    设计不够直观,与人类的思维习惯不一致,系统软件适应性差,可拓展性差,可维护性低。

面向过程最大的问题就在于随着系统的膨胀,面向过程将无法应付,最终导致系统的崩溃。为了解决这一危机,我们提出了面向对象思想。

1.4 、面向对象三大核心特性

面向对象开发模式更有利于人们开拓思维,在具体的开发过程中便于程序的划分,方便程序员分工合作,提高开发效率。

该开发模式之所以使程序设计更加完善强大,主要是因为面向对象具有继承封装多态三个核心特性。

1.4.1、继承

继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。
在这里插入图片描述
继承的特性:

  • 子类拥有父类中非private的属性和方法
  • 子类可以用自己的属性和方法,即子类可以对父类进行扩展
  • 子类可以用自己的方式实现父类的方法
  • Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,例如B类继承A类,C类继承B类,所以按照关系就是B类是C类的父类,A类是B类的父类,这是Java继承区别与C++继承的一个特性
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系紧密,代码独立性越差)

生活中的继承:
在这里插入图片描述
兔子和羊都属于食草动物,狮子和老虎属于食肉动物。
食草动物和食肉动物又是属于动物类。

由上述关系图可知,继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例和方法,或者说子类从父类继承方法,使得子类具有父类相同的方法。

所以继承关系需要符合的关系是:is-a,父类更通用,子类更具体。

虽然实操动物和食肉动物都属于动物,但是两者的属性和行为是有差别,所以子类会具有父类的一般特性也会有自身独有的一些特性。

举个栗子:
人类有一些属性姓名和年龄,还有一些特征,会吃、会睡觉、会自我介绍。
然而人类还有种类之分,无论是哪种人类,都具备这些共同的特征,所以我们就可以把这些功共同的特征提取出来,放在一个父类中(也就是超类或者基类),然后由各种类的人去继承人类这个父类,从而实现继承的特性。

Prople类

public class People {

    private String name;
    private int age;

    public People(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat(){
        System.out.println(name + "正在吃!");
    }

    public void sleep(){
        System.out.println(name + "正在睡!");
    }

    public void sayHello(){
        System.out.println("大家好,我是" + name + ",今年" + age + "岁了!");
    }
}

Chinese类

public class Chinese extends People{

    private String name;

    public Chinese(String name, int age) {
        super(name, age);
        this.name = name;
    }

    public void color(){
        System.out.println(name + "是黄种人!");
    }

    public static void main(String[] args) {
        Chinese chinese = new Chinese("中国人",21);
        chinese.eat();
        chinese.sleep();
        chinese.sayHello();
        chinese.color();
    }
}

运行结果:
中国人正在吃!
中国人正在睡!
大家好,我是中国人,今年21岁了!
中国人是黄种人!(此处是子类Chinese自身延展的特征,在父类中并没有定义)

American类

public class American extends People {

    private String name;

    public American(String name, int age) {
        super(name, age);
        this.name = name;
    }

    public void color(){
        System.out.println(name + "是白种人!");
    }

    public static void main(String[] args) {
        American american = new American("美国人",20);
        american.eat();
        american.sleep();
        american.sayHello();
        american.color();
    }
}

运行结果:
美国人正在吃!
美国人正在睡!
大家好,我是美国人,今年20岁了!
美国人是白种人!(此处是子类Chinese自身延展的特征,在父类中并没有定义)

1.4.2、封装

通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。该机制保证了程序和数据都不受外部干扰且不被误用,封装的目的在于保护信息,使用封装有以下优点:

  • 良好的封装能够减少耦合。
  • 类内部的结构可以自由修改。
  • 可以对成员变量进行更加精确的控制。
  • 隐藏信息,实现细节。
  • 在面向对象程序设计方法中,封装(Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
  • 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
  • 要访问该类的代码和数据,必须通过严格的接口控制。
  • 封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段
  • 适当的封装可以让程序代码更加容易理解和维护,也增强了程序代码的安全性。

在这里插入图片描述
新建Animal类:
(1)、修改属性的可见性来限制对属性的访问(一般限制为private),

public class Animal {
    private String name;
    private int age;
}

这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。

(2)、对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问

public class Animal {
    
    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;
    }
}

(3)、通过测试,这些私有属性如何被访问和设置属性值的

public static void main(String[] args) {

        Animal animal = new Animal();
        animal.setName("二狗子");
        animal.setAge(2);
        System.out.println("name:" + animal.getName() + ";age:" + animal.getAge());
}
    
运行结果:
name:二狗子;age:2

1.4.3、多态

多态性是指允许不同子类型的对象对同一消息做出不同的响应。简单的说就是同样的对象引用调用同样的方法,但是却做了不同的事情;也可以理解为同一个行为具有多个不同的表现形式或形态的能力。 多态性又分为编译时多态运行时多态。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性就可以理解为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对于A系统来说都是透明的。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,

多态的优点:

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化行

多态存在的三个必要条件:

  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();
    在这里插入图片描述
    上述实例很明显的表现出了多态性的两大特性,方法重写和父类对象指向子类引用,也就是说同样是打印机(父类)分别指向了不同的两个不同的打印机实例(子类),同一个事件作用在不同的子类实例上就产生了不同的结果。

虚函数:
虚函数的存在是为了多态,Java中其实没有虚函数的概念,它的普通函数就相当于C++中的虚函数,动态绑定就是Java的默认行为,如果Java中不希望某个函数具有虚函数特性,可以加上final关键字让其变成非虚函数。

举个栗子:
Employee类

public class Employee {

    private String name;
    private String address;

    public Employee(String name, String address) {
        System.out.println("Employee 构造函数");
        this.name = name;
        this.address = address;
    }
    public void mailCheck() {
        System.out.println("邮寄支票给: " + this.name
                + " " + this.address);
    }

    public String getName() {
        return name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String newAddress) {
        address = newAddress;
    }
}

Salary类

public class Salary extends Employee {

    private double salary;

    public Salary(String name, String address,double salary) {
        super(name, address);
        this.salary = salary;   //或者setSalary(salary);
    }

    public double getSalary() {
        return salary;
    }
    public void setSalary(double newSalary) {
        if(newSalary >= 0.0) {
            salary = newSalary;
        }
    }
    public double computePay() {
        System.out.println("计算工资,付给:" + getName());
        return salary/52;
    }

    public void mailCheck() {
        System.out.println("Salary 类的 mailCheck 方法 ");
        System.out.println("邮寄支票给:" + getName() + " ,工资为:" + salary);
    }
}

测试

public static void main(String[] args) {
        Salary s = new Salary("员工 A", "北京", 3600.00);
        s.mailCheck();

        System.out.println("------------------------------------");

        Employee e = new Salary("员工 B", "上海", 2400.00);
        e.mailCheck();


}

运行结果:
Employee 构造函数
Salary 类的 mailCheck 方法 
邮寄支票给:员工 A ,工资为:3600.0
------------------------------------
Employee 构造函数
Salary 类的 mailCheck 方法 
邮寄支票给:员工 B ,工资为:2400.0

(4)抽象: 抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

注意:默认情况下面向对象有3大特性,封装、继承和多态,如果面试官问让说出4面向对象的4大特性,那么就可以把抽象特性加上了。

1.5、访问权限修饰符的区别

修饰符当前类同包子类其他包(类)
public
protectedX
default(默认不写)XX
privateXXX
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一宿君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值