Java面向对象三大特征:封装、继承、多态
1.前沿:
由于最近又重新学习了一遍javaSE的基础知识,所以也相对来说,比较理解java面向对象的三大特性以及他们的用法。这对于以后的java面向对象编程有很大的帮助,也可以更好的跨越面向过程的这道槛。(其实这是更好的运用对象, 然后把属性和行为方法分开)。
2.封装
2.1封装性
-
对象的封装性
- 封装的定义: 隐藏类内部实现的细节,对外提供统一的操作方法
- 封装的好处:
- 从类的本身,保护变量不被外部随机更改
- 从调用者角度考虑,不用了解细节,简化操作步骤
-
在程序中如何体现封装性:
private修饰的方法或者变量,仅仅在本类有效、
public修饰的方法或者变量,可以在外部类调用、或者是外包
protected受保护的变量或者方法, 可以在本包调用。 变量没声明类型,默认是protect
访问范围:public > protected > private
对于单个类的分装:对于成员变量,声明成私有
对方法的封装,如果是私有,仅限于在本类调用
对于构造方法,如果是私有的,外部不能直接new,必须有类的内部提供实例。
2.2封装的概念
高度概括:对属性的访问做限制
在java中类的封装性主要体现不能让外部随意修改一个成员变量的值,否则会引起很多逻辑上的错误,以及一些不可预知的错误。
在定义一个类的成员(包括变量和方法),使用private关键字说明这个成员的访问权限,只能被这个类的其他成员方法调用,而不能被其他的类中的方法所调用;为实现封装性,常将类的成员变量声明为private,再通过public的方法来对这个变量进行访问。对一个变量的操作,一般都有 读取和赋值操作,我们一般定义两个方法来实现这两种操作,即:getXxx()与setXxx();
一个类就是一个模块,我们应该让模块仅仅公开必须要让外界知道的内容,而隐藏其他的一切内容。再进行程序设计时,应尽量避免一个模块直接修改或操作另一个模块的数据,模块设计追求强内聚(许多功能尽量在类的内部独立完成,不让外面干预),弱耦合(提供给外部尽量少的方法调用)。
假设:有 Student 的学生类,里面有一个属性 age,年龄
public class Student {
int age;//年龄
}
问:这么访问属性有没有问题?
public static void main(String[] args) {
Student student = new Student();
student.age = -1;
}
答:显示生活中,年龄有999岁的吗?随意访问age属性,明显问题就出现了。
那么怎么解决这个问题?
2.3 private
Java*四种权限修饰符:public、private、protected、default(默认,什么都不写,也称为包访问权限)
- 而被 private 修饰的属性和方法的特点是:只有当前类才能访问。
解决上面的问题,首先使用private私有age属性:
public class Student {
private int age;//年龄
}
但是,此时如果是在其他类中使用一下代码,会出现无法访问的问题:
public static void main(String[] args) {
Student student = new Student();
student.age = 999;//这行代码报错,找不到age属性。因为该属性,被 private 修饰,所以只有Student 本类才能访问。
}
如果解决该问题?被 private 修饰的属性,怎么在外部类去修改该属性值?
2.4get和set方法
使用get和set方法是为了程序的封装,为了其它的类可以使用(设置set和获取get)该类的私有属性和方法。
public class Student {
private int age;//年龄
public int getAge() {
return age - 3;
}
public void setAge(int age) {
if (age<100&&age>0) {
this.age = age;
}else{
System.out.println("设置的age不合法");
this.age = 18;//如果设置非法年龄,自动设置age默认为18
}
}
}
这样就可以通过 public 的 get和set 方法,让外部类去访问 Student 私有的属性 age了。但访问受到了限制:
public static void main(String[] args) {
Student student = new Student();
student.setAge(999);
System.out.println("年龄为:"+student.getAge());
//控制台将输出:
//设置的age不合法
//年龄为:18
}
get 和 set 是为了程序的封装,封装是为了对 外部类访问本类属性和方法做限制。
2.5.静态static
-
在一个类中,为什么会出现静态的以下内容?
在程序中尽量避免多次实例化对象
-
静态代码模块:
- 在类多次实例化中,仅仅被调用一次
- 在静态代码模块中只能使用静态变量
- 静态代码模块执行顺序优先于构造方法
-
静态的变量:static int a =3;
静态变量在内存中只有一份地址拷贝(在内存中的地址是唯一的),各个类的实例或者是类名都可以共享它
静态的方法:使用类名直接调用,静态方法只能使用静态变量
2.6.代码块
代码块的种类:静态代码块、构造代码块、普通代码块
执行顺序:静态代码块—》构造代码块—》构造方法—–》普通方法—–》普通代码块
静态代码块:
- 功能:一般完成静态成员变量的初始化。
-
特点:
- 1.一般不能使用非静态的变量
2.静态的代码块只会加载一次,执行时机只有创建第一个对象的时候才会被执行,而且仅执行一次,如果不创建对象也不会执行
使用场景:如果想实现对静态成员变量的初始化赋值,可以通过静态代码块实现
构造代码块:
特点:
在构造方法之前执行
直接定义在类体中的代码块
- 每创建一个对象都会被执行一次
方法代码块:
特点:
- 方法中的代码块
- 只有调用方法的时候才会被执行的代码块
- 代码块中声明的变量外界无法访问
3.继承
3.1.继承的概念
继承的定义:
- 子类继承父类(父亲和孩子的关系)
- public class 子类 extends 父类{ }
- Java是一种纯粹的面向对象的语言,声明的所有类默认是继承Object类,它是所有的java类的根
- Java是单根继承关系(一脉相传),保证纯正的血统
- 子类会拥有父类的一些特征
3.2继承关系的特点
- 子类如果实例化,那么父类的构造方法会被先调用
- 子类可以调用父类的public方法,私有方法是不能调用的
- 子类的功能是在继承关系中最强大的
public class Person extends MonkeyMan{
public Person(){
System.out.println("人的构造方法");
}
public void clothes(){
System.out.println("人会穿衣服");
}
public void paint(){
System.out.println("人会画画");
}
public static void main(String[] args) {
Person person = new Person();
person.walk();
person.useTools();
}
}
3.3super关键字:
是使用在继承关系中,用于子类调用父类的构造方法和普通方法
- 构造方法调用方法:super(参数列表);
- 普通方法调用方法:super.方法名称;
- this 只能在本类使用 this(参数列表);
3.4方法的重写(overriding)和方法的重载(overloading)
方法的重载只能是在本类,方法的重写必须在子父类之间
-
方法的重写的好处是什么?
是对父类方法功能的完善,方法名必须一致,参数列表、返回值相同
父类不能调用子类的任何方法,因为父类对子类是无法预知的
3.5继承的一个原则(什么时候需要把代码设计成继承原则)
里氏替换原则:如果是两个类中有相同的方法,就抽象出一个类然后让这两个类继承它
继承的好处?
-
注意:同一包内的不同类要通过声明才能调用或者是静态类型的话直接类名加方法调用就行
继承的类直接继承父类方法除了main方法
4抽象类
4.1抽象类的概念
结构:public abstract class 类名{ }
-
抽象方法定义:public abstract 返回类型 方法名称(参数列表);
没有方法体(即{})
-
抽象类的定义:
- 如果在本类中有一些无法实现的功能,那么应该把本类声明成抽象类。
或者是父类对于自己的某一些方法,无法预知子类怎么使用,应该声明成抽象类
抽象类不一定有抽象的方法,但如果有抽象方法,必然是抽象类
- 抽象类如何使用:
- 如果子类继承父类(抽象类),父类中有抽象方法,子类如果没有完全实现父类的抽象方法,那么子类也会变成抽象类
- 抽象类不能实例化,即不能new,只能找子类实例化。没有子类就声明一个继承的子类
- 抽象类允许抽象方法和普通方法并存,原因是可以给子类提供普通的方法调用
-
抽象类在继承关系中的作用:
- 父类:抽象的方法不用自己实现,对子类有着引导约束的作用
子类:可以调用父类的非抽象方法,子类完成父类所有的抽象方法。
4.2.抽象类例子
public abstract class GrandFather{
private String schoolGrade;//文凭小学
private String skill;//技能种地
public void setSchoolGrade(String schoolGrade){
this.schoolGrade = schoolGrade;
}
public String getSchoolGrade(){
return schoolGrade;
}
public void setSkill(String skill){
this.skill = skill;
}
public String getSkill(){
return skill;
}
//本方法对于他不能使用
public abstract void gotoCollege();//抽象方法没有方法体
public abstract void planeMan();
}
public abstract class Father extends GrandFather{
private double money=10000000;
public Father(){
}
public double getMoney(){
return money;
}
public void gotoCollege(){
System.out.println("父亲考上大学!!!");
}
public void planeMan(){
System.out.println("父亲当上飞行员!!!");
}
public abstract void gotoMoon();
}
public class Son extends Father{
public void gotoMonn(){
System.out.println("登陆月球!!!");
}
public static void main(String[] args) {
Son son = new Son();
System.out.println(son.getMoney());
son.gotoMonn();
}
}
5.多态
5.1多态的定义
-
如何声明多态?多态用在哪?
抽象类可以实现多态,接口也可以实现多态,多态一般用在类的方法中
-
使用多态的好处
在同一个方法中,只要传递一个参数(类),但是可以实现多种功能。
public class Hospital{
//多态的方法
public void watch (Doctor doctor,String msg){
doctor.cure(msg);
}
public static void main(String[] args) {
Hospital hospital= new Hospital();
//多态的实现
EyeDoctor eye = new EyeDoctor("令狐冲","眼");
hospital.watch(eye,"近视眼");
System.out.println("--------------");
SkinDoctor skin = new SkinDoctor("王富贵","皮肤");
hospital.watch(skin,"发炎");
System.out.println("--------------");
BoneDoctor bone = new BoneDoctor("铁拐李","骨");
hospital.watch(bone,"瘸了");
System.out.println("--------------");
}
}