04_JavaSE之OOP--面向对象(封装、继承)
对象(四)
一、封装
面向对象的三大特征:封装、继承、多态。
今天呢,我们来谈谈,其中两个 ---- 封装和继承。而多态呢,如果没有继承也就没有多态一说,这个我们后续继续聊。
- 什么是封装?
封装说白了,就是把对象的属性和行为给隐藏起来,仅仅对外提供公共的访问方式。如:将电脑的具体实现细节隐藏起来,提供键盘和一系列接口供用户使用,用户不必关心具体内部的实现细节。 - 封装的好处
- 隐藏了实现细节,提供公共的访问方式
- 提高了代码复用性
- 提高安全性
3. 封装的原则
-
- 将不需要对外提供的内容都隐藏起来。
- 把属性隐藏,提供公共方法对其访问。
4 .说明
把成员变量私有(private),提供相应的set/get方法。private仅仅是封装的一种体现形式,并不能说封装就是私有。
二、继承
继承,利用继承我们可以基于已经存在的类构造新的类,继承已经存在的类就可以复用(继承)这些类的方法和成员变量。同时,我们也可以添加一些自己的方法和属性,使得子类更加强大。
如:人可以是父类,而学生是人,是人的子类。而学生又具有他自己的特性。因此,这里存在着很明显的is-a的关系,is-a关系是继承的一个很明显的特征。
继承使用 extends 关键字。
- 继承的代码
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 }
子类拥有父类的方法,子类更加灵活。抽取共性,动物都有颜色,还有腿的个数。猫和狗继承动物类,这样可以直接使用Animal的Color和leg属性。虽说不能直接访问父类的私有属性,但是通过set/get方法依然可以进行赋值和取值。
- 继承的好处
1)提高了代码的复用性(不用多些多余的代码,做重复性的工作)
2)提高代码维护性
3)类和类之间产生了关系,这是多态的前提 - 继承的弊端
类和类之间的耦合性增加了
开发的原则 高内聚,低耦合 耦合 类与类的关系 内聚 就是自己完成某件事情的能力
- java继承特点
java不支持多继承,因为会有安全性问题。
但是支持多层继承,A extends B,C extends A ……(继承体系) - 继承的注意事项=
1)子类只能继承父类所有非私有的成员(成员方法和成员变量)
2)子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
3)不要为了部分功能而去继承。而是体现 is-a 的关系时使用继承。
如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。 - 重写
当子类出现了和父类同名的方法时,则子类的方法称为重写父类的方法。
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容。
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 }
- 重载和重写的区别(面试问过)
这个问题感觉很奇葩,很二的一个问题,但没办法面试问过,而且对于刚出来的学生,例如我。问到的概率还挺大的,其实他两的关系和区别是,雷锋和雷峰塔的关系,java和JavaScript的关系,印度和印度尼西亚的关系。
罢了,简单说说他两的区别吧。
(图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 }
执行结果:
首先,编译后运行,字节码文件进入方法区(即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 }
执行结果:
同理,首先,编译后运行,字节码文件进入方法区,因为有继承关系,在执行子类之前先得完成父类的初始化加载,静态代码块随着类的加载而加载,因此先执行父类的静态代码块,然后执行子类的静态代码块。
接着,执行父类的构造代码块,再执行父类的构造方法。
最后执行子类的构造代码块,执行子类的构造方法。
如有错误之处,欢迎指正。
邮箱:it_chang@126.com