Java面试题JavaSE基础之Java面向对象
Posted 一宿君
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java面试题JavaSE基础之Java面向对象相关的知识,希望对你有一定的参考价值。
JavaSE基础
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 | √ | √ | √ | √ |
protected | √ | √ | √ | X |
default(默认不写) | √ | √ | X | X |
private | √ | X | X | X |
以上是关于Java面试题JavaSE基础之Java面向对象的主要内容,如果未能解决你的问题,请参考以下文章
Java最最最最最基础的面试题之谈谈你对面向对象思想的理解(含视频讲解)-建议收藏!!!