04_JavaSE之OOP--面向对象(封装、继承)

对象(四)

一、封装

  面向对象的三大特征:封装、继承、多态。

  今天呢,我们来谈谈,其中两个 ---- 封装和继承。而多态呢,如果没有继承也就没有多态一说,这个我们后续继续聊。

  1. 什么是封装?
    封装说白了,就是把对象的属性和行为给隐藏起来,仅仅对外提供公共的访问方式。
    如:将电脑的具体实现细节隐藏起来,提供键盘和一系列接口供用户使用,用户不必关心具体内部的实现细节。
  2. 封装的好处
    •  隐藏了实现细节,提供公共的访问方式
    •  提高了代码复用性
    •  提高安全性

  3. 封装的原则

    •  将不需要对外提供的内容都隐藏起来。
    •  把属性隐藏,提供公共方法对其访问。

   4 .说明

    把成员变量私有(private),提供相应的set/get方法。private仅仅是封装的一种体现形式,并不能说封装就是私有。

 

二、继承
  继承,利用继承我们可以基于已经存在的类构造新的类,继承已经存在的类就可以复用(继承)这些类的方法和成员变量。同时,我们也可以添加一些自己的方法和属性,使得子类更加强大。
  如:人可以是父类,而学生是人,是人的子类。而学生又具有他自己的特性。因此,这里存在着很明显的is-a的关系,is-a关系是继承的一个很明显的特征。

  继承使用 extends 关键字。

  1. 继承的代码
     1 class Test_Animal {
     2     public static void main(String[] args) {
     3         Cat c1 = new Cat("花",4);
     4         System.out.println(c1.getColor() + "..." + c1.getLeg());
     5         c1.eat();
     6         c1.catchMouse();
     7 
     8         Dog d1 = new Dog("黑",2);
     9         System.out.println(d1.getColor() + "..." + d1.getLeg());
    10         d1.eat();
    11         d1.lookHome();
    12     }
    13 }
    14 /*
    15 * A:猫狗案例分析
    16 * B:案例演示
    17     * 猫狗案例继承版
    18     * 属性:毛的颜色,腿的个数
    19     * 行为:吃饭
    20     * 猫特有行为:抓老鼠catchMouse
    21     * 狗特有行为:看家lookHome
    22 */
    23 
    24 class Animal {
    25     private String color;                    //毛的颜色
    26     private int leg;                        //腿的个数
    27 
    28     public Animal(){}
    29 
    30     public Animal(String color,int leg) {
    31         this.color = color;
    32         this.leg = leg;
    33     }
    34 
    35     public void setColor(String color) {    //设置颜色
    36         this.color = color;
    37     }
    38 
    39     public String getColor() {                //获取颜色
    40         return color;
    41     }
    42 
    43     public void setLeg(int leg) {            //设置腿的个数
    44         this.leg = leg;
    45     }
    46 
    47     public int getLeg() {                    //获取腿的个数
    48         return leg;
    49     }
    50 
    51     public void eat() {                        //吃饭
    52         System.out.println("吃饭");
    53     }
    54 }
    55 
    56 class Cat extends Animal {
    57     public Cat() {}                            //空参构造
    58 
    59     public Cat(String color,int leg) {        //有参构造
    60         super(color,leg);
    61     }
    62 
    63     public void eat() {                        //吃鱼
    64         System.out.println("猫吃鱼");
    65     }
    66 
    67     public void catchMouse() {                //抓老鼠
    68         System.out.println("抓老鼠");
    69     }
    70 }
    71 
    72 class Dog extends Animal {
    73     public Dog() {}                            //空参构造
    74 
    75     public Dog(String color,int leg) {        //有参构造
    76         super(color,leg);
    77     }
    78 
    79     public void eat() {                        //吃肉
    80         System.out.println("狗吃肉");
    81     }
    82 
    83     public void lookHome() {                //看家
    84         System.out.println("看家");
    85     }
    86 }
    View Code

    子类拥有父类的方法,子类更加灵活。抽取共性,动物都有颜色,还有腿的个数。猫和狗继承动物类,这样可以直接使用Animal的Color和leg属性。虽说不能直接访问父类的私有属性,但是通过set/get方法依然可以进行赋值和取值。

  2. 继承的好处
    1)提高了代码的复用性(不用多些多余的代码,做重复性的工作)
    2)提高代码维护性
    3)类和类之间产生了关系,这是多态的前提
  3. 继承的弊端
    类和类之间的耦合性增加了

    开发的原则
    高内聚,低耦合
    耦合 类与类的关系
    内聚 就是自己完成某件事情的能力


      
       

  4. java继承特点
    java不支持多继承,因为会有安全性问题。
    但是支持多层继承,A extends B,C extends A ……(继承体系)

  5. 继承的注意事项=
    1)子类只能继承父类所有非私有的成员(成员方法和成员变量)
    2)子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
    3)
    不要为了部分功能而去继承。而是体现 is-a 的关系时使用继承。
    如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。

  6. 重写
    当子类出现了和父类同名的方法时,则子类的方法称为重写父类的方法。
    当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容。
     1 public class Iphone17 {
     2     //打电话
     3     public void call(){
     4         System.out.println("打电话");
     5     }
     6     
     7 }
     8 
     9 class Iphone18 extends Iphone17 {
    10     
    11     //重写父类的方法,实现更加强大的功能,如果想要调用父类的call(),可以super.call()
    12     @Override
    13     public void call(){
    14         //super.call();
    15         System.out.println("通过意念打电话");
    16     }
    17 }
    View Code
  7. 重载和重写的区别(面试问过)
    这个问题感觉很奇葩,很二的一个问题,但没办法面试问过,而且对于刚出来的学生,例如我。问到的概率还挺大的,其实他两的关系和区别是,雷锋和雷峰塔的关系,java和JavaScript的关系,印度和印度尼西亚的关系。
    罢了,简单说说他两的区别吧。

    (图1)

    (图2)

三、代码块(局部代码块,构造代码块,静态代码块,同步代码块)

1):代码块概述
    * 在Java中,使用 { } 括起来的代码被称为代码块。
2):代码块分类
    * 根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程讲解)。
3):常见代码块的应用
 * a:局部代码块 
        * 在方法中出现;限定变量生命周期,及早释放,提高内存利用率
    * b:构造代码块 (初始化块)
        * 在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
    * c:静态代码块 
        * 在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。
        * 一般用于加载驱动

4) 例子:(面试可能会遇到,实际开发没有任何意义)

① 代码

 1 public class Student {
 2 
 3     static {
 4         System.out.println("Student 静态代码块");
 5     }
 6 
 7     {
 8         System.out.println("Student 构造代码块");
 9     }
10 
11     public Student() {
12         System.out.println("Student 构造方法");
13     }
14 }
15 
16 class Demo_Student {
17     static {
18         System.out.println("Demo_Student静态代码块");
19     }
20 
21     public static void main(String[] args) {
22         System.out.println("我是main方法");
23 
24         Student s1 = new Student();
25         Student s2 = new Student();
26     }
27 }
View Code

执行结果:

首先,编译后运行,字节码文件进入方法区(即Demo_Student.class),首先执行Demo_Student静态代码块,因为静态代码块随着类的加载而加载。

接着,主方法进栈。执行“我是main方法”。

然后,当加载Student.class时候,执行Student 静态代码块。

接着,再执行构造代码块,最后执行构造方法。

 

②代码

 1 class Fu {
 2     static {
 3         System.out.println("静态代码块Fu");
 4     }
 5 
 6     {
 7         System.out.println("构造代码块Fu");
 8     }
 9 
10     public Fu() {
11         System.out.println("构造方法Fu");
12     }
13 }
14 
15 class Zi extends Fu {
16     static {
17         System.out.println("静态代码块Zi");
18     }
19 
20     {
21         System.out.println("构造代码块Zi");
22     }
23 
24     public Zi() {
25         System.out.println("构造方法Zi");
26     }
27 }
28 
29 class Dmeo {
30     public static void main(String[] args){
31         Zi z = new Zi(); //请执行结果。
32     }
33 }
View Code

执行结果:

同理,首先,编译后运行,字节码文件进入方法区,因为有继承关系,在执行子类之前先得完成父类的初始化加载,静态代码块随着类的加载而加载,因此先执行父类的静态代码块,然后执行子类的静态代码块。

接着,执行父类的构造代码块,再执行父类的构造方法。

最后执行子类的构造代码块,执行子类的构造方法。

 

如有错误之处,欢迎指正。

邮箱:it_chang@126.com

posted @ 2018-03-06 22:24  changDV  阅读(297)  评论(0编辑  收藏  举报