Java基础-封装、继承、多态
封装
1、概念
将类的某些信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的方法来对隐藏的信息进行操作和访问。
因此,封装就有两个含义:把该隐藏的隐藏起来,把该暴露的暴露出来。
2、好处
a) 封装可以隐藏实现的细节
b) 让使用者只能通过实现写好的访问方法来访问这些字段,这样一来我们只需要在这些方法中增加逻辑控制,限制对数据的不合理访问、
c) 方便数据检查,有利于于保护对象信息的完整性
d) 便于修改,提高代码的可维护性
3、封装的实现步骤
a) 修改属性的可见性设为(private)
b) 创建getter/setter方法(用于属性的读写)(通过这两种方法对数据进行获取和设定,对象通过调用这两种发方法实现对数据的读写)
c) 在getter/setter方法中加入属性控制语句(对属性值的合法性进行判断)
1 public class Person{ 2 private String name; 3 private int age; 4 5 public int getAge(){ 6 return age; 7 } 8 9 public String getName(){ 10 return name; 11 } 12 13 public void setAge(int age){ 14 this.age = age; 15 } 16 17 public void setName(String name){ 18 this.name = name; 19 } 20 }
继承
1、概念
继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。
在Java之中,如果要实现继承的关系,可以使用如下的语法:
class 子类 extends 父类 {}
子类又被称为派生类; 父类又被称为超类(Super Class)。
1 package com.wz.extendsdemo; 2 3 class Person { 4 private String name; 5 private int age; 6 7 public void setName(String name) { 8 this.name = name; 9 } 10 11 public void setAge(int age) { 12 this.age = age; 13 } 14 15 public String getName() { 16 return this.name; 17 } 18 19 public int getAge() { 20 return this.age; 21 } 22 } 23 24 class Student extends Person { // Student类继承了Person类 25 } 26 27 public class TestDemo { 28 public static void main(String args[]) { 29 Student stu = new Student(); // 实例化的是子类 30 stu.setName("张三"); // Person类定义 31 stu.setAge(20); // Person类定义 32 System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge()); 33 } 34 }
通过代码可以发现,子类(Student)并没有定义任何的操作,而在主类中所使用的全部操作都是由Person类定义的,这证明:子类即使不扩充父类,也能维持父类的操作。
1 package com.wz.extendsdemo; 2 3 class Person { 4 private String name; 5 private int age; 6 7 public void setName(String name) { 8 this.name = name; 9 } 10 11 public void setAge(int age) { 12 this.age = age; 13 } 14 15 public String getName() { 16 return this.name; 17 } 18 19 public int getAge() { 20 return this.age; 21 } 22 } 23 24 class Student extends Person { // Student类继承了Person类 25 private String school; // 子类的属性 26 27 public void setSchool(String school) { 28 this.school = school; 29 } 30 31 public String getSchool() { 32 return this.school; 33 } 34 } 35 36 public class TestDemo { 37 public static void main(String args[]) { 38 Student stu = new Student(); // 实例化的是子类 39 stu.setName("张三"); // Person类定义 40 stu.setAge(20); // Person类定义 41 stu.setSchool("清华大学"); // Student类扩充方法 42 System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge() + ",学校:" + stu.getSchool()); 43 } 44 }
以上的代码,子类对于父类的功能进行了扩充(扩充了一个属性和两个方法)。但是思考一下:子类从外表看是扩充了父类的功能,但是对于以上的代码,子类还有一个特点:子类实际上是将父类定义的更加的具体化的一种手段。父类表示的范围大,而子类表示的范围小。
2、继承的特性
a)子类拥有父类非 private 的属性、方法。
b) 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
c) 子类可以用自己的方式实现父类的方法。
d) Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
e) 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
3、继承类型
- 单继承
- 多重继承
- 不同类继承同一个类
- 多继承(不支持),但是可以通过implements实现多继承
1 public interface A { 2 public void eat(); 3 public void sleep(); 4 } 5 6 public interface B { 7 public void show(); 8 } 9 10 public class C implements A,B { 11 }
4、super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
1 class Animal { 2 void eat() { 3 System.out.println("animal : eat"); 4 } 5 } 6 7 class Dog extends Animal { 8 void eat() { 9 System.out.println("dog : eat"); 10 } 11 void eatTest() { 12 this.eat(); // this 调用自己的方法 13 super.eat(); // super 调用父类方法 14 } 15 } 16 17 public class Test { 18 public static void main(String[] args) { 19 Animal a = new Animal(); 20 a.eat(); 21 Dog d = new Dog(); 22 d.eatTest(); 23 } 24 }
多态
1、概念
a) 多态是同一个行为具有多个不同表现形式或形态的能力。同一个接口,使用不同的实例而执行不同操作。
b) 多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
c) java 的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。
1. 如果a是类A的一个引用,那么,a可以指向类A的一个实例,或者说指向类A的一个子类。
2. 如果a是接口A的一个引用,那么,a必须指向实现了接口A的一个类的实例。
2、多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
3、多态的实现方式
方式一:重写:
方式二:接口
-
1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
-
2. java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。
方式三:抽象类和抽象方法
TODO
4、Java多态性实现机制
SUN目前的JVM实现机制,类实例的引用就是指向一个句柄(handle)的指针,这个句柄是一对指针:
一个指针指向一张表格,实际上这个表格也有两个指针(一个指针指向一个包含了对象的方法表,另外一个指向类对象,表明该对象所属的类型);
另一个指针指向一块从java堆中为分配出来内存空间。
5、总结
a) 通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用。
1 DerivedC c2=new DerivedC(); 2 BaseClass a1= c2; //BaseClass 基类,DerivedC是继承自BaseClass的子类 3 a1.play(); //play()在BaseClass,DerivedC中均有定义,即子类覆写了该方法
分析:
1 BaseClass a2=new BaseClass(); 2 DerivedC c1=a2;//出错
1 c1=(DerivedC)a2;
6、Java与C++多态性的比较
a) 虚函数
虚函数的存在是为了多态。
Java 中其实没有虚函数的概念,它的普通函数就相当于 C++ 的虚函数,动态绑定是Java的默认行为。如果 Java 中不希望某个函数具有虚函数特性,可以加上 final 关键字变成非虚函数。
1 public class Override { 2 public static void main(String[] args) { 3 People p=new Stu(); 4 p.eat(); 5 //调用特有的方法 6 Stu s=(Stu)p; 7 s.study(); 8 } 9 } 10 class People{ 11 public void eat(){ 12 System.out.println("吃饭"); 13 } 14 } 15 class Stu extends People{ 16 @java.lang.Override 17 public void eat(){ 18 System.out.println("学生吃"); 19 } 20 public void study(){ 21 System.out.println("好好学习"); 22 } 23 } 24 class Teachers extends People{ 25 @java.lang.Override 26 public void eat(){ 27 System.out.println("老师吃"); 28 } 29 public void teach(){ 30 System.out.println("认真授课"); 31 } 32 }