面向对象的封装性
为什么封装
新建两个类:用户类、用户测试类
package day01.encapsulation;
/**
* @author 衣鱼
*用户类
*/
public class User {
int age;
}
package day01.encapsulation;
/**
* @author 衣鱼
*用户的测试类
* user类中的age属性在外部程序中可以随意访问,导致age属性
* 不安全。用户年龄被任意修改,年龄不可能为负数,以下程序当中的年龄被设置为负数
* 程序运行时没有报错,这就是当前程序的缺陷。
*
* 面向对象:封装
* 封装之后,看不到事物复杂的内部,只能看到简单的操作入口
* 照相机的实现原理很复杂,但是对于用户拍照的操作很简便。
* 封装之后才会形成真正的对象,真正的“独立体”
*
* 封装之后,对于事物本身提高了安全性;
* 封装意味着以后的程序可以成分使用
*/
public class UserTest {
public static void main(String[] args) {
//初始化对象
User u = new User();
//访问age
System.out.println("用户的年龄为"+u.age);
//修改年龄
u.age=23;
System.out.println("用户年龄为"+u.age);
//修改年龄
//这里的age属性,显然是完全暴露给测试类(外部程序)
u.age=-125;
System.out.println("用户年龄为"+u.age);
}
}
怎么封装
-
1、封装的步骤
所有属性私有化,使用private关键字修饰,private表示私有的,修饰的所有数据只能在本类中访问
此时进行测试,编译报错 age属于私有化 ,外部程序不能直接访问。对于目前的程序来说,age彻底不能被外部访问。 -
2、提供简单拿到操作入口
外部程序想要访问age属性时,必须通过这些简单的入口进行访问。
一个属性访问形式:读取属性的值get、修改属性的值set。
对外提供两个公开方法:get方法、set方法。
命名规范:
public void setAge(int a){ //【this关键字文章可以加深理解】
age = a;
}
public int getAge(int a){
return age;
} -
3、setter、getter方法没有static关键字
static关键字的调用:类名.方法名(实参)
没有static关键字修饰的方法:引用.方法名(实参)
package day01.encapsulation02;
/**
* @author 衣鱼
* 1、封装的步骤
* 所有属性私有化,使用private关键字修饰,private表示私有的,修饰的所有数据只能在本类中访问
* 此时进行测试,编译报错 age属于私有化 ,外部程序不能直接访问。对于目前的程序来说,age彻底不能被外部访问。
* 2、提供简单拿到操作入口
* 外部程序想要访问age属性时,必须通过这些简单的入口进行访问。
* 一个属性访问形式:读取属性的值get、修改属性的值set。
*
* 对外提供两个公开方法:get方法、set方法。
* 命名规范:
* public void setAge(int a){
* age = a;
* }
* public int getAge(int a){
* return age;
* }
*
* 3、setter、getter方法没有static关键字
* static关键字的调用:类名.方法名(实参)
* 没有static关键字修饰的方法:引用.方法名(实参)
*
*
*/
public class User {
private int age; //一个属性:get、set
public void setAge( int a) {
//编写业务逻辑代码进行安全控制:避免出现年龄是负数的情况
//age = a;
if(a>=150||a<=0) {
System.out.println("抱歉您输入数据错误!");
return; //“return”语句的出现在返回值为void的方法中,
//目的是为了结束当前方法—弹栈。仅仅是“return;”,不能返回值“return 100;”
}
//输入数据合法,进行赋值
age = a;
}
public int getAge() {
return age;
}
}
快速自动生成set、 get方法
面向对象的继承性
- 一、继承是java的三大特性之一
- 二、继承的作用
- 1、代码复用
- 2、有了继承,可以为”方法覆盖“”多态机制“提供条件!!
- 三、继承的语法格式;
- [修饰符列表] class 类名 extends 父类名{
类体=属性+方法
} - 四、java语言当中继承只支持单继承,一个类不能同时继承多类,只能继承一个类
在C++中支持多继承 - 五、继承的语义:
B类继承A类 : A类称为父类、基类、superclass;B类称为子类、派生类、subclass - 六、子类继承父类的数据
- 私有不支持继承
- 构造方法不支持继承
- 其他数据均可被继承
- 七、java支持单继承,但是一个类也可以间接继承其他类,1继承2,2继承3,1间接继承3
- 八、java语言中假设一个类没有显示得继承任何类,那么该类默认继承java库中提供的java.lang.Object类
新建三个类:Account、CreditAccount、ExtendTest
package day01.ExtendsFeatures;
public class Account {
private String actno;
private double banlance;
public Account(String actno, double banlance) {
this.actno = actno;
this.banlance = banlance;
}
public Account() {
}
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno = actno;
}
public double getBanlance() {
return banlance;
}
public void setBanlance(double banlance) {
this.banlance = banlance;
}
}
package day01.ExtendsFeatures;
public class CreditAccount extends Account {
//private String actno;
//private double balance;
private double credit;
public CreditAccount() {
super();
}
public double getCredit() {
return credit;
}
public void setCredit(double credit) {
this.credit = credit;
}
}
package day01.ExtendsFeatures;
/**
* @author 衣鱼
* 一、继承是java的三大特性之一
* 二、继承的作用
* 1、代码复用
* 2、有了继承,可以为”方法覆盖“”多态机制“提供条件!!
* 三、继承的语法格式;
* [修饰符列表] class 类名 extends 父类名{
* 类体=属性+方法
* }
* 四、java语言当中继承只支持单继承,一个类不能同时继承多类,只能继承一个类
* 在C++中支持多继承
* 五、继承的语义:
* B类继承A类 : A类称为父类、基类、superclass;B类称为子类、派生类、subclass
* 六、子类继承父类的数据
* 私有不支持继承
* 构造方法不支持继承
* 其他数据均可被继承
* 七、java支持单继承,但是一个类也可以间接继承其他类,1继承2,2继承3,1间接继承3
* 八、java语言中假设一个类没有显示得继承任何类,那么该类默认继承java库中提供的java.lang.Object类
*/
public class ExtendsTest {
public static void main(String[] args) {
CreditAccount act = new CreditAccount();
act.setActno("act-001"); //CreditAccount类里面有Actno函数
act.setBanlance(-1000.0);
act.setCredit(0.99);
System.out.println(act.getActno()+","+act.getBanlance()+","+act.getCredit());
}
}
方法的覆盖
-
java的方法重载Overload
- 何时使用重载
- 当一个类当中,方法完成的功能是相似的,建议方法名相同。方便后续的编程。就像调用一个方法一样
- 重载的构成
在同一类当中,方法名相同,参数列表不同——类型、顺序、个数
方法重载与方法的返回值类型无关、与修饰符列表无关。
- 何时使用重载
-
java的方法覆盖
- 一、方法覆盖、方法重写 override
- 二、何时使用覆盖:当父类的方法已经无法满足子类的需求,子类有必要将父类的方法进行重写
- 三、什么条件满足后,可以覆盖:
方法重写发生在具有继承关系的子父类之间;
返回值类型相同、方法名相同、形参列表相同
访问权限不能更低,可以更高
抛出异常,不能更多,可以更少。 - 四、注意
- 私有方法不能继承,不能覆盖
- 构造方法不能继承,不能覆盖
- 静态方法不存在覆盖【多态文章】
- 覆盖只针对方法,不针对属性
package day01.ExtendsFeatures.OverrideMethod;
public class Animal {
//所有动物都会移动
public void move(){
System.out.println("动物在移动");
}
}
package day01.ExtendsFeatures.OverrideMethod;
public class Cat extends Animal {
public void move() {
System.out.println("猫在移动");
}
}
package day01.ExtendsFeatures.OverrideMethod;
public class Brid extends Animal {
}
package day01.ExtendsFeatures.OverrideMethod;
/**
* @author 衣鱼
* java的方法重载Overload
* 何时使用重载
* 当一个类当中,方法完成的功能是相似的,建议方法名相同。方便后续的编程
* 就像调用一个方法一样
* 重载的构成
* 在同一类当中,方法名相同,参数列表不同——类型、顺序、个数
* 方法重载与方法的返回值类型无关、与修饰符列表无关。
*
* java的方法覆盖
* 一、方法覆盖、方法重写 override
* 二、何时使用覆盖:当父类的方法已经无法满足子类的需求,子类有必要将父类的方法进行重写
* 三、什么条件满足后,可以覆盖:方法重写发生在具有继承关系的子父类之间;
* 返回值类型相同、方法名相同、形参列表相同
* 访问权限不能更低,可以更高
*/
public class OverriddTset01 {
public static void main(String[] args) {
//创建动物对象
Animal a = new Animal();
a.move();
//创建猫科对象
Cat c =new Cat();
c.move();
//创建飞禽对象
Brid b = new Brid();
b.move();
}
}
面向对象的多态性
- java语言中的多态机制
- 一、向上转型(upcasting):子类型——>父类型 自动转换
向下转型(downcasting):父类型——>子类型 强制转换【加强制类型转换符】
无论是向上转型、还是向下转型,两种类型之间必须有继承关系!没有继承关系不能转型- java.lang.ClassCastException 类型转换异常!!!这种异常总是在“向下转型”的时候发生,“向下转型”存在隐患【编译过了,运行错误】
- 向上转型,只要编译过了,运行一定没有问题。 Animal a1= new Cat();
- 向下转型,可能存在编译过了,运行错误!Animal a2 = new Brid(); Cat c2=(Cat)a2;
- 避免向下转型发生错误的措施
- 使用instanceof运算符可以避免以上的异常
- 一、向上转型(upcasting):子类型——>父类型 自动转换
- instanceof的使用
- 语法格式:(引用 instanceof 数据类型名)
- 以上运算符执行结果类型是布尔类型,结果可能是true/false
- (a instanceof Animal)
ture:a这个引用指向的对象是一个Animal类型
false:a这个引用指向的对象不是一个Animal类型
- (a instanceof Animal)
多态语法机制
结合下面的代码理解
- 1、java程序永远都分为编译阶段和运行阶段。先分析编译阶段,在分析运行阶段,一旦编译无法通过,不存在运行阶段
- 2、编译阶段编译器检查a1这个引用数据类型为Animal00,由于Animal00.class字节码当中有move()方法,所以编译会通过这个过程被称为静态绑定,只有静态绑定成功之后,才有后续的运行。
- 3、在程序运行阶段,JVM堆内存当中实际创建的对象是cat01对象,那么以下程序在运行阶段会调用cat01对象的move(),此时发生了动态绑定,运行阶段绑定
- 4、无论cat01类有没有重写move方法,运行阶段调用的一定是Cat01对象的move方法,因为底层真实对象假设cat对象。
- 5、父类型引用指向子类型对象,这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的状态,这种机制是一种多态语法机制。
package day01.ExtendsFeatures.polymorphism;
public class Animal00 {
//所有动物都会移动
public void move(){
System.out.println("动物在移动!");
}
}
package day01.ExtendsFeatures.polymorphism;
public class Cat01 extends Animal00 {
@Override
public void move() {
System.out.println("猫在移动");
}
//Cat特有行为:抓老鼠
public void catchMouse(){
System.out.println("猫抓老鼠 !");
}
}
package day01.ExtendsFeatures.polymorphism;
public class Brid01 extends Animal00 {
@Override
public void move() {
// TODO Auto-generated method stub
System.out.println("鸟儿在飞翔");
}
}
package day01.ExtendsFeatures.polymorphism;
/**
* @author 衣鱼
* Animal、Cat、Brid的三类关系
* Cat继承Animal
* Brid继承Animal
* Cat和Brid没有任何继承关系
*
* java语言中的多态机制
* 一、向上转型(upcasting):子类型——>父类型 自动转换
* 向下转型(downcasting):父类型——>子类型 强制转换【加强制类型转换符】
* 无论是向上转型、还是向下转型,两种类型之间必须有继承关系!没有继承关系不能转型
*
*
*/
public class TestACB {
public static void main(String[] args) {
//创建动物对象
Animal00 a = new Animal00();
a.move();
//创建猫科对象
Cat01 c =new Cat01();
c.move();
c.catchMouse();
//创建飞禽对象
Brid01 b = new Brid01();
b.move();
//使用多态机制
/**
* Animal00 和 Cat01之间有继承关系,Animal00是父类 Cat的子类
*
* Cat是Animal 【合理】
* new Cat() 创建的对象的类型是Cat , a1这个引用数据类型是Animal ,可见它们进行了数据转换
* 子类型转换成父类型,是向上转型 、自动类型转换
*
*/
Animal00 a1= new Cat01();
/**
* 1、java程序永远都分为编译阶段和运行阶段。先分析编译阶段,在分析运行阶段,一旦编译无法通过,不存在运行阶段
* 2、编译阶段编译器检查a1这个引用数据类型为Animal,由于Animal.class字节码当中有move()方法,所以编译会通过,这个过程被称为静态绑定,只有静态绑定成功之后,才有后续的运行。
* 3、在程序运行阶段,JVM堆内存当中实际创建的对象是cat01对象,那么以下程序在运行阶段会调用cat01对象的move(), 此时发生了动态绑定,运行阶段绑定
* 4、无论cat01类有没有重写move方法,运行阶段调用的一定是Cat01对象的move方法,因为底层真实对象假设cat对象。
* 5、父类型引用指向子类型对象,这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的状态,这种机制是一种多态语法机制。
*/
a1.move();
/**
* 此时有需求,让a1去抓老鼠:
* a1无法直接调用,a1是Animal00类型。此时需要强制类型转换 【当调用的方法是子类型中特有的,在父类型当中不存在,必须进行向下转型】
*
* 注意!!向下转型也需要两种类型之间必须有继承关系,不然编译会报错
* 强制类型转换符
*/
Cat01 c1= (Cat01)a1;
c1.catchMouse();
Animal00 a2 = new Brid01();
//Cat01 c2=(Cat01)a2; //运行错误
//使用instanceof运算符可以避免以上的异常
if(a2 instanceof Cat01) {
Cat01 c3=(Cat01)a2;
c3.catchMouse();
}
else if(a2 instanceof Brid01) {
Brid01 b2 = (Brid01)a2;
b2.move();
}
}
}
多态的作用
-
多态在实际开发中的作用:以饲养动物为例
- 分析场景,抽象类型
主人类、动作:喂养
宠物类、动作:进食
- 分析场景,抽象类型
-
面向对象编程的核心:定义好类,然后将类实例化为对象,给一个环境驱使,使各个对象协作起来形成一个系统。
-
多态的作用
降低程序的耦合度,提高程序的扩展力
父类型引用指向子类型对象
面向抽象编程,尽量不要面对具体编程
主人喂养宠物,建立Master、Cat、Dog、Test类
随着宠物类别的增加,传统的feed函数需要多次编写,扩展性差。
例题利用多态解决了该问题
package day01.polymorphism;
public class Cat extends Pet {
//猫吃鱼
public void eat() {
System.out.println("小猫在吃鱼");
}
}
package day01.polymorphism;
public class Dog extends Pet{
public void eat() {
System.out.println("小狗在吃骨头");
}
}
package day01.polymorphism;
public class Pet {
public void eat() {
//所有宠物都可以吃
}
}
package day01.polymorphism;
/**
* 这种方式没有使用使用java的多态机制:Master类的扩展能力很差
* 只要添加一个新的宠物,Master就要添加一个新方法!
* Msater 和Cat Dog两个类型的关联程度很高,耦合度很高、扩展性很差
public class Master {
// 主人喂养宠物
public void feed(Cat c) { //关联
c.eat();
}
public void feed(Dog d) { //关联 方法重载
d.eat();
}
}
*/
//降低程序的耦合度、提高程序的扩展力
//添加一个宠物类 宠物Cat、Dog继承宠物类Pet
//Master面对是是一个抽象的Pet,不再是一个具体的宠物
public class Master{
public void feed(Pet pet) { //pet的一个父类型的引用,传入参数jery是一个子类型的对象
pet.eat();
}
}
package day01.polymorphism;
/**
* @author 衣鱼
* 多态在实际开发中的作用:以饲养动物为例
* 分析场景,抽象类型
* -主人类、动作:喂养
* -宠物类、动作:进食
*面向对象编程的核心:定义好类,然后将类实例化为对象,给一个环境驱使,使各个对象协作起来形成一个系统。
*
*多态的作用
*/
public class Test {
public static void main(String[] args) {
Master xian = new Master();
Cat jery = new Cat();
//喂猫
xian.feed(jery);
//喂狗
Dog doudou = new Dog();
xian.feed(doudou);
}
}