JAVASE 学习笔记(面向对象------封装、继承、多态)

封装:

类似于现实中看电视,我们要换台时只需要通过遥控器这个接口就能实现,而不需要知道电视的内部结构完成了什么步骤,这就是封装。

高内聚,低耦合:内部细节数据由自己完成,不让外部干涉;仅暴露部分方法给外部使用

JAVASE 学习笔记(面向对象------封装、继承、多态)_第1张图片

 将属性私有,通过get、set方法来设置和显示属性值:

set()方法中可以设置一些报错信息

JAVASE 学习笔记(面向对象------封装、继承、多态)_第2张图片

 封装的作用:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第3张图片

继承:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第4张图片

父类 (基类)   子类(派生类)是父类的抽象 ,通过extends关键词可以继承父类。有子类is a 父类的关系。

子类是对父类的扩展,子类可以继承父类的所有public属性和方法。(但是不能继承private的属性和方法,一般属性被封装为private,而方法一般为public权限,所有可以通过Get,Set方法来使子类调用父类的属性)

权限:

public 公开的

protected 保护的

default 默认的

private 私有的 

 注意:

 一个子类只能有一个父类,而一个父类可以有多个子类。

单继承就是:子类的父类可能还有它的父类,但是这个“爷爷类”不能算是子类的夫类

重点: 

JAVASE 学习笔记(面向对象------封装、继承、多态)_第5张图片

object类:

JAVAZ中所有的类直接间接继承boject,包含以下等方法:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第6张图片

JAVASE 学习笔记(面向对象------封装、继承、多态)_第7张图片

super:调用出父类的属性.方法

JAVASE 学习笔记(面向对象------封装、继承、多态)_第8张图片

 

第一个name打印的 是形参, 第二个this.name打印的是子类的name,第三个super打印的父类的name属性。

JAVASE 学习笔记(面向对象------封装、继承、多态)_第9张图片

 

 当子类继承了父类,但是在子类中进行了方法重写后,调用时用的是子类的方法。

JAVASE 学习笔记(面向对象------封装、继承、多态)_第10张图片JAVASE 学习笔记(面向对象------封装、继承、多态)_第11张图片   

结果:

构造器:

1.new一个 子类时 会先调用父类的构造器,再调用子类的构造器

 

2.用this和super调用构造器时,必须放在子类构造器的第一行

3.当父类定义了有参构造后,无参构造会自动消失。因为new一个子类时会先调用父类的无参构造器(不管子类是有参还是无参),再调用子类的构造器。如果父类只有有参构造器而没有无参构造器子类就会报错。(除非子类的第一行就用super调用父类的有参构造器)

 所以通常在写类时如果定义了有参构造,就要另外再显示构造一个无参构造器。这样当他作为父类时就不会报错。

子类为无参:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第12张图片

JAVASE 学习笔记(面向对象------封装、继承、多态)_第13张图片

 结果:

子类为有参:

 JAVASE 学习笔记(面向对象------封装、继承、多态)_第14张图片

JAVASE 学习笔记(面向对象------封装、继承、多态)_第15张图片

结果:

super注意点总结: 

JAVASE 学习笔记(面向对象------封装、继承、多态)_第16张图片

方法重写 @Override 

 *重点总结:

1.重写需要有继承关系,且是子类对父类的方法重写。

重写时子类的方法和父类必须一致(方法名相同、参数列表相同)不同的只是方法体

2.静态方法的调用只和左边定义的数据类型有关,只有非静态的方法才能重写

3.修饰符:范围可以扩大:   public>protected>default>private

4.抛出的异常:范围可以被缩小,但不能扩大:ClassNotFoundException -->Excertion(大)

为什么要重写?

父类的功能子类不一定需要,或者不一定满足(需要更多)。

静态的方法:调用只和左边定义的数据类型有关

因为类中的静态方法只属于类,不能重写。(final 常量、private 私有类型方法也不能重写)

如下:

A是子类   B是父类,    

A a  =new A();       a.text();方法调用的是A类test()方法的方法

B b = new A();//父类的引用指向的子类   ,此时b 调用的是B类的test(方法)

JAVASE 学习笔记(面向对象------封装、继承、多态)_第17张图片

 非静态的方法(只有非静态的方法才能重写)

A a  =new A();       new了一个A(),指向的是A类的一个实例a.

B b = new A();//父类的引用指向的子类   , new了一个A(),指向的是B的实例 b,但是还是A,这就是子类重写了父类的方法

JAVASE 学习笔记(面向对象------封装、继承、多态)_第18张图片

多态:

一图理解多态:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第19张图片

 

 多态存在的条件:

向上转型:

多态本身就是向上转型过的过程
          使用格式:父类类型 变量名=new 子类类型();

          适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。

向下转型:

必须先向上转型才能向上转型,将父类引用类型转为子类引用各类型
         使用格式:子类类型 变量名=(子类类型) 父类类型的变量;

         适用场景:当要使用子类特有功能时。
 

多态是什么?

多态: 事物存在的多种形态

          对象存在的多种形态

多态是什么多态?  多态是对象的多态,方法的多态是对象多态的体现

(代码层面)对象存在的多种类型

           Cat c = new Cat();           //对象是 猫      类

           Animal a = new Cat();   //对象是 动物   类   

同一方法可以根据发送对象的不同而采用多种不同的行为方式

 

例子①:

 动物类:JAVASE 学习笔记(面向对象------封装、继承、多态)_第20张图片

猫类(继承动物类):

JAVASE 学习笔记(面向对象------封装、继承、多态)_第21张图片 先写了两个类,这两个类满足了多态的:

1.猫继承与动物

2.猫类中重写了父类的run()方法

然后写了一个测试类:

其中Animal a = new Cat();  //向上转型(Animal在栈中的引用a 指向了new出来的Cat()对象,此时是不能调用子类cat中特有的属性与方法的!!!)

满足了多态的第三个条件:3.父类的引用指向了子类

JAVASE 学习笔记(面向对象------封装、继承、多态)_第22张图片

结果:

子类Cat重写了父类的Animal的非静态方法eat();输出结果为:猫在吃饭

子类Cat重写了父类的Animal的静态方法sleep();输出结果为:动物在睡觉

未被子类(Cat)重写的父类(Animal)方法run();输出结果为:动物在跑

JAVASE 学习笔记(面向对象------封装、继承、多态)_第23张图片
然而 a不能调用子类中特有的属性与方法:a.catchMouse()在编译时就报错了

JAVASE 学习笔记(面向对象------封装、继承、多态)_第24张图片

这是多态的缺点,可以这么理解:对象a 实际上是Cat类的,但是父类Animal的引用指向了a,它乔装成了Animal类(此时他是A类但是他有随时可以变回C类)。因为乔装了不能被发现所一a只能

有父类Animal的属性与方法,而不能有C类的属性与方法(实际上是因为父亲的类型,智能看到堆内存中super的一小块空间)。

如果a想用Cat中的catchMouse()方法就必须放弃乔装从Animal类———>强制转化为Cat类。

就能调用catchMouse()方法:

代码:

结果:   

向下转型注意点:

1. 向下转型,必须发生在子父类的关系当中

2. 向下转型之前,必须得先有向上转型。转上去,才能转下来

Animal a = new Animal();Dog d = (Dog) a ;//报错

例:

Animal a = new Dog();//对象dog()向上转型为父类Animal

Dog d = (Dog) a ; //向下转型 ,不报错

Cat c = (Cat) a ;//报错

狗类和猫类不存在子父类关系.

ClassCastException :类型转换异常产生:当引用数据类型的强转,出现了错误就会抛出此异常


 

例子②:

public class TestSuperMan{
    public static void main (String [] args) {
        //1. 超人乔装成人   
        Person p =new SuperMan();//向上转型(父类引用指向子类引用,此时不能调用子类的属性和行为)

        //多态创建对象,并调用成员变量的特点(编译看左边,运行看左边)
        System.out.println(p.name);// 克拉克
        //2.谈生意
        p.谈生意();

        //这时有人跳楼,超人要去救人,
        p.fly();  //报错,因为乔装成人了

        //多态的弊端:不能调用子类特有的属性和行为
        //需要向下转型,将乔装成人的[超人]-->转换为超人类型
        SuperMan sm = (SuperMan) p ;//向下转型

        //3.飞出去救人
        System.out.println(sm.name);
        sm.fly();
    }
}

class Person {
    String name = "克拉克";
    public void 谈生意 () {
        System.out.println("谈几个亿的大单子");
        }
    }

class SuperMan extends Person {        
    String name = "超人";
    public void fly () {
        System.out.println("飞出去救人"");
    }
}

例子③

用花木兰替父从军的例子来理解多态:

花木兰替父亲花弧从军。那么这时候花木兰是子类,花弧是父类。花弧有自己的成员属性年龄,姓名,性别。花木兰也有这些属性,但是很明显二者的属性完全不一样。花弧有自己的非静态成员方法‘骑马杀敌’,同样花木兰也遗传了父亲一样的方法‘骑马杀敌’。花弧还有一个静态方法‘自我介绍’,每个人都可以问花弧姓甚名谁。同时花木兰还有一个自己特有的非静态成员方法‘涂脂抹粉’。但是,现在花木兰替父从军,女扮男装。这时候相当于父类的引用(花弧这个名字)指向了子类对象(花木兰这个人),那么在其他类(其他的人)中访问子类对象(花木兰这个人)的成员属性(姓名,年龄,性别)时,其实看到的都是花木兰她父亲的名字(花弧)、年龄(60岁)、性别(男)。当访问子类对象(花木兰这个人)的非静态成员方法(骑马打仗)时,其实都是看到花木兰自己运用十八般武艺在骑马打仗。当访问花木兰的静态方法时(自我介绍),花木兰自己都是用她父亲的名字信息在向别人作自我介绍。并且这时候花木兰不能使用自己特有的成员方法‘涂脂抹粉’。-----多态中的向上转型

终于一将功成万骨枯,打仗旗开得胜了,花木兰告别了战争生活。有一天,遇到了自己心爱的男人,这时候爱情的力量将父类对象的引用(花弧这个名字)强制转换为子类对象本来的引用(花木兰这个名字),那么花木兰又从新成为了她自己,这时候她完全是她自己了。名字是花木兰,年龄是28,性别是女,打仗依然那样生猛女汉子,自我介绍则堂堂正正地告诉别人我叫花木兰。OMG!终于,终于可以使用自己特有的成员方法‘涂脂抹粉’了。从此,花木兰完全回到了替父从军前的那个花木兰了。并且和自己心爱的男人幸福的过完了一生。-----多态中的向下转型。

PS:向上转型向下转型一定是在多态这个前提下,否则强制将女儿变成父亲,或者将父亲变成女人,就变成东方不败了,系统此时就会报错非法类型转换。哈哈哈哈哈。另外开发中一般是利用多态声明形式参数,并将创建子类的匿名对象作为实际参数。以上。

(参考知乎回答:小史的JavaSE课堂随笔整理)

根据以上情况总结多态创建对象时,调用成员变量和方法时的特点: 

 ①成员变量(属性):编译看左边(父类),运行看左边(父类)

  多态是方法的多态,属性没有多态

 ②成员方法:编译看左边(父类),运行看右边(子类)动态绑定 

编译时会检查父类中是否存在该方法[也叫动态绑定机制]

如果不存在,编译阶段直接报错

如果存在, 编译通过,但是运行时,执行子类的方法(因为部分方法在父类中,是不存在方法体逻辑的如果运行时走父类的方法,那么没有逻辑就没有意义)

Animal a = new Cat();

Cat b = new Cat();

比较a和b:

a只能使用父类的所有方法或者子类中重写了的父类的方法(编译看左边)而不能使用子类中特有的属性与方法。                其中静态方法和没有重写的非静态方法 调用的是父类方法,重写了的方法 最终调用的是子类的方法(运行看右边)。

而b既可以使用父类Animal的所有方法,也可以使用子类Cat的所有方法

 ③静态方法:编译看左边(父类),运行看左边(父类)

因为类中的静态方法只属于类,不能重写。(final 常量、private 私有类型方法也不能重写)

综上:只有非静态的成员方法有多态(编译看左边,运行看右边)

 多态的缺点:

多态后不能调用子类的的特有的成员属相和子类特有的成员方法

JAVASE 学习笔记(面向对象------封装、继承、多态)_第25张图片

多态的优点:

1.提高了代码的复用性
2.提高了代码的维护性
3.提高了代码的扩展性:可以将一个方法的形式参数,定义为父亲类型,该方法就能接受这个父类的任意子类对象

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用 ,更能体现出多态的拓展性与便利,

4.方便方法的调用时,减少重复的代码!简洁。

在使用有继承关系的类方法时,不用重新new一个类,而是把一个类向上转型或者向下转型就可以用其他类的方法了。

instanceof 及类型转换:

instenceof关键字用于判判定某对象是否为特定类(或者该特定类的子类/父类)若是则 为true;反之 则为false

System.out.println(X instanceof Y);编译能否通过,取决于X与Y是否有父子关系

例:有下面三个继承关系

①:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第26张图片

object默认是Object类(但实际上是隐式的Student类),

有继承关系:

 

结果:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第27张图片

②: 

 JAVASE 学习笔记(面向对象------封装、继承、多态)_第28张图片

person默认是Person类(但实际上是隐式的Student类)

有继承关系

而Sring类既和Student与Person类都没有父子关系,所以编译不通过。

结果:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第29张图片

③:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第30张图片

student有继承关系:Object>Person>Student

student类与teacher类和string类没有父子关系所以编译报错了

结果:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第31张图片

 类型之间的转换:

父类的引用可以指向子类//向上转型,向上转型的子类可以强制转化为子类//向下转型

JAVASE 学习笔记(面向对象------封装、继承、多态)_第32张图片

Person  obj = new Student();//向上转型,不用强制转换直接完成

obj默认是Person类(但实际是隐式的Student类),obj不能直接调用 子类Student中独有的属性与方法,必须要将其向下转型为Student类。

 有以下继承关系:

 

obj可以向下转型为Person类或Student类???吗

向下转型注意点:

需要用强制转换:格式:((子类)父类对象)

1. 向下转型,必须发生在子父类的关系当中

2. 向下转型之前,必须得先有向上转型。转上去,才能转下来

Animal a = new Animal();Dog d = (Dog) a ;//报错

ClassCastException :类型转换异常产生:当引用数据类型的强转,出现了错误就会抛出此异常

static关键词详解

JAVASE 学习笔记(面向对象------封装、继承、多态)_第33张图片

静态变量/方法    可以直接通过  类名.属性/方法名调用。

而非静态变量  需要先new一个实例,然后再实例名.属性/方法名。

方法和类中有静态代码块和匿名代码块,会在构造方法之前加载。

PS:1.静态代码块和类一起加载(最先加载),且只执行一次

      2.可以用匿名代码块附初始值

JAVASE 学习笔记(面向对象------封装、继承、多态)_第34张图片

 JAVASE 学习笔记(面向对象------封装、继承、多态)_第35张图片

 抽象类(约束!由子类来帮忙实现):

JAVASE 学习笔记(面向对象------封装、继承、多态)_第36张图片

1.abstract修饰符可以用来修饰方法和类,抽象类里可以没有抽象方法,但是有抽象方法的一定是抽象类。(抽象类中可以有普通的方法,即有方法体的方法)

2.抽象类:不能使用new关键词来创建对象,它是用来让子类继承的。约束!

3.抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的

4.子类继承抽象类,那么子类必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类

抽象类是单继承~  而接口可以多继承~

JAVASE 学习笔记(面向对象------封装、继承、多态)_第37张图片

有构造器;

 抽象类意义:

例如游戏角色,将其公有属性抽象出来放在抽象类中。每个角色在继承抽象类时另外的增删其独有的属性和方法。提高开发效率和可扩展性

接口:

普通类、抽象类、接口的区别:

①:

普通类:只有方法的具体实现

抽象类:具体实现方法和抽象方法(规范)都有

接口:只有规范!自己无法写

②:普通类和抽象类关键词为:class

        接口的关键词为:interface  JAVASE 学习笔记(面向对象------封装、继承、多态)_第38张图片            

接口的本质是契约,对象的抽象是OO的精髓,而接口是最能体现抽象的。

JAVASE 学习笔记(面向对象------封装、继承、多态)_第39张图片

定义了两个接口:UserService和TimerService

1.接口中定义的属性都默认带有修饰词:public static final

2.接口中的定义方法默认都带有修饰词:public abstract

3.接口中的方法不能定义,由其子类在继承时实现(重写override)

 JAVASE 学习笔记(面向对象------封装、继承、多态)_第40张图片JAVASE 学习笔记(面向对象------封装、继承、多态)_第41张图片

定义了一个实现接口的类:UserServiceimpl

1. 类可以实现接口     

抽象类的关键词:extends

接口    的关键词:implments


2.实现接口的类必须实现接口中的抽象方法

和抽象类一样,接口在被实现时,实现接口的类必须实现接口中的抽象方法。

3.利用接口可以实现多继承!

 JAVASE 学习笔记(面向对象------封装、继承、多态)_第42张图片

作用:

1.约束(接口中不能实现,让别人来进行实现)

2.定义一些方法,让不同的人实现   ~     n---->1

总结及注意点:

1.接口中定义的属性都默认带有修饰词:public static final

2.接口中的定义方法默认都带有修饰词:public abstract

3.接口中没有构造方法~故而接口不能被实例化~

4.实现类中的implments关键词后面可以实现多个接口(变相的多继承)

5.实现接口的类必须要实现(重写)接口中的抽象方法

N种内部类:

JAVASE 学习笔记(面向对象------封装、继承、多态)_第43张图片

 1.成员内部类

 //用于获得外部类的私有属性~JAVASE 学习笔记(面向对象------封装、继承、多态)_第44张图片

 2.静态内部类

里面不能调用 外部类的私有非静态属性,因为静态属性是和类一起最先加载的

JAVASE 学习笔记(面向对象------封装、继承、多态)_第45张图片

 3.局部内部类

JAVASE 学习笔记(面向对象------封装、继承、多态)_第46张图片

4.匿名内部类

 //没有名字初始化类,不用将实例保存到变量中

  //一个java文件中可以有多个class类,但是只能有一个public class

 JAVASE 学习笔记(面向对象------封装、继承、多态)_第47张图片

你可能感兴趣的:(java)