目录
封装(encapsulation)
继承(extends)
super
多态(polymorphic)
多态细节
保护代码的私有性,项目的目的是给用户的,隐藏代码实现的一些细节,或者协保证代码的安全性。
提高程序的安全性,保护数据
隐藏代码的实现细节
统一接口
系统的可维护性增加
利用private修饰符进行封装(类的属性私有),如果在公共类中需要访问封装好的类时,在private的属性中通过get/set访问(Alt+Insert快捷键)(驼峰原则)同时可以根据一些规定在private的属性中进行一些修改,比如年龄必须是0-120之间,否则返回3等等规则。
在通过子类中的get方法(人为设置)访问私有数据
封装介绍
封装 ( encapsulation) 就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作
封装的理解和好处
隐藏实现细节 方法(连接数据库)<----调用(传入参数...)
可以对数据进行验证,保证安全合理
Person{name,age}
Person p = new Person();
p . name = "jack";
p . age = 1200;//没有进行正确(合理)判断
封装实现步骤(三步)
将属性进行私有化private【不能直接修改属性】
提供一个公用的(public)set方法,用于对属性判断并赋值
public void setXxx(类型 参数名){//Xxx表示某个属性 //加入数据验证的业务逻辑 //属性 = 参数名; }
提供一个公用的(public)get方法,用于获取属性的值
public void getXxx(){//权限判断,Xxx某个属性 return xx; }
通过extends关键字继承父类,Java中的类只有单继承。
继承的本质是对某一些类的抽象化,方便更好的管理代码。
继承是一种拓展,子类是父类的拓展(子类具有父类的一般特性)。
继承是类和类的一种关系,除了继承,还有依赖,组合,聚合等
继承关系的两个类,一个为子类(派生类)一个为父类(基础类)
子类和父类之间有“is a”的关系
object是所有类的父类,使用时不需要继承(即系统会自动继承)(也叫做祖宗类)
子类继承了所有的属性和方法(只不过是private不显现,可以通过Debug工具看出),非私有的属性和方法可以在子类里直接访问,但是私有属性和方法不能在子类里直接访问,要通过父类提供公共的方法去访问
子类必须调用父类的构造器,完成父类的初始化
当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
使用方法:super(数据类型 变量名...);如果父类有多个构造器,一般只能用 super单独指定父类中的一个有参构造器,因为 super语句只能放在子类的第一句
如果需要指定去调用父类的某个构造器,则需要显式的调用一下:super(参数列表)
super在使用时,需要且只能放在构造器的第一行
super()和this()都只能放在构造器的第一行,且这两条语句不能同时存在于一个构造器当中
Java所有类都是Object的子类,Object是所有类的基类
父类构造器的调用不限于直接父类!将一直向上追溯到Object类
子类最多只能继承一个父类(指直接继承),即Java中是单继承机制
不能滥用继承,子类和父类必须满足 is - a 的逻辑关系
继承的本质
public class ExtendsTheory { public static void main(String[] args) { Son son = new Son();//分析内存的布局 } } class GrandPa{//父类的父类GrandPa String name = "强壮爷爷"; String hobby = "钓鱼"; } class Father extends GrandPa{//父类Father String name = "小头爸爸"; int age = 39; } class Son extends Father{//子类Son String name = "大头儿子"; }
进行实例化Son()对象时,先加载顶级类Object的信息再加载GrandPa()信息,再加载Father()信息,最后加载Son信息
也就是再方法区中依次加载了四次信息
1.首先加载的爷爷类的属性会放在堆中的地址0X11中,属性指向方法区中常量池中的属性
2.然后加载父类的属性,但是如果父类的变量名和爷类的一致时,不会覆盖,会在堆中开辟另外的空间(基本数据类型只会存放在堆中,不会放在常量池中)然后再指向常量池中的变量
3.加载子类信息
4.栈中的main方法调用Son对象(地址)
按照查找关系来返回信息 1.首先看子类是否有该属性 2.如果子类有这个属性并且可以访问,则直接返回信息 3.如果子类没有这个属性,就一层一层依次向上查找该属性(并返回)
如果再查找过程中遇到有private的无法访问,则直接报错,不会再继续向上查找这个属性
如果要访问子类父类爷类中的同名属性,需要再父类爷类中设置返回需要的信息的方法
this关键字是指向当前类
super是指向父类
父类中的private修饰的属性或者方法无法被子类调用,理论上来说是可以继承过去,但是无法被子类所访问(可以通过间接的方法访问)
子类和父类都有无参构造时
在调用子类的无参构造时,有一句隐藏的代码是super();(这句调用父类的构造器必须放在子类构造器内部的第一行)即默认先调用父类的无参构造
调用构造器时,只用调用父类或者子类的其中一个(调用子类需要把this放在第一行,调用父类需要把super放在第一行,如果同时调用,则会冲突)(子类继承父类后,父类有构造器的时候,子类会默认调用父类的构造器,也就是说这里如果只写this,这里的this也会报错(因为这里的this之前有默认调用父类的super))
当子类设置有参构造时,无参构造自动消除,即对父类的super无参构造无法使用
封装的时候,一个类无论怎么写,只要重写了有参构造,一般需要先把无参构造加上
如果没写父类的无参构造,子类仅可以调用父类的有参构造
方法重载(overloading)和方法覆盖(overriding)都是实现多态的手段,但是二者机制不同
抽象方法只起定义作用,不需要有方法体,一个类中如果全部都是抽象方法,基于称之为接口(interfere)只有接口的子类才可以实例化
多[多种]态[状态]基本介绍
方法或对象具有多种形态。是面对对象的第三大特征,多态时建立在封装和继承基础之上的
多态具体体现
方法的多态 Ploy Demo 01 . java
重写和重载体现多态
对象的多态(核心、困难、重点)
一个对象的编译类型和运行类型可以不一致
编译类型在确定对象时,就确定了,不能改变
运行类型时可以变化的
编译类型看定义时 = 号的左边
运行类型看定义时 = 号 的右
案例:
Animal animal = new Dog();[animal的编译类型是Animal,运行类型是Dog]
animal = new Cat();[animal的运行类型变成了Cat,编译类型仍然是Animal]
多态的前提:两个对象(类)存在继承关系
多态的向上转型
向上转型调用方法的规则如下
可以调用父类中的所有成员(需要遵守访问权限)
不能调用子类的特有的成员(因为在编译阶段,能调用那些成员都是由编译类型决定的)
最终运行效果看运行类型的具体实现,即调用方法时,按照运行类型开始查找方法,然后调用,规则与之前的访问规则一致
多态的向下转型
语法:子类类型 引用名 = (子类类型)父类引用
只能强转父类的引用,不能强转父类的对象
要求父类的引用必须指向的是当前目标类型的对象
当向下转型后,才可以调用子类类型中的所有成员(也就是说父类不能直接调用子类的新方法)
属性没有重写之说!!!属性的值看编译类型
(即属性不能动态绑定,在编译时就已经确定了)
instanceof 比较操作符 用于判断对象的运行类型是否为XX类型或者XX类型的子类型
Java的动态绑定机制(very important a lot)
动态绑定机制:
当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
当调用对象属性时,没有动态绑定机制,那里声明就在那里使用
多态的应用
多态数组
数组的定义类型为父类类型,里面保存的实际元素为子类类型
示例:
Person[] persons = new Person[5];
persons[0] = new Person("jack",20);//指向Person的数组数组某元素
persons[1] = new Student("小王",18,100);//指向Student的数组某元素
persons[2] = new Student("小明",19,65);
persons[3] = new Teacher("李老师",29,8000);//指向Teacher的数组某元素
persons[4] = new Teacher("赵老师",40,6000);
//循环遍历多态数组
for(int i = 0; i < persons.length; i++){
System.out.println(persons[i].say());
//
if(persons[i] instanceof Student){//判断person[i]的运行类型是否是Student
((Student)persons[i]).study();//运行person数组中Student(子类)特有方法的语法
//或者写成Student student = (Student) persons[i];
// student.study
}else if(persons[i] instanceof Teacher){//保证进行类型转换时不会出错
((Teacher)persons[i]).teach();//执行Teacher中的特有方法teach()
}else if (persons[i] instanceof Person){
}else{
System.out.println("类型有误,请自行检测");
}
多态参数
方法定义的形参类型为父类类型,实参类型允许为子类类型