一、封装
封装(Encapsulation)是面向对象方法的重要原则,就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。
封装的好处
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员进行更精确的控制。
- 隐藏信息,实现细节。
封装的实现
- 需要修改属性的访问控制符(修改为private);一旦使用了private进行修饰,那么本类当中仍然可以随意访问。但是!超出了本类范围之外就不能再直接访问了。
- 创建getter/setter方法(用于属性的读写);
- 在getter/setter方法中加入属性控制语句(用于判断属性值的合法性)。
间接访问private成员变量,就是定义一对儿Getter/Setter方法。必须叫setXxx或者是getXxx命名规则。对于Getter来说,不能有参数,返回值类型和成员变量对应;
对于Setter来说,不能有返回值,参数类型和成员变量对应。
public class Person{
private String name;
private int age;
private String sex;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
private int getAge(){
return age;
}
private void setAge(int age){
this.age = age;
}
public void setSex(String sex){
this.sex = sex;
}
}
如果没有setter(),getter()的话,那么Person类应该是这样的:
public class Person {
public String name ;
public String sex ;
public int age ;
}
我们应该这样使用它:
Person person = new Person();
person.age = 25;
person.name = "张三";
person.sex = "男";
但是如果需要修改Person,比如将sex修改为int类型,几十或者上百个这样的地方估计要改到崩溃,如果封装了,只需要修改setSex()方法就好了。另外,封装确实可以使我们容易地修改类的内部实现,而无需修改使用了该类的客户代码。还有针对某些成员变量,不想让其他类知道值为多少,就可以不去做getter()操作,比如Person类中的sex,不想让其他人知道性别,就不做getSex()。还有就是private修饰的成员变量以及成员函数,只能无法在类外调用,做到隐藏的作用。比如:Person类中的成员变量以及getAge()和setAge()在其他类是无法获取到的。
public class Person{
private String name;
private int age;
private int sex;//1:男;2:女;0:保密
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
private int getAge(){
return age;
}
private void setAge(int age){
this.age = age;
}
public void setSex(String sex){
if(StringUtils.isNotEmpty(sex)){
if(sex.equals('男')){
this.sex = 1;
}else if(sex.equals('女')){
this.sex = 2;
}else{
this.sex = 0;
}
}else{
System.out.println("请输入性别!"); //提示错误信息
}
}
}
二、继承
成员变量的访问特点:
在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:
1、直接通过子类对象访问成员变量: 点号(·)左边是谁,就优先用谁,没有则向上找。
2、间接通过成员方法访问成员变量: 该方法属于谁,就优先用谁,没有则向上找。
package cn.itcast.day09.demo03;
/*
局部变量: 直接写成员变量名
本类的成员变量: this.成员变量名
父类的成员变量: super.成员变量名
*/
public class Fu {
int num = 10;
}
//________________________________________________
package cn.itcast.day09.demo03;
public class Zi extends Fu {
int num = 20;
public void method() {
int num = 30;
System.out.println(num); // 30,局部变量
System.out.println(this.num); // 20,本类的成员变量
System.out.println(super.num); // 10,父类的成员变量
}
}
/*
在父子类的继承关系当中,创建子类对象,访问成员方法的规则:
创建的对象是谁,就优先用谁,如果没有则向上找。
注意事项:
无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。
重写(Override)
概念:在继承关系当中,方法的名称一样,参数列表也一样。
重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。
重载(Overload):方法的名称一样,参数列表【不一样】。
方法的覆盖重写特点:创建的是子类对象,则优先用子类方法。
*/
继承的特点:
- 继承关系是传递的。若类C继承类B,类B继承类A(多层继承),则类C既有从类B那里继承下来的属性与方法,也有从类A那里继承下来的属性与方法,还可以有自己新定义的属性和方法。继承来的属性和方法尽管是隐式的,但仍是类C的属性和方法。继承是在一些比较一般的类的基础上构造、建立和扩充新类的最有效的手段。
- List item提供多重继承机制。从理论上说,一个类可以是多个一般类的特殊类,它可以从多个一般类中继承属性与方法,这便是多重继承。Java出于安全性和可靠性的考虑,仅支持单重继承,而通过使用接口机制来实现多重继承。
- 提高代码的复用性。若类B继承类A,那么建立类B时只需要再描述与基类(类A)不同的少量特征(数据成员和成员方法)即可。这种做法能减小代码和数据的冗余度,大大增加程序的重用性。
- Java只支持单继承,不支持多继承。也就是一个类只能有一个父类,不可以有多个父类。在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待,子类可以依然可以派生出其他子类(a是b的父类,b是c的父类,则a是c的间接父类,a是b的直接父类)。
- 补充看一下:重写和重载
三、多态
含义:多态指的是对象的多种形态。多态有两种:引用多态和方法多态。继承是多态的实现基础。
java程序中定义的引用变量所指向的具体类型和通过该引用类型发出的方法在调用时不确定,该引用变量发出的方法到底调用哪个类的实现的方法,必须在程序运行期间才能决定,这就是多态。
假设有一个类 叫 鸟类,它拥有属性 翅膀,拥有方法 鸣叫,如下:
public class Bird{
private Wing wing;
public void moo(){
System.out.println(“鸟叫声”);
}
}
鸟类封装了 翅膀类和moo方法;另外有两个类都继承鸟类并重写了moo方法,分别是鹦鹉和麻雀,如下:
鹦鹉类:
public class Parrot extends Bird{
public void moo(){
System.out.println(“鹦鹉的叫声”);
}
}
麻雀类:
public class Sparrow extends Bird{
public void moo(){
System.out.println(“麻雀的叫声”);
}
}
方法重写应该懂吧,不懂自己找书看吧;然后你有个妻子她想听鸟叫,就有个妻子类
public class Wife{
public void listen(Bird bird){
bird.moo();
}
这时多态就很好的体现了,你妻子想听鸟叫,无论什么鸟都可以给她,但是你想让她和鹦鹉说话,你就买了一只鹦鹉传给listen方法,结果你妻子听到了鹦鹉的叫声,程序输出:鹦鹉的叫声
public static void main(String[] args) {
new Wife().listen(new Parrot());
}
}
多态实现了动态绑定,让程序有了很好的扩展性,比如你以后想买一只燕子送给你妻子,就只需要写个燕子类Swallow继承Bird方法就可以了,而不需要再在妻子类里添加一个方法listen(Swallow swallow)
1. 多态存在的前提(多态的三要素)
A.必须有子类和父类,具有继承或实现(继承)
B.子类必须重写父类的方法(重写)
C.父类的引用变量指向子类的对象(向上转型)
2. 多态的优点
A. 可替换性,多态对一存在的代码具有可替代性
B. 可扩充性:增加的子类不影响已存在的类的特性的运行和操作
C. 接口性:多态时超类通过方法签名想子类提供了一个公共的接口,由子类来完善或者覆盖它而实现的
D. 灵活性:在应用中体现了灵活多样的操作,提高了使用的效率
E. 简化性: 多态简化对应用软件的代码的编写和修改过程,尤其在处理大量的对象的运算和操作时,这个特点尤为突出和重要
3. 多态的缺点
A. 只能使用父类的引用访问父类的成员
4. 多态中的成员特点:
成员变量:编译与运行时期都看父类!
成员方法:编译时期看父类,运行时期看子类
四、向上转型和向下转型
向上转型一定是安全的,没有问题的。但是也有一个弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。
解决方案:用对象的向下转型【还原】。
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态的好处:可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。以下是一个多态实例的演示。
public class Test {
public static void main(String[] args) {
show(new Cat()); // 以 Cat 对象调用 show 方法
show(new Dog()); // 以 Dog 对象调用 show 方法
Animal a = new Cat(); // 向上转型
a.eat(); // 调用的是 Cat 的 eat
Cat c = (Cat)a; // 向下转型
c.work(); // 调用的是 Cat 的 work
}
public static void show(Animal a) {
a.eat();
// 类型判断
if (a instanceof Cat) { // 猫做的事情
Cat c = (Cat)a;
c.work();
} else if (a instanceof Dog) { // 狗做的事情
Dog c = (Dog)a;
c.work();
}
}
}
abstract class Animal {
abstract void eat();
}
class Cat extends Animal {
public void eat() {
System.out.println("吃鱼");
}
public void work() {
System.out.println("抓老鼠");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("吃骨头");
}
public void work() {
System.out.println("看家");
}
}
执行以上程序,输出结果为:
吃鱼
抓老鼠
吃骨头
看家
吃鱼
抓老鼠
接口多态的综合案例
package cn.itcast.day10.demo07;
public class DemoMain {
public static void main(String[] args) {
// 首先创建一个笔记本电脑
Computer computer = new Computer();
computer.powerOn();
// 准备一个鼠标,供电脑使用
// Mouse mouse = new Mouse();
// 首先进行向上转型
USB usbMouse = new Mouse(); // 多态写法
// 参数是USB类型,我正好传递进去的就是USB鼠标
computer.useDevice(usbMouse);
// 创建一个USB键盘
Keyboard keyboard = new Keyboard(); // 没有使用多态写法
// 方法参数是USB类型,传递进去的是实现类对象
computer.useDevice(keyboard); // 正确写法!也发生了向上转型
// 使用子类对象,匿名对象,也可以
// computer.useDevice(new Keyboard()); // 也是正确写法
computer.powerOff();
System.out.println("==================");
method(10.0); // 正确写法,double --> double
method(20); // 正确写法,int --> double
int a = 30;
method(a); // 正确写法,int --> double
}
public static void method(double num) {
System.out.println(num);
}
}
public class Computer {
public void powerOn() {
System.out.println("笔记本电脑开机");
}
public void powerOff() {
System.out.println("笔记本电脑关机");
}
// 使用USB设备的方法,使用接口作为方法的参数
public void useDevice(USB usb) {
usb.open(); // 打开设备
if (usb instanceof Mouse) { // 一定要先判断
Mouse mouse = (Mouse) usb; // 向下转型
mouse.click();
} else if (usb instanceof Keyboard) { // 先判断
Keyboard keyboard = (Keyboard) usb; // 向下转型
keyboard.type();
}
usb.close(); // 关闭设备
}
}
public interface USB {
public abstract void open(); // 打开设备
public abstract void close(); // 关闭设备
}
// 鼠标就是一个USB设备
public class Mouse implements USB {
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
public void click() {
System.out.println("鼠标点击");
}
}
// 键盘就是一个USB设备
public class Keyboard implements USB {
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
public void type() {
System.out.println("键盘输入");
}
}
——————————————————————————————
看这里
原文链接:https://blog.youkuaiyun.com/hellosweet1/article/details/81320384