目录
封装
封装:面向对象三大特征之一
封装:将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问 。
封装的两个大致原则
把尽可能多的东西藏起来,对外提供便捷的接口
把所有的属性藏起来
封装的好处
- 便于使用者正确使用系统,防止错误修改属性
- 有助于系统之间的松耦合,提高系统独立性
- 提高软件的可重用性
- 降低了构建大型系统的风险
封装的具体步骤
修改属性的可见性——设为private
创建公有的getter/setter方法——属于属性的读写
在getter/setter方法中加入属性控制语句——对属性值的合法性进行判断
封装使用总结
封装时会用到多个权限修饰符来修饰成员变量和方法
this关键字:
是对一个对象的默认引用。在每个实例方法内部,都有一个this引用变量,指向调用这个方法的对象。
作用1:调用属性
使用this调用成员变量,解决成员变量和局部变量的同名冲突
作用2:调用方法
使用this调用成员方法,this可以省略,直接调用print();
作用3:调用构造方法
如果使用this调用重载的构造方法,只能在构造方法中使用,必须是构造方法中的第一条语句
添加getter/setter方法快捷键:
面向对象设计的基本步骤
面向对象设计的过程就是抽象的过程,分以下三步来完成
- 发现类(名词): 根据“对象”抽象出“类”
- 发现类的属性(名词):在定义类的属性时,要根据业务需求进行定义,只放和业务相关的属性
- 发现类的方法(动词): 在定义类的方法时,要根据业务需求进行定义,只放和业务相关的方法
使用类图描述面向对象设计
程序设计是一个逐步调整、完善的过程,类图是面向对象设计的“图纸”,使用“图纸”进行设计,方便了沟通和修改。
构造方法
能否在创建对象的同时就完成赋值?
在Java中,可以通过无参或带参的构造方法(Constructor)完成初始化工作
构造方法是一种特殊的方法,它是一个与类同名且无返回值类型的方法。
构造方法的功能主要是完成对象的初始化。
对象的创建就是通过构造方法来完成,当类实例化一个对象时会自动调用构造方法。在没有给类提供任何构造方法时,系统会提供一个默认无参构造方法。一旦提供了自定义构造方法,系统将不再提供这个无参构造方法。如果要使用它,则必须手动添加
方法重载(overloading)
方法重载的优点:
方法重载其实是对一般方法的一种升级,可以根据参数的不同,采用不同的实现方法,而且不需要编写多个名称,只要记住一个方法即可。
构造方法重载
构造方法重载特点:
- 方法名相同
- 参数数据类型或者参数个数不同
- 与返回值,访问修饰符无关
this关键字:
是对一个对象的默认引用,这里用以区分同名成员变量
static修饰符
- static可以用来修饰属性、方法和代码块
- static修饰的变量属于这个类所有,即由这个类创建的所有对象共用同一个static变量。
- 通常把static修饰的属性和方法称为类属性和类方法,不使用static修饰的属性和方法属于单个对象,通常称为实例属性和实例方法
static修饰符总结
- 在加载类的过程中,完成静态变量的内存分配,再执行静态块,两者是在创建对象之前执行的。
- 类属性和类方法可以通过类名和对象名访问,实例属性和实例方法只能通过对象名访问。
- 类方法只能访问类属性和其他类方法,不能使用this和super关键字。
- 实例方法中不可以定义static变量
static修饰和非static修饰的区别
封装——总结
继承
继承:面向对象三大特征之一是Java中实现代码重用的重要手段之一。
Java中只支持单继承,即每个类只能有一个直接父类。继承的语法:
1:编写父类(或者叫基类、超类)2:编写子类(SubClass),继承父类(SuperClass)
使用继承优化设计
可以将Dog类和Penguin类中相同的属性和方法提取出来放在一个单独的Pet类中,然后让Dog类和Penguin类继承Pet类,同时保留自己特有的属性和方法,这就需要通过Java的继承功能来实现。
子类可以从父类中继承到哪些“财产”
1:继承public和protected修饰的属性和方法,无论子类和父类是否在同一个包里。
2:继承默认权限修饰符修饰的属性和方法,但是子类和父类必须在同一个包里。
不能被继承的父类成员
- private成员
- 子类与父类不在同包,使用默认访问权限的成员
- 构造方法
访问修饰符protected
可以修饰属性和方法
本类、同包、子类可以访问
子类访问父类成员
访问父类构造方法
访问父类属性
访问父类方法
(1)super代表对当前对象的直接父类对象的默认引用
(2)super必须出现在子类(子类的构造方法)中,且必须是第一句
(3)不可以访问父类中定义为private的属性和方法
多重继承关系的初始化顺序是怎样的?
继承关系中的构造方法
- 如果子类的构造方法中没有通过super显式调用父类的有参构造方法,也没有通过this显式调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法。
- 如果子类的构造方法中通过super显式调用父类的有参构造,则将执行父类相应的构造方法,而不执行父类的无参构造方法。
- 如果子类的构造方法中通过this显式调用自身的其他构造方法,则在相应构造方法中应用以上两条规则。
class Car { private int site = 4; //座位数 Car(){ System.out.println ("载客量是"+site+"人); } public void setSite(int site){ this.site = site; } void print(){ System.out.print("载客量是"+site+"人"); } }
class Bus extends Car { Bus(int site){ setSite(site); } }
public static void main(String[] args) { Bus bus = new Bus(20); bus.print(); }
何时使用继承
继承与真实世界类似
只要说“猫是哺乳动物”,猫的很多属性、行为就不言自明了
藏獒是一种狗符合is-a关系的设计使用继承
继承是代码重用的一种方式
将子类共有的属性和行为放到父类中
如果从父类继承的方法不能满足子类的需求,则在子类中可以对父类的同名方法进行重写,以符合需求。
方法重写(overriding)
方法重写:在子类中可以根据需求对从父类继承的方法进行重写,称为方法的重写或方法的覆盖。
方法重写的规则:
- 重写方法和被重写方法必须具有相同的方法名
- 重写方法和被重写方法必须具有相同的参数列表
- 重写方法的返回值类型必须和被重写方法的返回值相同或者是其子类
- 重写方法不能缩小被重写方法的访问权限
overloading有什么区别与联系
overloading是方法重载,重载涉及同一个类中的同名方法,要求方法名相同,参数列表不同,与返回值类型、访问修饰符无关。
overriding是方法重写,重写涉及的是子类和父类的同名方法,要求方法名相同,参数列表不同,返回值类型相同(或是其子类)、访问修饰符不能严于父类。
Obejct类
Object类是所有类的父类。
在定义一个类时,没有使用extends关键字,也就是没有显式地继承某个类,那个这个类直接继承Object类。所有对象都继承Object类的方法。
Object类的常用方法
Object类定义了大量的可被继承的方法,也是它的子类经常重写的方法。
重写Object类的equals()方法
经典案例:
final修饰符
- 在Java中,final修饰符可以用来修饰类、方法和变量(包括成员变量和局部变量)
- 修饰类:当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
使用final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)“使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是 如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升。在最近的Java 版本中,不需要使用final方法进行这些优化了。“
final成员变量表示常量,只能被赋值一次,赋值后值不可以改变。
final修饰一个成员变量(属性),必须要显示初始化。这里有两种初始化方式,一种是在变量声明的时候初始化;第二种方法是在声明变量的时候不赋初值,但是要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
当final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
面试题
使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?
final修饰一个基本数据类型时,表示该基本数据类型的值一旦在初始化后便不能发生变化;如果final修饰一个引用类型时,则在对其初始化之后便不能再让其指向其他对象了,但该引用所指向的对象的内容是可以发生变化的。
继承——总结
多态
频繁修改代码,代码可扩展性、可维护性差,如何优化?
什么是多态?
生活中的多态:
不同类型的打印机打印效果不同同一种操作,由于条件不同,产生的结果也不同
多态:同一个引用类型,使用不同的实例而执行不同操作
如何实现多态——实现多态的思路
实现多态的三个要素:
编写具有继承关系的父类和子类
子类重写父类方法
使用父类的引用指向子类的对象
子类到父类的转换(向上转型)
向上转型:将父类的引用指向子类对象,称为向上转型,自动进行类型转换
转换时的规则:
此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,不是父类的方法
此时通过父类引用变量无法调用子类特有的方法
向上转型语法: <父类型> <引用变量名> = new <子类型>();
使用父类作为方法形参实现多态
多态是面向对象的三大特征之一
使用父类作为方法的形参,是Java中实现和使用多态的主要方式之一。下面就以这种方法重构主人给宠物喂食的功能。
使用父类作为方法返回值实现多态
- 使用父类作为方法的返回值,是Java中实现多态的另一种方式。下面就以这种方式实现主人领养宠物的功能。
- 实现思路:
在Master类添加领养方法getPet(String typeId )
创建测试类,根据主人选择宠物类型编号来领养宠物
public class Master { public Pet getPet(String typeId ){ … … } }
父类到子类的转换(向下转型)
向下转型:将一个指向子类对象的父类引用赋值给一个子类的引用,称为向下转型,此时必须进行强制类型转换。向下转型可能会出现类型转换异常ClassCastException。
instanceof运算符
在强制类型转换中。如果没有转换为真实子类类型,就会出现类型转换异常,怎么办?
在Java中,提供了instanceof运算符来判断对象的类型
语法: 对象名 instanceof 类或接口
使用经验:
1:使用instanceof运算符时,对象的类型必须和instanceof的第二个参数所指定的类或接口在继承树上有上下级关系,否则会出现编译错误。
2:instanceof通常和强制类型转换结合使用
总结——多态