封装
- 封装的好处
1、封装之后,复杂的事物被“包起来”了。复杂性封装,对外提供简单的操作入口。比如照相机,照相机内部结构、实现原理都很复杂,然而对于使用者就很简单。
2、封装之后才会形成真正的“对象”,真正的“独立体”。
3、封装意味着以后的程序可以重复使用,并且这个事物应该适应性比较强,在任何场合都适用。
4、封装之后,对于事物本身,提高了安全性【安全级别高】。 - 封装的步骤
1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。(例子:private int age,age属性私有化,在外部程序不能直接访问)
2、对外提供简单的操作入口,也就是说以后外部程序要想访问age属性,必须通过这些简单的入口进行访问。(属性的访问形式:读取属性的值(get);修改属性的值(set)。)
3、对外提供两个公开的方法,分别是set方法和get方法:想修改属性,调用set方法;想读取属性,调用get方法。
4、set方法的命名规范:
public void set+属性名首字母大写(形参){
安全控制;
Java代码;
}
例子:
public void setAge(int a){ if(a<0 || a>150){ return; } age = a; }
get方法的命名规范:
public 参数类型 get+属性名首字母大写(){
安全控制;
Java代码;
}
例子:
public int getAge(){ if(a<0 || a>150){ return; } return age; }
5、setter和getter方法没有static关键字;有static关键字修饰的方法怎么调用:类名.方法名(实参);没有static关键字修饰的方法怎么调用:引用.方法名(实参)。
继承
- 作用
基本作用:代码复用。
重要作用是:有了继承才有以后“方法的覆盖”和“多态机制”。 - 继承的语法格式:
[修饰符列表] class 类名 extends 父类名{
类体 = 属性 + 方法
} - 单继承
Java中只支持单继承,一个类不能同时继承很多类,只能继承一个类。在C++中支持多继承
但是一个类也可以间接继承其他类,例如:
C extends B{ } B extends A{ } A extends T{ }
C类直接继承B类,但是C类间接继承了A、T类
- 关于继承中的一些术语
B类继承A类:
A类称为:父类、基类、超类、superclass
B类称为:子类、派生类、subclass - 子类继承父类继承那些数据呢?
私有的不支持继承
构造方法不支持继承
其他数据都可以被继承 - 默认继承
Java中假设一个类没有显示继承任何类,该类默认继承JavaSE库中提供的java.lang.Object类。
//快捷键:查找类型[Open Type]:ctrl + shift + T;
查找资源:[Open resource]:ctrl + shift + R
继承中的方法覆盖
- 方法覆盖
1、方法覆盖又被称为方法重写(override)/(overwrite)
2、什么时候使用方法重写?
当父类中的方法已经无法满足当前子类的业务需求;
子类有必要将父类中继承过来的方法进行重新编写; - 代码需要满足什么条件才能构成方法覆盖?
1、方法重写发生在具有继承关系的父子类之间;
2、方法重写的时候:方法名相同、返回值类型相同、形参列表相同;
3、方法重写的时候:访问权限不能更低,可以更高;
4、方法重写的时候:抛出异常不能更多,可以更少;
5、建议方法重写的时候尽量复制粘贴!(因为容易出错,导致没有产生覆盖) - 重写标注
1、为了避免错误,可以使用一个特殊的Java语法,称为重写标注,在子类的方法前面放一个@Override。
2、该标注表示被标注的方法必须重写父类的一个方法。如果具有该标注的方法没有重写父类的方法,编译器将报告一个错误。例如,如果toString被错误地输入为tostring,将报一个编译错误。如果没有使用重写标注,编译器不会报告错误。使用标注可以避免错误。 - 代码例子:
访问权限不能更低: - 注意
私有方法不能继承,所以不能覆盖;
构造方法不能继承,所以不能覆盖;
静态方法不存在覆盖。
覆盖只针对方法,不谈属性。
多态
- 关于Java中的多态语法机制
1、Animal、Cat、Bird三个类之间的关系:
Cat继承Animal
Bird继承Animal
Cat和Bird之间没有任何继承关系 - 关于多态涉及到的几个概念:
1、向上转型(upcasting):
子类型 转换为 父类型
又被称为自动类型转换
2、向下转型(downcasting):
父类型 转换为 子类型
又被称为强制类型转换【需要加强制类型转换符】
3、注意:向上转型和向下转型的前提是具有继承关系!(没有继承关系,程序是无法编译通过的)
4、代码、例子及内存图
//动物类 public class Animal { public void move(){ System.out.println("动物在移动"); } }
//猫类 public class Cat extends Animal{ //重写父类 public void move(){ System.out.println("猫在悄无声息地跑"); } //子类对象特有 public void catchMouse(){ System.out.println("猫抓老鼠"); } }
//鸟儿类 public class Bird extends Animal{ //重写父类 public void move(){ System.out.println("鸟儿在飞翔"); } //子类特有 public void fly(){ System.out.println("bird is flying!"); } }
//使用多态语法机制 Animal a2 = new Cat(); /*1、Java程序分为编译阶段和运行阶段*/ /*2、先分析编译阶段,在分析运行阶段; 编译无法通过,根本是无法运行的。*/ /*3、编译阶段编译器检查a2这个引用的 数据类型为Animal,由于Animal.class字 节码当中有move()方法,所以编译通过了。 这个过程我们成为静态绑定,编译阶段绑定。 只有静态绑定成功之后才有后续的运行。*/ /*4、在程序运行阶段, JVM堆内存当中 真实创建的对象是cat对象,那么以下程 序在运行阶段定会调用cat对象的move()方法, 此时发生了程序的动态绑定,运行阶段绑定。*/ /*5、调用的一定是Cat()方法,与重写不 重写无关,无论是Cat类有没有重写move方 法,运行阶段一定调用的是Cat对象的move 方法,因为底层真实对象就是cat对象。*/ a2.move(); /*6、cat对象里除了move()方法还有 catchMouse()方法,但是不能使用 catchMouse()方法,因为程序编译的 时候a2引用的数据类型Animal里面没有 catchMouse()方法,所以编译不通过。*/ /*7、父类型引用指向子类型对象这种机制 导致程序存在编译阶段绑定和运行阶段绑定 两种不同的形态/状态,这种机制可以称为一 种多态语法机制。*/
Animal和Cat之间存在继承关系,Animal是父类,Cat是子类。
new Cat()创建的对象的类型是Cat,a2这个引用的数据类型是Animal,可见它们之间进行了类型转换。子类型转换成父类型,称为向上转型(upcasting)或者自动类型转换。
Java中允许这种语法:父类型引用指向子类型对象。
- 怎么让以上的对象执行catchMouse()方法?
1、a2是无法调用的,因为a2的数据类型是Animal,Animal中没有catchMouse()方法。
所以要将a2强制类型转换为Cat类型。(属于子类转父类,所以其为强制类型转换)
2、什么时候需要向下转型?
当调用的方法是子类型中特有的,在父类中不存在的,必须进行向下转型。
3、代码
/*long x = 100L; int y = (int)x;*/ Cat c2 = (Cat)a2;/*a2在上面的代码中 被自动转换成了Animal类型,所以需要强转为Cat类型*/ c2.catchMouse(); //或者 ((Cat) a2).catchMouse(); //著名的异常:java.lang.classCastException Animal a3 = new Bird(); /*1、以下程序编译是没有问题的,因为编译 器检查到a3的数据类型是Animal,Animal和 cat之间存在继承关系,并且Animal是父类型, cat是子类型,父类型转换成子类型叫做向下 转型,语法合格。*/ /*2、程序虽然编译通过了,但是程序在运行 阶段会出现异常,因为JVM堆内存当中真实存在 的对象是Bird类型, Bird对象无法转换成 cat对象,因为两种类型之间不存在任何继承 关系,此时出现了著名的异常: java.lang.classCastException.类型转换 异常,这种异常总是在"向下转型的时候"会发生。*/ Cat c3 = (Cat)a3;
- “向下转型"存在隐患
1、以上异常只有在强制类型转换的时候会发生,也就是说“向下转型"存在隐患(编译过了,但是运行错了!)
2、向上转型只要编译通过,运行一定不会出问题: Animal a = new cat()
3、向下转型编译通过,运行可能错误: Animal a3 = new Bird(); cat c3 = (Cat) a3;
4、怎么避免向下转型出现的ClassCastException呢?
使用instanceof运算符可以避免出现以上的异常。 - instanceof运算符
1、语法格式:(引用 instanceof 数据类型名)
2、以上运算符的执行结果类型是布尔类型,结果可能是true/false
3、关于运算结果true/false:
假设: (a instanceof Animal)
true表示:a这个引用指向的对象是一个Animal类型。
false表示:a这个引用指向的对象不是一个Animal类型。
4、代码
Animal a3 = new Bird(); if (a3 instanceof Cat){//a3是一个Cat类型的对象 Cat c3 = (Cat) a3; c3.catchMouse(); } else if(a3 instanceof Bird) {//a3是一个Bird类型的对象 Bird b2 = (Bird) a3; b2.fly(); }
5、Java规范中要求:在进行强制类型之前采用instanceof运算符进行判断,避免ClassCastException异常的发生,这是一种编程的好习惯。
- 低耦合,高扩展
1、现有Master、Dog、Cat三个类:
Master和Cat, Dog这两个类型的关联程度很强,耦合度很高,扩展力差。
2、所以要降低程序的耦合度【解耦合】,提高程序的扩展力【软件开发的一个很重要的目标】
3、创建一个Pet类,使Cat, Dog继承Pet
这时Master主人类面向的是一个抽象的Pet,不再面向具体的宠物
4、提倡:面向抽象编程,不要面向具体编程。
面向抽象编程的好处是,耦合度低,扩展力强。 - 多态的作用是什么?
降低程序的耦合度,提高程序的扩展力。
能使用多态尽量使用多态。
父类型引用指向子类型对象。
来源:https://www.cnblogs.com/yu011/p/12632615.html